diff --git a/changelog.d/2310.fixed.md b/changelog.d/2310.fixed.md new file mode 100644 index 0000000000..4a3bda8989 --- /dev/null +++ b/changelog.d/2310.fixed.md @@ -0,0 +1 @@ +Pay Carer's Allowance and Carer Support Payment, and count a carer for the Universal Credit carer element, on caring hours only where the new input `cares_for_severely_disabled_person` says the person cared for gets a qualifying disability benefit; it defaults to true, so results change only where a calculation sets it false. diff --git a/docs/book/programs/gov/dwp/disability-legacy-benefits.md b/docs/book/programs/gov/dwp/disability-legacy-benefits.md index dc63b96fca..3496743b36 100644 --- a/docs/book/programs/gov/dwp/disability-legacy-benefits.md +++ b/docs/book/programs/gov/dwp/disability-legacy-benefits.md @@ -94,7 +94,8 @@ annual netting does not represent benefit spells at different weekly rates. The focused household tests retain live UC eligibility, disability/carer elements and final awards. Legacy receipt and disability-assessment inputs are assumptions, not a re-derivation of IB/SDA entitlement. The care-hours interface -does not identify the person cared for or check their qualifying benefit. No +does not identify the person cared for, and reads their qualifying benefit only +from the input `cares_for_severely_disabled_person`, which defaults to true. No private-data impact or Axiom parity has been measured. ## References diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/carer_premium.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/carer_premium.yaml index 63eb07b0a2..0873c9466c 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/carer_premium.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/carer_premium.yaml @@ -19,9 +19,10 @@ # partners are treated as caring for the same person unless both are entitled # with an award: a reported Carer's Allowance or Carer Support Payment award # (carers_allowance_reported carries both), or an entitlement that caring -# hours do not explain (fewer than 35 a week, or no claim), which was supplied -# directly. Most cases below with two premiums therefore give both partners a -# reported award. +# hours do not explain (fewer than 35 a week, care of someone who isn't +# severely disabled (cares_for_severely_disabled_person false), or no claim), +# which an input supplied directly. Most cases below with two premiums +# therefore give both partners a reported award. - name: Carer premium for a single claimant entitled to Carer's Allowance period: 2026 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/childcare_element/uc_childcare_work_condition_reg_32.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/childcare_element/uc_childcare_work_condition_reg_32.yaml index 6add9f640f..0aee9af7f4 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/childcare_element/uc_childcare_work_condition_reg_32.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/childcare_element/uc_childcare_work_condition_reg_32.yaml @@ -128,7 +128,8 @@ # allowance, so is a "severely disabled person" (SSCBA 1992 s. 70(2)). # Sara meets the Carer's Allowance conditions that reg. 30(1)(a) # imports, so "both Ben and Sara satisfy the paid work test" (ADM F7013). - # The model's is_carer_for_benefits reads only Sara's 40 care hours; it + # The model's is_carer_for_benefits reads Sara's 40 care hours and her + # cares_for_severely_disabled_person, left at its default of true; it # does not check her mother's attendance allowance. is_carer_for_benefits: [false, true, false, false] uc_childcare_work_condition: [true, false] diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/carers_allowance_cared_for_person.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/carers_allowance_cared_for_person.yaml new file mode 100644 index 0000000000..f79eee0ebf --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/carers_allowance_cared_for_person.yaml @@ -0,0 +1,441 @@ +# Carer benefits for caring for a severely disabled person. +# SSCBA 1992 s.70(1): "A person shall be entitled to a carer’s allowance for +# any day on which he is engaged in caring for a severely disabled person". +# s.70(2) defines a "severely disabled person" by the benefit payable for them: +# attendance allowance, the disability living allowance care component at the +# highest or middle rate, the personal independence payment daily living +# component, armed forces independence payment, the Scottish disability +# payments it lists, or a payment that SI 1976/409 reg 3 prescribes. +# SSI 2023/302 reg 5(1): "Carer Support Payment may only be paid to an +# individual in respect of a period during which that individual provides +# regular and substantial care to a person to whom a qualifying disability +# benefit is normally payable". DWP includes the Universal Credit carer +# element (UC Regs 2013 reg 29) for a claimant with regular and substantial +# caring responsibilities for a severely disabled person, which a claimant +# has if "they satisfy the conditions for entitlement to a carer’s +# allowance", or would but for the earnings limit or residence in Scotland +# (reg 30(1)(a)), whether or not they claim the allowance (reg 30(2)). +# +# cares_for_severely_disabled_person records whether the person cared for +# gets such a benefit. It defaults to true. False removes the route through +# caring hours; a reported award (carers_allowance_reported) still counts. +# +# The model reads these parameters at 30 April of the simulation year and +# counts 52 weeks or 12 months in a year. For 2026: +# - Carer's Allowance (gov.dwp.carers_allowance.rate, from 2026-04-01): +# 86.45 a week, 86.45 * 52 = 4,495.40; +# - Carer Support Payment (gov.social_security_scotland.carer_support_payment +# .rate, from 2026-04-05): 86.45 a week, 86.45 * 52 = 4,495.40; +# - Scottish Carer Supplement (gov.social_security_scotland +# .carer_support_payment.supplement, from 2026-04-05): 11.70 a week, +# 11.70 * 52 = 608.40; +# - Universal Credit carer element (gov.dwp.universal_credit.elements.carer +# .amount, from 2026-04-01): 209.34 a month, 209.34 * 12 = 2,512.08; +# - Universal Credit standard allowance for a single claimant aged 25 or over +# (gov.dwp.universal_credit.standard_allowance.amount.SINGLE_OLD, from +# 2026-04-01): 424.90 a month, 424.90 * 12 = 5,098.80; +# - Pension Credit carer addition (gov.dwp.pension_credit.guarantee_credit +# .carer.addition, from 2026-04-01) and the legacy carer premium +# (gov.dwp.carer_premium.single, from 2026-04-01): 48.15 a week each, +# 48.15 * 52 = 2,503.80. +# The minimum caring hours are 35 a week for both benefits +# (gov.dwp.carers_allowance.min_hours and +# gov.social_security_scotland.carer_support_payment.min_hours), so 40 hours +# meet them. + +- name: England carer of a partner with no qualifying disability benefit gets no Carer's Allowance + # The carer cares 40 hours a week for their partner, who has no s.70(2) + # benefit, so the partner is not a severely disabled person and DWP pays + # no allowance (s.70(1)): 0 for both. Without a carer benefit or the hours + # route, the carer is not a carer for benefits either. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 45 + care_hours: 40 + cares_for_severely_disabled_person: false + partner: + age: 50 + benunits: + benunit: + members: [carer, partner] + households: + household: + members: [carer, partner] + country: ENGLAND + output: + carers_allowance: [0, 0] + is_entitled_to_carer_benefit: [false, false] + is_carer_for_benefits: [false, false] + +- name: England carer with the input left out gets Carer's Allowance on caring hours + # The model takes the person cared for to be severely disabled unless an + # input says otherwise: 40 hours meet the 35-hour minimum, so the carer gets + # the weekly rate all year, 86.45 * 52 = 4,495.40. The partner does not + # care: 0. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 45 + care_hours: 40 + partner: + age: 50 + benunits: + benunit: + members: [carer, partner] + households: + household: + members: [carer, partner] + country: ENGLAND + output: + carers_allowance: [4_495.40, 0] + is_entitled_to_carer_benefit: [true, false] + is_carer_for_benefits: [true, false] + +- name: Scotland carer of a partner with no qualifying disability benefit gets no Carer Support Payment + # Social Security Scotland pays Carer Support Payment only for care of a + # person to whom a qualifying disability benefit is normally payable (reg + # 5(1)), and the partner has none: 0. The model pays the supplement only + # with a payable Carer Support Payment: 0. From 2025 Carer Support Payment + # replaces Carer's Allowance in Scotland, so Carer's Allowance is 0 too. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 45 + care_hours: 40 + cares_for_severely_disabled_person: false + partner: + age: 50 + benunits: + benunit: + members: [carer, partner] + households: + household: + members: [carer, partner] + country: SCOTLAND + output: + carer_support_payment: [0, 0] + scottish_carer_supplement: [0, 0] + carers_allowance: [0, 0] + +- name: Scotland carer with the input left out gets Carer Support Payment and the supplement + # 40 hours meet the 35-hour minimum: 86.45 * 52 = 4,495.40 of Carer + # Support Payment and 11.70 * 52 = 608.40 of supplement. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 45 + care_hours: 40 + partner: + age: 50 + benunits: + benunit: + members: [carer, partner] + households: + household: + members: [carer, partner] + country: SCOTLAND + output: + carer_support_payment: [4_495.40, 0] + scottish_carer_supplement: [608.40, 0] + carers_allowance: [0, 0] + +- name: Universal Credit claimant caring for someone with no qualifying disability benefit has no carer element + # The claimant would not claim Carer's Allowance, so no allowance enters + # the award as income, and the carer element needs no claim (reg 30(2)). + # The person cared for is not severely disabled, so the claimant fails the + # Carer's Allowance conditions in reg 30(1)(a): no carer element. The award + # is the standard allowance alone, 424.90 * 12 = 5,098.80. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + care_hours: 40 + would_claim_carers_allowance: false + cares_for_severely_disabled_person: false + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + country: ENGLAND + output: + carers_allowance: 0 + uc_carer_element: 0 + universal_credit: 5_098.80 + +- name: Universal Credit claimant with the input left out has the carer element + # The same claimant, with the person cared for taken to be severely + # disabled: the carer element, 209.34 * 12 = 2,512.08, and an award of + # 5,098.80 + 2,512.08 = 7,610.88. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + care_hours: 40 + would_claim_carers_allowance: false + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + country: ENGLAND + output: + carers_allowance: 0 + uc_carer_element: 2_512.08 + universal_credit: 7_610.88 + +- name: A reported Carer's Allowance award counts whatever the input says + # The Department for Work and Pensions pays a reported award, so the input + # false leaves it: the carer gets the weekly rate all year, 86.45 * 52 = + # 4,495.40, not the reported amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 45 + care_hours: 40 + cares_for_severely_disabled_person: false + carers_allowance_reported: 4_000 + partner: + age: 50 + benunits: + benunit: + members: [carer, partner] + households: + household: + members: [carer, partner] + country: ENGLAND + output: + carers_allowance: [4_495.40, 0] + is_entitled_to_carer_benefit: [true, false] + is_carer_for_benefits: [true, false] + +- name: A reported award in Scotland keeps Carer Support Payment whatever the input says + # carers_allowance_reported carries a reported Carer Support Payment award + # too, which Social Security Scotland pays: 86.45 * 52 = 4,495.40 and the + # supplement, 11.70 * 52 = 608.40. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 45 + care_hours: 40 + cares_for_severely_disabled_person: false + carers_allowance_reported: 4_000 + partner: + age: 50 + benunits: + benunit: + members: [carer, partner] + households: + household: + members: [carer, partner] + country: SCOTLAND + output: + carer_support_payment: [4_495.40, 0] + scottish_carer_supplement: [608.40, 0] + +- name: A reported award above the earnings limit keeps the carer element whatever the input says + # The claimant reports a Carer's Allowance award but earns 20,000 a year. + # Income tax takes 20% (gov.hmrc.income_tax.rates.uk) of 20,000 less the + # 12,570 personal allowance, 0.2 * 7,430 = 1,486, and employee National + # Insurance takes 8% (gov.hmrc.national_insurance.class_1.rates.employee + # .main) above the primary threshold of 241.73 a week (12,569.96 a year), + # 0.08 * 7,430.04 = 594.40. Net earnings come to (20,000 - 1,486 - 594.40) + # / 52 = 344.61 a week, above the 204 earnings limit + # (gov.dwp.carers_allowance.earnings_limit, from 2026-04-06), so the + # claimant is gainfully employed and DWP pays no allowance (s.70(1)(b)): + # 0. The reported award still counts as caring for a severely disabled + # person whatever the input says, and a claimant over the earnings limit + # still has the caring responsibilities the carer element needs (reg + # 30(1)(a)(i)), so the claimant is a carer for benefits and the element is + # 209.34 * 12 = 2,512.08. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + care_hours: 40 + employment_income: 20_000 + cares_for_severely_disabled_person: false + carers_allowance_reported: 4_000 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + country: ENGLAND + output: + is_gainfully_employed_for_carers_allowance: true + carers_allowance: 0 + is_entitled_to_carer_benefit: false + is_carer_for_benefits: true + uc_carer_element: 2_512.08 + +- name: Couple who both care give the allowance only to the partner who cares for a severely disabled person + # Both care 40 hours a week. The elder, the benefit unit head, cares for + # someone with no qualifying disability benefit, so only the younger meets + # the caring condition and has the allowance, 86.45 * 52 = 4,495.40. With + # the input left out the elder would have the couple's one award. With one + # partner entitled, the couple restriction has no choice to make, whatever + # partners_care_for_same_severely_disabled_person says. One carer premium: + # 48.15 * 52 = 2,503.80. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + elder: + age: 40 + care_hours: 40 + cares_for_severely_disabled_person: false + younger: + age: 38 + care_hours: 40 + benunits: + benunit: + members: [elder, younger] + would_claim_uc: false + households: + household: + members: [elder, younger] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + carers_allowance_pre_couple_limit: [0, 4_495.40] + carers_allowance: [0, 4_495.40] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2_503.80 + +- name: A supplied entitlement whose caring hours go to someone not severely disabled counts as a second award + # The elder has a reported award. The younger cares 40 hours a week for + # someone with no qualifying disability benefit, and an input supplies the + # younger's entitlement to a carer benefit. The hours can't explain that + # entitlement, so it counts as an award: two awards mean two people cared + # for, and the default is false. Each partner then has the carer premium, + # 2 * 48.15 * 52 = 5,007.60. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + elder: + age: 40 + care_hours: 40 + carers_allowance_reported: 4_000 + is_entitled_to_carer_benefit: true + younger: + age: 38 + care_hours: 40 + cares_for_severely_disabled_person: false + is_entitled_to_carer_benefit: true + benunits: + benunit: + members: [elder, younger] + would_claim_uc: false + households: + household: + members: [elder, younger] + country: ENGLAND + output: + partners_care_for_same_severely_disabled_person: false + carer_premium: 5_007.60 + +- name: The same couple with the input left out has one carer premium + # The model's same-person default reads an entitlement that caring hours + # explain as no award, since hours can't show whom a carer cares for. Now + # the younger's 40 hours, for someone the model takes to be severely + # disabled, explain the younger's entitlement. One award leaves the + # default true, and caring for the same person caps the premium at one + # amount: 48.15 * 52 = 2,503.80. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + elder: + age: 40 + care_hours: 40 + carers_allowance_reported: 4_000 + is_entitled_to_carer_benefit: true + younger: + age: 38 + care_hours: 40 + is_entitled_to_carer_benefit: true + benunits: + benunit: + members: [elder, younger] + would_claim_uc: false + households: + household: + members: [elder, younger] + country: ENGLAND + output: + partners_care_for_same_severely_disabled_person: true + carer_premium: 2_503.80 + +- name: Pension-age carer of someone with no qualifying disability benefit gets no Pension Credit carer addition + # A claimant aged 70 cares 40 hours a week for someone outside the + # household who has no qualifying disability benefit. With no entitlement + # to Carer's Allowance, the claimant has neither the Pension Credit carer + # addition nor the legacy carer premium: 0. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 70 + care_hours: 40 + cares_for_severely_disabled_person: false + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + country: ENGLAND + output: + carers_allowance: 0 + is_entitled_to_carer_benefit: false + carer_minimum_guarantee_addition: 0 + carer_premium: 0 + +- name: Pension-age carer with the input left out gets the Pension Credit carer addition + # The same claimant, entitled to Carer's Allowance on caring hours: 86.45 + # * 52 = 4,495.40 of allowance, and the carer addition and the carer + # premium, 48.15 * 52 = 2,503.80 each. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 70 + care_hours: 40 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + country: ENGLAND + output: + carers_allowance: 4_495.40 + is_entitled_to_carer_benefit: true + carer_minimum_guarantee_addition: 2_503.80 + carer_premium: 2_503.80 diff --git a/policyengine_uk/tests/test_cares_for_severely_disabled_person_properties.py b/policyengine_uk/tests/test_cares_for_severely_disabled_person_properties.py new file mode 100644 index 0000000000..2a5ba00304 --- /dev/null +++ b/policyengine_uk/tests/test_cares_for_severely_disabled_person_properties.py @@ -0,0 +1,508 @@ +"""Carer benefits pay on caring hours only for care of a severely disabled +person. + +The Department for Work and Pensions pays Carer's Allowance only for caring +for a "severely disabled person" (SSCBA 1992 s.70(1)), defined by the benefit +payable for them (s.70(2)). Social Security Scotland pays Carer Support +Payment only for care of a person "to whom a qualifying disability benefit is +normally payable" (SSI 2023/302 reg 5(1)). DWP includes the Universal Credit +carer element (UC Regs 2013 reg 29) for a claimant who meets the Carer's +Allowance conditions, or would but for the earnings limit or living in +Scotland (reg 30(1)(a)). The input cares_for_severely_disabled_person records +whether the person cared for gets such a benefit. It defaults to true, and +the model reads it only on the route through caring hours: a reported award +(carers_allowance_reported) still counts. + +Invariants, for benefit units of one or two adults and up to one qualifying +young person, each with drawn caring hours, reported award, take-up, +earnings and overlapping benefit, in each country, in 2024 (Scotland still on +Carer's Allowance), 2026, 2030 (the year the Carer's Allowance earnings +taper starts) and 2031, where no input supplies a carer benefit amount or +entitlement: + +1. leaving the input out gives exactly the values that setting it true + gives, for carers_allowance, carer_support_payment, is_carer_for_benefits, + is_entitled_to_carer_benefit, uc_carer_element, + partners_care_for_same_severely_disabled_person and + carer_minimum_guarantee_addition; +2. setting one person's input false never raises that person's + carers_allowance or carer_support_payment and never turns that person's + is_carer_for_benefits or is_entitled_to_carer_benefit on; it never raises + the benefit unit's uc_carer_element or carer_minimum_guarantee_addition, + and never turns partners_care_for_same_severely_disabled_person on; +3. before the taper, setting every person's input false never raises any + person's carers_allowance or carer_support_payment, or the benefit unit's + amounts, and never turns any of those flags on; +4. a person whose input is false and who has no reported award gets no + Carer's Allowance or Carer Support Payment, before or after the + overlapping-benefit adjustment, and is neither entitled to a carer benefit + nor a carer for benefits; +5. setting the input false for the people with a reported award leaves every + person's carers_allowance and carer_support_payment as they were, and + every person's is_carer_for_benefits too, except for a reported recipient + who would not claim, whose route through caring hours the input closes. + +And for couples where an input supplies each partner's entitlement to a +carer benefit, true or false: + +6. partners_care_for_same_severely_disabled_person is false exactly where + both partners have an entitlement and an award: a reported award, or an + entitlement that caring hours for a severely disabled person don't explain + (fewer than the minimum hours, the input false, or no claim). Leaving the + input out gives what setting it true gives, and setting inputs false never + turns the flag on. + +Only one of two partners who care for the same person can have the award +(SSCBA 1992 s.70(7ZA); SSI 2023/302 reg 5(3)). So when one partner's input +goes false, the model can give the award to the other partner, whose amount +and entitlement then rise, as the law has it; the second invariant therefore +compares only the person whose input changes, and the benefit unit. Under +the earnings taper the partners' awards can differ, and the model gives the +award to the partner with the larger one: setting both inputs false can then +give the other partner back a reported award, so the third invariant holds +only before the taper. Two fixed tests at the end run both cases. + +The first five invariants need households where no input supplies a carer +benefit entitlement or amount. Without one, the input can't change +partners_care_for_same_severely_disabled_person, so the sixth invariant +supplies the entitlements. A supplied entitlement that caring hours no longer +explain counts as a second award: it can turn that flag false and give the +couple a second carer premium or Universal Credit carer element, as the YAML +case "A supplied entitlement whose caring hours go to someone not severely +disabled counts as a second award" shows. Batching needs the same care: +supplying a value for one person makes it an input for every person in the +simulation, so the others take its default, not the formula. The sixth +invariant's households supply the entitlement for every person. + +Tests 1, 2, 3, 5 and 6 build each benefit unit more than once in one +simulation, in separate households: as drawn, and with the input changed. +Test 4 builds each unit once, with each member's input false or left out. +""" + +import numpy as np +from hypothesis import HealthCheck, example, given, settings +from hypothesis import strategies as st + +from policyengine_uk import Simulation + +INPUT = "cares_for_severely_disabled_person" +YEARS = [2024, 2026, 2030, 2031] +YEARS_BEFORE_TAPER = [2024, 2026] +COUNTRIES = ["ENGLAND", "SCOTLAND", "WALES", "NORTHERN_IRELAND"] +AWARD = 4_000 +# Annual amounts are float32; a change smaller than half a penny is not one. +TOLERANCE = 0.005 + +PERSON_AMOUNTS = ["carers_allowance", "carer_support_payment"] +PERSON_FLAGS = ["is_carer_for_benefits", "is_entitled_to_carer_benefit"] +BENUNIT_AMOUNTS = ["uc_carer_element", "carer_minimum_guarantee_addition"] +BENUNIT_FLAGS = ["partners_care_for_same_severely_disabled_person"] +PRE_OVERLAP = ["carers_allowance_pre_overlap", "carer_support_payment_pre_overlap"] + + +@st.composite +def carer_inputs(draw, earns=True): + # The draws lean towards a claim within the earnings limit, so that most + # carers who care the hours have an award the input can take away. + return { + # Either side of the 35-hour minimum both benefits use. + "care_hours": draw(st.sampled_from([0, 20, 34, 35, 40, 40, 60])), + "carers_allowance_reported": draw(st.sampled_from([0, 0, AWARD])), + "would_claim_carers_allowance": draw(st.sampled_from([True, True, False])), + # From 2026: below the earnings limit, above it by less than the rate + # (13,500 exceeds it by 50.60 a week in 2026 and 21.70 in 2031, so the + # taper pays some allowance), and far above it. The lower 2024 limit + # puts 8,000 and 13,500 above it, by 2.84 and 103.60 a week. + "employment_income": ( + draw(st.sampled_from([0, 0, 0, 8_000, 13_500, 30_000])) if earns else 0 + ), + # Above the carer rates, so an overlapping benefit can reduce the + # payment to nil and leave the entitlement. + "incapacity_benefit_reported": draw(st.sampled_from([0, 0, 6_000])), + } + + +@st.composite +def benefit_units(draw): + """One benefit unit in its own household: its members, the country, one + member whose input a test changes, and for each member the input false + or left out (None).""" + has_young_person = draw(st.booleans()) + young_person_age = draw(st.integers(16, 19)) + head_age = draw(st.integers(young_person_age + 16 if has_young_person else 18, 85)) + members = [{"age": head_age, "is_parent": has_young_person, **draw(carer_inputs())}] + if draw(st.booleans()): + # Within 15 years of the head in both directions when either could be + # under 20, and under 20 years older otherwise, so the model reads + # neither as the other's child. + oldest_partner = min(85, head_age + 19) if head_age >= 20 else head_age + 15 + youngest_partner = max(18, head_age - 15) + if has_young_person: + youngest_partner = max(youngest_partner, young_person_age + 16) + members.append( + { + "age": draw(st.integers(youngest_partner, oldest_partner)), + "is_parent": has_young_person, + **draw(carer_inputs()), + } + ) + adults = len(members) + if has_young_person: + # A qualifying young person: 16 to 19 in non-advanced education. + members.append( + { + "age": young_person_age, + "current_education": "UPPER_SECONDARY", + **draw(carer_inputs(earns=False)), + } + ) + return { + "members": members, + "adults": adults, + "country": draw(st.sampled_from(COUNTRIES)), + "chosen": draw(st.integers(0, len(members) - 1)), + "inputs": [draw(st.sampled_from([False, None])) for _ in members], + } + + +def with_input(unit, values): + """The unit with the input set to each member's value, or left out where + the value is None.""" + members = [ + member if value is None else {**member, INPUT: value} + for member, value in zip(unit["members"], values) + ] + return {**unit, "members": members} + + +@st.composite +def couples_with_supplied_entitlements(draw): + """A couple in its own household, where an input supplies each partner's + entitlement to a carer benefit, true or false, and each partner's input + is false or left out (None).""" + head_age = draw(st.integers(18, 85)) + oldest_partner = min(85, head_age + 19) if head_age >= 20 else head_age + 15 + ages = [head_age, draw(st.integers(max(18, head_age - 15), oldest_partner))] + members = [ + { + "age": age, + "is_parent": False, + "is_entitled_to_carer_benefit": draw(st.booleans()), + **draw(carer_inputs()), + } + for age in ages + ] + return { + "members": members, + "adults": 2, + "country": draw(st.sampled_from(COUNTRIES)), + "chosen": draw(st.integers(0, 1)), + "inputs": [draw(st.sampled_from([False, None])) for _ in members], + } + + +def simulate(units, year): + people, benunits, households = {}, {}, {} + for i, unit in enumerate(units): + names = [] + for j, inputs in enumerate(unit["members"]): + name = f"p{i}_{j}" + people[name] = {key: {year: value} for key, value in inputs.items()} + names.append(name) + benunits[f"b{i}"] = {"members": names} + households[f"h{i}"] = {"members": names, "country": {year: unit["country"]}} + sim = Simulation( + situation={"people": people, "benunits": benunits, "households": households} + ) + offsets = np.cumsum([0] + [len(unit["members"]) for unit in units]) + return sim, offsets + + +def calculate(units, year, variables): + sim, offsets = simulate(units, year) + values = {name: sim.calculate(name, year) for name in variables} + return values, offsets + + +SETTINGS = settings( + max_examples=12, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) + +UNITS = st.lists(benefit_units(), min_size=1, max_size=6) + +ADULT = { + "is_parent": False, + "carers_allowance_reported": 0, + "would_claim_carers_allowance": True, + "employment_income": 0, + "incapacity_benefit_reported": 0, +} +# Both partners care 40 hours a week. The elder, the benefit unit head, has the +# couple's one award; with the elder's input false the younger has it. +COUPLE = { + "members": [ + {**ADULT, "age": 40, "care_hours": 40}, + {**ADULT, "age": 38, "care_hours": 40}, + ], + "adults": 2, + "country": "ENGLAND", + "chosen": 0, + "inputs": [False, None], +} +# The same couple, aged 70 and 60, where an overlapping benefit takes the +# elder's award to nil: with the elder's input false, the younger is paid. +OVERLAPPED_COUPLE = { + **COUPLE, + "members": [ + {**ADULT, "age": 70, "care_hours": 40, "incapacity_benefit_reported": 6_000}, + {**ADULT, "age": 60, "care_hours": 40}, + ], +} +# Under the taper: the elder's reported award, tapered by earnings, loses to +# the younger's larger award on caring hours. With both inputs false the elder +# has it back; with only the elder's false, nothing changes. +TAPERED_COUPLE = { + **COUPLE, + "members": [ + { + **ADULT, + "age": 40, + "care_hours": 40, + "carers_allowance_reported": AWARD, + "employment_income": 13_500, + }, + {**ADULT, "age": 38, "care_hours": 40}, + ], + "inputs": [False, False], +} +SCOTTISH_COUPLE = {**COUPLE, "country": "SCOTLAND"} +# The elder has a reported award; the younger cares 40 hours a week for +# someone not severely disabled. Each has a supplied entitlement, so the +# younger's counts as a second award once the input says the hours don't +# explain it. +SUPPLIED_COUPLE = { + **COUPLE, + "members": [ + { + **ADULT, + "age": 40, + "care_hours": 40, + "carers_allowance_reported": AWARD, + "is_entitled_to_carer_benefit": True, + }, + {**ADULT, "age": 38, "care_hours": 40, "is_entitled_to_carer_benefit": True}, + ], + "chosen": 1, + "inputs": [None, False], +} + + +@SETTINGS +@given(UNITS, st.sampled_from(YEARS)) +@example(drawn=[COUPLE, SCOTTISH_COUPLE], year=2026) +def test_input_left_out_matches_input_true(drawn, year): + variables = PERSON_AMOUNTS + PERSON_FLAGS + ["is_claimant_or_partner"] + benunit_variables = BENUNIT_AMOUNTS + BENUNIT_FLAGS + true = [with_input(unit, [True] * len(unit["members"])) for unit in drawn] + values, offsets = calculate(drawn + true, year, variables + benunit_variables) + k = len(drawn) + n = offsets[k] + for i, unit in enumerate(drawn): + # The generator's construction, checked against the model: the + # adults are the claimant and partner, the young person is not. + flags = values["is_claimant_or_partner"][offsets[i] : offsets[i + 1]] + adults = unit["adults"] + assert flags[:adults].all() and not flags[adults:].any(), unit + for name in variables: + assert np.array_equal(values[name][:n], values[name][n:]), name + for name in benunit_variables: + assert np.array_equal(values[name][:k], values[name][k:]), name + + +@SETTINGS +@given(UNITS, st.sampled_from(YEARS)) +@example(drawn=[COUPLE, OVERLAPPED_COUPLE, SCOTTISH_COUPLE], year=2026) +@example(drawn=[TAPERED_COUPLE], year=2031) +def test_one_persons_input_false_never_raises_their_award(drawn, year): + changed = [ + with_input( + unit, + [ + False if j == unit["chosen"] else None + for j in range(len(unit["members"])) + ], + ) + for unit in drawn + ] + variables = PERSON_AMOUNTS + PERSON_FLAGS + BENUNIT_AMOUNTS + BENUNIT_FLAGS + values, offsets = calculate(drawn + changed, year, variables) + k = len(drawn) + for i, unit in enumerate(drawn): + before = offsets[i] + unit["chosen"] + after = offsets[k + i] + unit["chosen"] + for name in PERSON_AMOUNTS: + assert values[name][after] <= values[name][before] + TOLERANCE, (name, unit) + for name in PERSON_FLAGS: + assert values[name][before] or not values[name][after], (name, unit) + for name in BENUNIT_AMOUNTS: + assert values[name][k + i] <= values[name][i] + TOLERANCE, (name, unit) + for name in BENUNIT_FLAGS: + assert values[name][i] or not values[name][k + i], (name, unit) + + +@SETTINGS +@given(UNITS, st.sampled_from(YEARS_BEFORE_TAPER)) +@example(drawn=[COUPLE, OVERLAPPED_COUPLE, SCOTTISH_COUPLE], year=2026) +def test_everyones_input_false_never_raises_an_award_before_the_taper(drawn, year): + false = [with_input(unit, [False] * len(unit["members"])) for unit in drawn] + variables = PERSON_AMOUNTS + PERSON_FLAGS + BENUNIT_AMOUNTS + BENUNIT_FLAGS + values, offsets = calculate(drawn + false, year, variables) + k = len(drawn) + n = offsets[k] + for name in PERSON_AMOUNTS: + assert (values[name][n:] <= values[name][:n] + TOLERANCE).all(), name + for name in PERSON_FLAGS: + assert not (values[name][n:] & ~values[name][:n]).any(), name + for name in BENUNIT_AMOUNTS: + assert (values[name][k:] <= values[name][:k] + TOLERANCE).all(), name + for name in BENUNIT_FLAGS: + assert not (values[name][k:] & ~values[name][:k]).any(), name + + +@SETTINGS +@given(UNITS, st.sampled_from(YEARS)) +@example(drawn=[COUPLE, TAPERED_COUPLE, SCOTTISH_COUPLE], year=2031) +def test_input_false_without_a_reported_award_pays_no_carer_benefit(drawn, year): + units = [with_input(unit, unit["inputs"]) for unit in drawn] + variables = PERSON_AMOUNTS + PRE_OVERLAP + PERSON_FLAGS + values, offsets = calculate(units, year, variables) + for i, unit in enumerate(drawn): + for j, (member, value) in enumerate(zip(unit["members"], unit["inputs"])): + if value is False and member["carers_allowance_reported"] == 0: + for name in PERSON_AMOUNTS + PRE_OVERLAP: + assert values[name][offsets[i] + j] == 0, (name, unit) + for name in PERSON_FLAGS: + assert not values[name][offsets[i] + j], (name, unit) + + +@SETTINGS +@given(UNITS, st.sampled_from(YEARS)) +@example(drawn=[TAPERED_COUPLE], year=2031) +@example(drawn=[{**COUPLE, "members": TAPERED_COUPLE["members"]}], year=2026) +def test_reported_award_pays_the_same_whatever_the_input(drawn, year): + toggled = [ + with_input( + unit, + [ + False if member["carers_allowance_reported"] > 0 else None + for member in unit["members"] + ], + ) + for unit in drawn + ] + variables = PERSON_AMOUNTS + ["is_carer_for_benefits"] + values, offsets = calculate(drawn + toggled, year, variables) + n = offsets[len(drawn)] + for name in PERSON_AMOUNTS: + assert np.array_equal(values[name][:n], values[name][n:]), name + # A reported award the person would claim keeps them a carer for benefits + # whatever the input says, as the reported limb of is_carer_for_benefits + # has it; a reported recipient who would not claim relies on the hours. + claims = np.array( + [ + member["carers_allowance_reported"] == 0 + or member["would_claim_carers_allowance"] + for unit in drawn + for member in unit["members"] + ] + ) + carer = values["is_carer_for_benefits"] + assert np.array_equal(carer[:n][claims], carer[n:][claims]) + + +@SETTINGS +@given( + st.lists(couples_with_supplied_entitlements(), min_size=1, max_size=6), + st.sampled_from(YEARS), +) +@example(drawn=[SUPPLIED_COUPLE, {**SUPPLIED_COUPLE, "country": "SCOTLAND"}], year=2026) +def test_a_supplied_entitlement_counts_as_an_award_unless_hours_explain_it(drawn, year): + true = [with_input(unit, [True, True]) for unit in drawn] + changed = [with_input(unit, unit["inputs"]) for unit in drawn] + sim, offsets = simulate(drawn + true + changed, year) + same = sim.calculate("partners_care_for_same_severely_disabled_person", year) + claimant_or_partner = sim.calculate("is_claimant_or_partner", year) + gov = sim.tax_benefit_system.parameters(year).gov + k = len(drawn) + assert claimant_or_partner.all() + for i, unit in enumerate(drawn): + assert same[k + i] == same[i], unit + assert same[i] or not same[2 * k + i], unit + # The minimum hours of the benefit that applies: Carer Support + # Payment's in Scotland from 2025, Carer's Allowance's otherwise. + if unit["country"] == "SCOTLAND" and year >= 2025: + min_hours = gov.social_security_scotland.carer_support_payment.min_hours + else: + min_hours = gov.dwp.carers_allowance.min_hours + awards = 0 + for member, value in zip(unit["members"], unit["inputs"]): + explained = ( + member["care_hours"] >= min_hours + and value is not False + and member["would_claim_carers_allowance"] + ) + reported = member["carers_allowance_reported"] > 0 + awards += member["is_entitled_to_carer_benefit"] and ( + reported or not explained + ) + assert same[2 * k + i] == (awards < 2), unit + + +def _couple_values(units, year, variables): + values, _ = calculate(units, year, variables) + return {name: [round(float(x), 2) for x in values[name]] for name in variables} + + +def test_award_passes_to_the_partner_who_cares_for_a_severely_disabled_person(): + # The cases that the second invariant leaves out, run as they are. With + # the elder's input false the younger's allowance rises from nil to the + # full rate, 86.45 * 52 = 4,495.40: one partner's hours no longer count, + # so the other is the only one caring for a severely disabled person. + names = ["carers_allowance", "is_entitled_to_carer_benefit"] + default = _couple_values([COUPLE], 2026, names) + changed = _couple_values([with_input(COUPLE, COUPLE["inputs"])], 2026, names) + assert default == { + "carers_allowance": [4_495.4, 0], + "is_entitled_to_carer_benefit": [1, 0], + } + assert changed == { + "carers_allowance": [0, 4_495.4], + "is_entitled_to_carer_benefit": [0, 1], + } + # Where an overlapping benefit takes the elder's award to nil, the couple + # had nothing and now has the younger's full allowance. + overlapped = _couple_values([OVERLAPPED_COUPLE], 2026, names) + changed = _couple_values( + [with_input(OVERLAPPED_COUPLE, OVERLAPPED_COUPLE["inputs"])], 2026, names + ) + assert overlapped["carers_allowance"] == [0, 0] + assert changed["carers_allowance"] == [0, 4_495.4] + + +def test_under_the_taper_both_inputs_false_can_give_back_a_reported_award(): + # The case that the third invariant leaves out. In 2031 the elder's + # tapered award falls short of the younger's award on caring hours, so + # the model gives the younger the couple's award. With both inputs false + # the younger has none, and the elder keeps the reported award. + names = ["carers_allowance_pre_couple_limit", "carers_allowance"] + default = _couple_values([TAPERED_COUPLE], 2031, names) + both_false = _couple_values( + [with_input(TAPERED_COUPLE, TAPERED_COUPLE["inputs"])], 2031, names + ) + elder_award, younger_award = default["carers_allowance_pre_couple_limit"] + assert 0 < elder_award < younger_award + assert default["carers_allowance"] == [0, younger_award] + assert both_false["carers_allowance"] == [elder_award, 0] diff --git a/policyengine_uk/utils/carers_allowance_taper.py b/policyengine_uk/utils/carers_allowance_taper.py index e72d9a1de5..ef7d5ecd7c 100644 --- a/policyengine_uk/utils/carers_allowance_taper.py +++ b/policyengine_uk/utils/carers_allowance_taper.py @@ -45,7 +45,12 @@ def carers_allowance_weekly_by_part_of_year(person, period, parameters): csp_replaces_ca = period.start.year >= 2025 receives_ca = person("carers_allowance_reported", period) > 0 meets_age_condition = person("age", period) >= ca.min_age - meets_work_condition = person("care_hours", period) >= ca.min_hours + # SSCBA 1992 s. 70(1): the hours count only for caring for a severely + # disabled person (s. 70(2)), which the model takes to hold unless the + # input says otherwise. + meets_work_condition = (person("care_hours", period) >= ca.min_hours) & person( + "cares_for_severely_disabled_person", period + ) would_claim = person("would_claim_carers_allowance", period) eligible = ( ~(in_scotland & csp_replaces_ca) diff --git a/policyengine_uk/variables/gov/dwp/cares_for_severely_disabled_person.py b/policyengine_uk/variables/gov/dwp/cares_for_severely_disabled_person.py new file mode 100644 index 0000000000..d3699861a3 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/cares_for_severely_disabled_person.py @@ -0,0 +1,73 @@ +from policyengine_uk.model_api import * + + +class cares_for_severely_disabled_person(Variable): + value_type = bool + entity = Person + label = "Cares for a severely disabled person" + documentation = ( + "Whether the person this person cares for, in the household or " + "outside it, gets a benefit that makes them a severely disabled " + "person for Carer's Allowance (SSCBA 1992 s.70(2), with the payments " + "that SI 1976/409 reg 3 prescribes) or a qualifying disability " + "benefit for Carer Support Payment (SSI 2023/302 regs 2 and 5(1)). " + "The Department for Work and Pensions pays Carer's Allowance only for " + "caring for a severely disabled person (s.70(1)), and the model " + "applies the same condition in Northern Ireland. Social Security " + "Scotland pays Carer Support Payment only for care of a person to " + "whom a qualifying disability benefit is normally payable (reg 5(1)). " + "DWP includes the Universal Credit carer element (UC Regs 2013 reg " + "29) for a claimant with regular and substantial caring " + "responsibilities for a severely disabled person: one who meets the " + "Carer's Allowance conditions, or would but for the earnings limit or " + "residence in Scotland, or who has an entitlement to Carer Support " + "Payment (reg 30(1)). Caring hours in the survey " + "count care for anyone and don't say whom the carer cares for, and " + "the person cared for can live elsewhere, so the model doesn't derive " + "this from the household's disability benefits: it takes the person " + "cared for to qualify unless this input says otherwise, and the " + "default is true. The model reads it only where care_hours reach the " + "minimum: on the route through caring hours to Carer's Allowance, " + "Carer Support Payment and is_carer_for_benefits (and so the " + "Universal Credit carer element), and in " + "partners_care_for_same_severely_disabled_person, which counts a " + "supplied entitlement as a separate award unless caring hours for a " + "severely disabled person explain it. A reported award " + "(carers_allowance_reported, the model's reported-receipt input for " + "both benefits) still counts whatever this input says, since the " + "department or Social Security Scotland pays it. Set it to false for " + "a carer whose caring hours go to someone with none of those " + "benefits." + ) + definition_period = YEAR + default_value = True + reference = [ + dict( + title="Social Security Contributions and Benefits Act 1992 s. 70(1) and (2)", + href="https://www.legislation.gov.uk/ukpga/1992/4/section/70", + ), + dict( + title="Social Security Contributions and Benefits (Northern Ireland) Act 1992 s. 70", + href="https://www.legislation.gov.uk/ukpga/1992/7/section/70", + ), + dict( + title="The Social Security (Invalid Care Allowance) Regulations 1976 reg. 3", + href="https://www.legislation.gov.uk/uksi/1976/409/regulation/3", + ), + dict( + title="The Carer's Assistance (Carer Support Payment) (Scotland) Regulations 2023 reg. 2", + href="https://www.legislation.gov.uk/ssi/2023/302/regulation/2", + ), + dict( + title="The Carer's Assistance (Carer Support Payment) (Scotland) Regulations 2023 reg. 5(1)", + href="https://www.legislation.gov.uk/ssi/2023/302/regulation/5", + ), + dict( + title="The Universal Credit Regulations 2013 reg. 29", + href="https://www.legislation.gov.uk/uksi/2013/376/regulation/29", + ), + dict( + title="The Universal Credit Regulations 2013 reg. 30(1)(a)", + href="https://www.legislation.gov.uk/uksi/2013/376/regulation/30", + ), + ] diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/childcare_element/uc_unable_to_provide_childcare.py b/policyengine_uk/variables/gov/dwp/universal_credit/childcare_element/uc_unable_to_provide_childcare.py index d44a0cfef2..b73e503b6e 100644 --- a/policyengine_uk/variables/gov/dwp/universal_credit/childcare_element/uc_unable_to_provide_childcare.py +++ b/policyengine_uk/variables/gov/dwp/universal_credit/childcare_element/uc_unable_to_provide_childcare.py @@ -21,10 +21,12 @@ class uc_unable_to_provide_childcare(Variable): "Limb (ii), defined in regulation 30, reads " "is_carer_for_benefits: receipt of Carer's Allowance or Carer Support " "Payment, or at least the Carer's Allowance qualifying hours of care " - "a week. Its hours branch does not check that the person cared for " - "is severely disabled (a Carer's Allowance condition, SSCBA 1992 " - "s. 70(1)-(2), that regulation 30(1)(a) imports) or exclude a carer " - "paid for the caring (regulation 30(3)). Limb (iii) is the input " + "a week. Its hours branch checks that the person cared for is " + "severely disabled (a Carer's Allowance condition, SSCBA 1992 " + "s. 70(1)-(2), that regulation 30(1)(a) imports) only through the " + "input cares_for_severely_disabled_person, which defaults to true, " + "and does not exclude a carer paid for the caring (regulation " + "30(3)). Limb (iii) is the input " "uc_is_temporarily_absent_from_claimant_household." ) definition_period = YEAR diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/meets_uc_minimum_age_condition.py b/policyengine_uk/variables/gov/dwp/universal_credit/meets_uc_minimum_age_condition.py index 7675aabfec..cdc9b5c09d 100644 --- a/policyengine_uk/variables/gov/dwp/universal_credit/meets_uc_minimum_age_condition.py +++ b/policyengine_uk/variables/gov/dwp/universal_credit/meets_uc_minimum_age_condition.py @@ -22,8 +22,9 @@ class meets_uc_minimum_age_condition(Variable): is_carer_for_benefits means receipt of Carer's Allowance or Scottish Carer Support Payment, underlying entitlement to either benefit, or at least the Carer's Allowance qualifying hours of care (currently 35 weekly). - Its hours limb does not verify the recipient's - qualifying disability benefit, and it does not exclude paid care. + Its hours limb reads the cared-for person's qualifying disability benefit + only from the input cares_for_severely_disabled_person, which defaults to + true, and it does not exclude paid care. For regulation 8(1)(d), responsibility is proxied by being a claimant in a benefit unit with a nonclaimant child under the UC child definition. A diff --git a/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_couple_limit.py b/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_couple_limit.py index 775a09b2e4..80aa3b657c 100644 --- a/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_couple_limit.py +++ b/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_couple_limit.py @@ -16,6 +16,7 @@ class carer_support_payment_pre_couple_limit(Variable): "https://www.legislation.gov.uk/asp/2018/9/part/4", "https://www.legislation.gov.uk/ssi/2023/302/regulation/3", "https://www.legislation.gov.uk/ssi/2023/302/regulation/4", + "https://www.legislation.gov.uk/ssi/2023/302/regulation/5", "https://www.legislation.gov.uk/ssi/2023/302/regulation/16", "https://www.legislation.gov.uk/ssi/2023/302/regulation/14", "https://www.legislation.gov.uk/ssi/2023/302/schedule/2/paragraph/4", @@ -29,7 +30,12 @@ def formula(person, period, parameters): csp = parameters(period).gov.social_security_scotland.carer_support_payment meets_age_condition = person("age", period) >= csp.min_age weekly_care_hours = person("care_hours", period) - meets_hours = weekly_care_hours >= csp.min_hours + # Reg 5(1): only care of a person to whom a qualifying disability + # benefit is normally payable counts, which the model takes to hold + # unless the input says otherwise. + meets_hours = (weekly_care_hours >= csp.min_hours) & person( + "cares_for_severely_disabled_person", period + ) receives_ca = person("carers_allowance_reported", period) > 0 would_claim = person("would_claim_carers_allowance", period) earnings = person("carers_allowance_earnings", period) diff --git a/policyengine_uk/variables/household/demographic/is_carer_for_benefits.py b/policyengine_uk/variables/household/demographic/is_carer_for_benefits.py index f86e87520d..7a01840354 100644 --- a/policyengine_uk/variables/household/demographic/is_carer_for_benefits.py +++ b/policyengine_uk/variables/household/demographic/is_carer_for_benefits.py @@ -9,28 +9,39 @@ class is_carer_for_benefits(Variable): documentation = ( "Receives or is entitled to a carer benefit, or provides at least the " - "Carer's Allowance qualifying hours of care a week. The Universal " + "Carer's Allowance qualifying hours of care a week for a severely " + "disabled person. The Universal " "Credit carer element does not require a Carer's Allowance claim. " "Entitlement-based additions and premiums use " "is_entitled_to_carer_benefit; receipt-based rules use " "receives_carer_benefit. A " "carer whose allowance is reduced to nil by an overlapping benefit, " - "such as State Pension, stays entitled. The hours limb tests " - "hours alone, as carers_allowance_pre_overlap does: it does not check that the " - "person cared for receives a qualifying disability benefit (part of " - "the Carer's Allowance conditions referenced by regulation 30), so a " - "survey hours field counts caring for " - "anyone and a dataset's take-up input carries that simplification. " + "such as State Pension, stays entitled. The hours limb, as in " + "carers_allowance_pre_overlap, counts the hours only where the input " + "cares_for_severely_disabled_person holds: the person cared for gets " + "a benefit that makes them a severely disabled person for Carer's " + "Allowance (SSCBA 1992 s.70(1) and (2)), one of the Carer's Allowance " + "conditions in regulation 30(1)(a). The input defaults to true, " + "because caring hours in the survey don't say whom the carer cares " + "for, so at the default a survey hours field counts caring for anyone " + "and a dataset's take-up input carries that simplification. Set it to " + "false in a household calculation for a carer whose hours go to " + "someone with no such benefit. " "A reported Carer's Allowance award the person would claim also " "counts, so a carer whose earnings put them over the Carer's Allowance " "earnings limit keeps the Universal Credit carer element, which does " "not apply that limit (regulation 30(1)(a)(i))." ) - reference = "https://www.legislation.gov.uk/uksi/2013/376/regulation/30" + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/regulation/30", + "https://www.legislation.gov.uk/ukpga/1992/4/section/70", + ) def formula(person, period, parameters): min_hours = parameters(period).gov.dwp.carers_allowance.min_hours - meets_hours = person("care_hours", period) >= min_hours + meets_hours = (person("care_hours", period) >= min_hours) & person( + "cares_for_severely_disabled_person", period + ) # A reported Carer's Allowance award the person would claim is # evidence of the caring itself, where no hours are recorded. It still # counts when the earnings limit (which the Universal Credit carer diff --git a/policyengine_uk/variables/household/demographic/partners_care_for_same_severely_disabled_person.py b/policyengine_uk/variables/household/demographic/partners_care_for_same_severely_disabled_person.py index 89d137939c..10a6775f8f 100644 --- a/policyengine_uk/variables/household/demographic/partners_care_for_same_severely_disabled_person.py +++ b/policyengine_uk/variables/household/demographic/partners_care_for_same_severely_disabled_person.py @@ -19,19 +19,23 @@ class partners_care_for_same_severely_disabled_person(Variable): "Carer's Allowance or Carer Support Payment award " "(carers_allowance_reported, the model's reported-receipt input for " "both), or an entitlement that caring hours do not explain (fewer " - "than the qualifying hours, or no claim), which must have been " + "than the qualifying hours, care of someone who isn't severely " + "disabled (cares_for_severely_disabled_person false), or no claim), " + "which must have been " "supplied directly (for example as carers_allowance, " "carers_allowance_pre_overlap or is_entitled_to_carer_benefit; supply " "it for every member, since members left out take the default). The " "qualifying hours are Carer Support Payment's in Scotland from 2025 " "and Carer's Allowance's otherwise. Two awards mean two different " "people cared for, while caring hours cannot show who is cared for, " - "so the entitlement of someone who cares the qualifying hours and " - "would claim is not read as an award. " + "so the default doesn't read as an award the entitlement of someone " + "who cares the qualifying hours for a severely disabled person and " + "would claim. " "With more than two members supplied as claimant or partner, " "two awards make the default false for all of them. The model's " "Carer's Allowance and Carer Support Payment candidate amounts follow " - "caring hours or a reported award. The default uses those candidates " + "a reported award or caring hours for a severely disabled person. " + "The default uses those candidates " "and directly supplied awards before the same-person couple limit, " "so it does not depend on the final awards it restricts." ) @@ -48,11 +52,13 @@ def formula(benunit, period, parameters): entitled = unlimited_carer_benefit_entitlement(benunit.members, period) reported_award = benunit.members("carers_allowance_reported", period) > 0 # The model makes someone entitled to a carer benefit only on a - # reported award or the qualifying hours, each for someone who would - # claim, so an entitlement the hours do not explain comes from a - # reported award or was supplied directly (an amount in payment, a - # pre-overlap amount or the entitlement itself). The hours are those - # of the benefit that applies, as in carers_allowance_pre_overlap. + # reported award or the qualifying hours of care for a severely + # disabled person (cares_for_severely_disabled_person), each for + # someone who would claim, so an entitlement the hours do not explain + # comes from a reported award or an input that supplies it directly + # (an amount in payment, a pre-overlap amount or the entitlement + # itself). The hours are those of the benefit that applies, as in + # carers_allowance_pre_overlap. gov = parameters(period).gov in_scotland = ( benunit.members.household("country", period).decode_to_str() == "SCOTLAND" @@ -64,7 +70,12 @@ def formula(benunit, period, parameters): gov.dwp.carers_allowance.min_hours, ) hours = benunit.members("care_hours", period) + cares_for_severely_disabled = benunit.members( + "cares_for_severely_disabled_person", period + ) would_claim = benunit.members("would_claim_carers_allowance", period) - explained_by_hours = (hours >= min_hours) & would_claim + explained_by_hours = ( + (hours >= min_hours) & cares_for_severely_disabled & would_claim + ) award = reported_award | ~explained_by_hours return benunit.sum(claimant_or_partner & entitled & award) < 2