diff --git a/changelog.d/working-age-severe-disability-premium.changed.md b/changelog.d/working-age-severe-disability-premium.changed.md new file mode 100644 index 0000000000..527fdbb906 --- /dev/null +++ b/changelog.d/working-age-severe-disability-premium.changed.md @@ -0,0 +1 @@ +- Read Attendance Allowance from its dataset award category when supplied, retained an explicitly approximate amount fallback otherwise, and applied Northern Ireland's separate AFIP and PIP commencement dates to the legacy severe disability premium. diff --git a/changelog.d/working-age-severe-disability-premium.fixed.md b/changelog.d/working-age-severe-disability-premium.fixed.md new file mode 100644 index 0000000000..58d4168268 --- /dev/null +++ b/changelog.d/working-age-severe-disability-premium.fixed.md @@ -0,0 +1 @@ +The legacy benefit severe disability premium now qualifies on the benefits the Regulations list (Attendance Allowance, the DLA care component at the middle or highest rate, the PIP daily living component at either rate, and Armed Forces Independence Payment), pays a couple only when both partners qualify or the other partner is blind, pays the single rate when a carer benefit is paid for one partner, and is barred by a non-dependant aged 18 or over or by a carer benefit paid for the claimant. The tax credit severe disability flag now counts higher-rate Attendance Allowance and Armed Forces Independence Payment instead of all Armed Forces Compensation Scheme payments. diff --git a/policyengine_uk/parameters/gov/dwp/disability_premia/severe_non_dependant_age.yaml b/policyengine_uk/parameters/gov/dwp/disability_premia/severe_non_dependant_age.yaml new file mode 100644 index 0000000000..66e066512a --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/disability_premia/severe_non_dependant_age.yaml @@ -0,0 +1,15 @@ +description: > + A claimant loses the legacy severe disability premium if a non-dependant of + at least this age normally resides with them, unless that non-dependant + receives a severe disability premium qualifying benefit or is blind. +metadata: + label: Legacy benefit severe disability premium non-dependant age + period: year + unit: year + reference: + - title: The Housing Benefit Regulations 2006 Sch. 3 para. 14(2)(a)(ii), (2)(b)(iii) + href: https://www.legislation.gov.uk/uksi/2006/213/schedule/3/paragraph/14 + - title: The Income Support (General) Regulations 1987 Sch. 2 para. 13(2)(a)(ii), (2)(b)(iii) + href: https://www.legislation.gov.uk/uksi/1987/1967/schedule/2/paragraph/13 +values: + 2006-03-06: 18 diff --git a/policyengine_uk/parameters/gov/dwp/disability_premia/severe_qualifying_benefits.yaml b/policyengine_uk/parameters/gov/dwp/disability_premia/severe_qualifying_benefits.yaml new file mode 100644 index 0000000000..e95c4a9421 --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/disability_premia/severe_qualifying_benefits.yaml @@ -0,0 +1,43 @@ +description: > + Benefits whose receipt makes a claimant or partner severely disabled for the + legacy severe disability premium, and whose receipt by a non-dependant means + that non-dependant is ignored in the premium's residence condition. The + Regulations list attendance allowance (either rate), the care component of + disability living allowance at the highest or middle rate, the daily living + component of personal independence payment at either rate, armed forces + independence payment, and the Scottish equivalents. The Scottish benefits + are not separate model variables, and the lists differ slightly between + instruments. The 8 April 2013 date is Great Britain's: S.I. 2013/388 added + the PIP daily living component and S.I. 2013/591 added armed forces + independence payment. This list applies in Great Britain; the + severe_qualifying_benefits_northern_ireland parameter holds Northern + Ireland's separate commencement dates. The model selects the list using + household country. Like other parameters, it reads the list as at 30 April + of each year from 2015 and at 1 January before that, and does not prorate a + change made during a year. +metadata: + label: Legacy benefit severe disability premium qualifying benefits + period: year + unit: list + reference: + - title: The Housing Benefit Regulations 2006 Sch. 3 para. 14(2)(a)(i) + href: https://www.legislation.gov.uk/uksi/2006/213/schedule/3/paragraph/14 + - title: The Income Support (General) Regulations 1987 Sch. 2 para. 13(2)(a)(i) + href: https://www.legislation.gov.uk/uksi/1987/1967/schedule/2/paragraph/13 + - title: The Employment and Support Allowance Regulations 2008 Sch. 4 para. 6(2)(a)(i) + href: https://www.legislation.gov.uk/uksi/2008/794/schedule/4/paragraph/6 + - title: The Jobseeker's Allowance Regulations 1996 Sch. 1 para. 15(1)(a), (2)(a), (4)(a) + href: https://www.legislation.gov.uk/uksi/1996/207/schedule/1/paragraph/15 + - title: The Personal Independence Payment (Supplementary Provisions and Consequential Amendments) Regulations 2013 reg. 2 + href: https://www.legislation.gov.uk/uksi/2013/388/regulation/2 + - title: "The Armed Forces and Reserve Forces Compensation Scheme (Consequential Provisions: Subordinate Legislation) Order 2013 art. 2" + href: https://www.legislation.gov.uk/uksi/2013/591/article/2 +values: + 2006-03-06: + - attendance_allowance + - dla_sc_middle_plus + 2013-04-08: + - attendance_allowance + - dla_sc_middle_plus + - pip_dl + - armed_forces_independence_payment diff --git a/policyengine_uk/parameters/gov/dwp/disability_premia/severe_qualifying_benefits_northern_ireland.yaml b/policyengine_uk/parameters/gov/dwp/disability_premia/severe_qualifying_benefits_northern_ireland.yaml new file mode 100644 index 0000000000..e4c3b9d8cf --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/disability_premia/severe_qualifying_benefits_northern_ireland.yaml @@ -0,0 +1,57 @@ +description: > + Benefits whose receipt qualifies a claimant or partner for the legacy severe + disability premium, or exempts a non-dependant from its residence condition, + in Northern Ireland. Attendance allowance at either rate and the disability + living allowance care component at the middle or highest rate qualify. + Armed forces independence payment was added from 24 December 2013 by + S.I. 2013/3021, and the personal independence payment daily living component + at either rate from 20 June 2016 by S.R. 2016/228. The amendments cover the + Northern Ireland Income Support, Jobseeker's Allowance, Housing Benefit and + Employment and Support Allowance regulations. Like other parameters, the model + reads the list as at 30 April of each year from 2015 and at 1 January before + that, and does not prorate a change made during a year. The initial value + date follows the shared model baseline, not the commencement of S.R. + 2006/405 on 20 November 2006. Northern Ireland historical coverage before + that commencement has not been verified. +metadata: + label: Northern Ireland legacy severe disability premium qualifying benefits + period: year + unit: list + reference: + - title: The Housing Benefit Regulations (Northern Ireland) 2006 reg. 1(1) + href: https://www.legislation.gov.uk/nisr/2006/405/regulation/1/made + - title: The Housing Benefit Regulations (Northern Ireland) 2006 Sch. 4 para. 14 + href: https://www.legislation.gov.uk/nisr/2006/405/schedule/4/paragraph/14 + - title: S.I. 2013/3021 art. 1 (commencement) + href: https://www.legislation.gov.uk/uksi/2013/3021/article/1 + - title: S.I. 2013/3021 art. 14(5)(c) (Income Support) + href: https://www.legislation.gov.uk/uksi/2013/3021/article/14/5/c + - title: S.I. 2013/3021 art. 17(7)(c) (Jobseeker's Allowance) + href: https://www.legislation.gov.uk/uksi/2013/3021/article/17/7/c + - title: S.I. 2013/3021 art. 26(6)(c) (Housing Benefit) + href: https://www.legislation.gov.uk/uksi/2013/3021/article/26/6/c + - title: S.I. 2013/3021 art. 28(5)(b) (Employment and Support Allowance) + href: https://www.legislation.gov.uk/uksi/2013/3021/article/28/5/b + - title: S.R. 2016/228 reg. 1 (commencement) + href: https://www.legislation.gov.uk/nisr/2016/228/regulation/1 + - title: S.R. 2016/228 reg. 11(5)(c) (Income Support) + href: https://www.legislation.gov.uk/nisr/2016/228/regulation/11/5/c + - title: S.R. 2016/228 reg. 14(7)(c) (Jobseeker's Allowance) + href: https://www.legislation.gov.uk/nisr/2016/228/regulation/14/7/c + - title: S.R. 2016/228 reg. 30(7)(c) (Housing Benefit) + href: https://www.legislation.gov.uk/nisr/2016/228/regulation/30/7/c + - title: S.R. 2016/228 reg. 34(5)(b) (Employment and Support Allowance) + href: https://www.legislation.gov.uk/nisr/2016/228/regulation/34/5/b +values: + 2006-03-06: + - attendance_allowance + - dla_sc_middle_plus + 2013-12-24: + - attendance_allowance + - dla_sc_middle_plus + - armed_forces_independence_payment + 2016-06-20: + - attendance_allowance + - dla_sc_middle_plus + - pip_dl + - armed_forces_independence_payment diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support/legacy_premiums.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support/legacy_premiums.yaml index 141319853e..2714eacf05 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support/legacy_premiums.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support/legacy_premiums.yaml @@ -14,6 +14,7 @@ is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED output: # The claimant qualifies in their own right: no statutory age-18 floor. disability_premium: 2332.20 @@ -28,6 +29,7 @@ is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED output: disability_premium: 2332.20 enhanced_disability_premium: 1144 @@ -46,6 +48,7 @@ is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED benunits: family: members: [parent, young_person] @@ -66,9 +69,11 @@ young_person: age: 19 is_in_non_advanced_education: true + age_started_or_accepted_current_education_or_training: 17 is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED benunits: family: members: [parent, young_person] @@ -91,16 +96,17 @@ is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED benunits: family: members: [claimant, partner] output: disability_premium: 3328 enhanced_disability_premium: 1632.80 - # Deliberately preserve the existing severe-premium approximation: - # one qualifying partner currently triggers the full couple rate. - # IS Sch 2 para 13 / HB Sch 3 para 14 require both to qualify. - severe_disability_premium: 8949.20 + # IS Sch 2 para 13(2)(b) / HB Sch 3 para 14(2)(b) require both partners + # to qualify; the claimant receives no qualifying benefit and is not + # blind, so there is no severe disability premium. + severe_disability_premium: 0 - name: Disabled lone parent with a young person keeps single legacy premiums period: 2026 @@ -113,9 +119,11 @@ is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED young_person: age: 19 is_in_non_advanced_education: true + age_started_or_accepted_current_education_or_training: 17 benunits: family: members: [parent, young_person] @@ -136,6 +144,7 @@ is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED benunits: family: members: [parent, child] @@ -154,11 +163,13 @@ is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED partner: age: 32 is_disabled_for_benefits: true is_enhanced_disabled_for_benefits: true is_severely_disabled_for_benefits: true + pip_dl_category: ENHANCED benunits: family: members: [claimant, partner] diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/is_severely_disabled_for_benefits.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/is_severely_disabled_for_benefits.yaml new file mode 100644 index 0000000000..2934198a36 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/is_severely_disabled_for_benefits.yaml @@ -0,0 +1,111 @@ +# Severe disability conditions of the Child Tax Credit disability element +# (CTC Regs 2002 reg 8(1)(b), (3)-(5)) and the Working Tax Credit severe +# disability element (WTC Regs 2002 reg 17(2)-(4)). + +- name: DLA care component at the highest rate is severe + period: 2026 + input: + dla_sc_category: HIGHER + output: + is_severely_disabled_for_benefits: true + +- name: DLA care component at the middle rate is not severe + period: 2026 + input: + dla_sc_category: MIDDLE + output: + is_severely_disabled_for_benefits: false + +- name: PIP daily living component at the enhanced rate is severe + period: 2026 + input: + pip_dl_category: ENHANCED + output: + is_severely_disabled_for_benefits: true + +- name: PIP daily living component at the standard rate is not severe + period: 2026 + input: + pip_dl_category: STANDARD + output: + is_severely_disabled_for_benefits: false + +- name: Attendance Allowance at the higher rate is severe (WTC reg 17(2)) + period: 2026 + input: + aa_category: HIGHER + output: + is_severely_disabled_for_benefits: true + +- name: Attendance Allowance at the lower rate is not severe + period: 2026 + input: + aa_category: LOWER + output: + is_severely_disabled_for_benefits: false + +- name: Armed Forces Independence Payment is severe + period: 2026 + input: + armed_forces_independence_payment: 1_000 + output: + is_severely_disabled_for_benefits: true + +- name: Other Armed Forces Compensation Scheme payments are not severe + period: 2026 + input: + afcs_reported: 1_000 + output: + is_severely_disabled_for_benefits: false + +- name: WTC severe disability element for a claimant on higher-rate Attendance Allowance + period: 2024 + absolute_error_margin: 0.01 + input: + age: 70 + aa_category: HIGHER + is_WTC_eligible: true + output: + # WTC Regs 2002 reg 17(2) and Sch 2 para 6: 1,705 a year in 2024-25. + WTC_severely_disabled_element: 1_705 + +# Attendance Allowance is read from its award category. Only when no category +# is given is an amount compared with the annual higher rate less GBP 10 a +# week: an approximation, since WTC reg 17(2) has no tolerance. +- name: The Attendance Allowance category decides over an amount entered with it + period: 2026 + input: + aa_category: LOWER + attendance_allowance: 5_959.20 + output: + is_severely_disabled_for_benefits: false + +- name: Attendance Allowance amount with no category, at the 2024 threshold, is severe + period: 2024 + input: + # 108.55 x 52 - 10 x 52 = 5,124.60. + attendance_allowance: 5_124.60 + output: + is_severely_disabled_for_benefits: true + +- name: Attendance Allowance amount with no category, just below the 2024 threshold, is not severe + period: 2024 + input: + attendance_allowance: 5_124.59 + output: + is_severely_disabled_for_benefits: false + +- name: Attendance Allowance amount with no category, at the 2026 threshold, is severe + period: 2026 + input: + # 114.60 x 52 - 10 x 52 = 5,439.20. + attendance_allowance: 5_439.20 + output: + is_severely_disabled_for_benefits: true + +- name: Attendance Allowance amount with no category, just below the 2026 threshold, is not severe + period: 2026 + input: + attendance_allowance: 5_439.19 + output: + is_severely_disabled_for_benefits: false diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/severe_disability_premium.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/severe_disability_premium.yaml new file mode 100644 index 0000000000..fffdd43830 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/severe_disability_premium.yaml @@ -0,0 +1,538 @@ +# Legacy benefit severe disability premium: HB Regs 2006 Sch 3 paras 14 and +# 20(6); IS Regs 1987 Sch 2 paras 13 and 15(5); ESA Regs 2008 Sch 4 paras 6 +# and 11(2); JSA Regs 1996 Sch 1 paras 15 and 20(6). +# Expected values are the 2026-27 weekly rates times 52, hand-computed from +# the Schedules' rate tables: single rate 86.05 * 52 = 4474.60; double rate +# for a couple who both qualify with no carer paid for either +# 172.10 * 52 = 8949.20. + +# Qualifying benefits (para 14(2)(a)(i) and its counterparts). + +- name: Attendance Allowance at the lower rate qualifies + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + aa_category: LOWER + output: + receives_severe_disability_premium_qualifying_benefit: true + severe_disability_premium: 4474.60 + +- name: Attendance Allowance at the higher rate qualifies + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + aa_category: HIGHER + output: + severe_disability_premium: 4474.60 + +- name: DLA care component at the middle rate qualifies + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + dla_sc_category: MIDDLE + output: + receives_severe_disability_premium_qualifying_benefit: true + severe_disability_premium: 4474.60 + +- name: DLA care component at the highest rate qualifies + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + dla_sc_category: HIGHER + output: + severe_disability_premium: 4474.60 + +- name: DLA care component at the lowest rate does not qualify + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + dla_sc_category: LOWER + output: + receives_severe_disability_premium_qualifying_benefit: false + severe_disability_premium: 0 + +- name: PIP daily living component at the standard rate qualifies + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + pip_dl_category: STANDARD + output: + receives_severe_disability_premium_qualifying_benefit: true + severe_disability_premium: 4474.60 + +- name: PIP daily living component at the enhanced rate qualifies + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + pip_dl_category: ENHANCED + output: + severe_disability_premium: 4474.60 + +- name: PIP mobility component alone does not qualify + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + pip_m_category: ENHANCED + output: + severe_disability_premium: 0 + +- name: Armed Forces Independence Payment qualifies + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + armed_forces_independence_payment: 1_000 + output: + receives_severe_disability_premium_qualifying_benefit: true + severe_disability_premium: 4474.60 + +- name: Other Armed Forces Compensation Scheme payments do not qualify + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + afcs_reported: 1_000 + output: + receives_severe_disability_premium_qualifying_benefit: false + severe_disability_premium: 0 + +- name: The tax credit severe disability flag alone does not qualify + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + is_severely_disabled_for_benefits: true + output: + severe_disability_premium: 0 + +- name: No qualifying benefit, no premium + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + output: + severe_disability_premium: 0 + +# Couples (para 14(2)(b), (3) and (4); para 20(6)(b)). + +- name: Couple who both qualify with no carer get the double rate + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + pip_dl_category: STANDARD + partner: + age: 42 + dla_sc_category: MIDDLE + benunits: + family: + members: [claimant, partner] + output: + severe_disability_premium: 8949.20 + +- name: Couple where only one partner qualifies get nothing + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + pip_dl_category: ENHANCED + partner: + age: 42 + benunits: + family: + members: [claimant, partner] + output: + severe_disability_premium: 0 + +- name: A blind partner who does not qualify is treated as absent + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + pip_dl_category: ENHANCED + partner: + age: 42 + is_blind: true + benunits: + family: + members: [claimant, partner] + output: + # Para 14(3): the claimant is tested as single and gets the single rate. + severe_disability_premium: 4474.60 + +- name: A blind partner who is the qualifying member's carer bars the premium + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + pip_dl_category: ENHANCED + partner: + age: 42 + is_blind: true + receives_carer_benefit: true + benunits: + family: + members: [claimant, partner] + output: + severe_disability_premium: 0 + +- name: Couple who both qualify with a carer paid for one get the single rate + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + pip_dl_category: STANDARD + partner: + age: 42 + aa_category: LOWER + receives_carer_benefit: true + benunits: + family: + members: [claimant, partner] + output: + # Para 20(6)(b)(i): a carer's allowance is paid for only one of them. + severe_disability_premium: 4474.60 + +- name: Couple who both qualify with a carer paid for each get nothing + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + pip_dl_category: STANDARD + receives_carer_benefit: true + partner: + age: 42 + aa_category: LOWER + receives_carer_benefit: true + benunits: + family: + members: [claimant, partner] + output: + severe_disability_premium: 0 + +# The claimant and partner, not every adult in the benefit unit (para 14(2); +# HB Regs reg 2 "family"). An 18 or 19 year old qualifying young person is a +# member of the family, neither a partner nor a non-dependant. + +- name: A lone parent qualifies alongside an 18-year-old young person + period: 2026 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 40 + is_parent: true + pip_dl_category: STANDARD + young_person: + age: 18 + is_in_non_advanced_education: true + benunits: + family: + members: [parent, young_person] + output: + severe_disability_premium: 4474.60 + +- name: A qualifying young person does not make a couple both qualify + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + is_parent: true + pip_dl_category: STANDARD + partner: + age: 42 + is_parent: true + young_person: + age: 18 + is_in_non_advanced_education: true + dla_sc_category: MIDDLE + benunits: + family: + members: [claimant, partner, young_person] + output: + severe_disability_premium: 0 + +- name: A blind young person is not a partner treated as absent + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + is_parent: true + pip_dl_category: STANDARD + partner: + age: 42 + is_parent: true + young_person: + age: 18 + is_in_non_advanced_education: true + is_blind: true + benunits: + family: + members: [claimant, partner, young_person] + output: + severe_disability_premium: 0 + +- name: A qualifying young person does not qualify the couple + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + is_parent: true + is_blind: true + partner: + age: 42 + is_parent: true + young_person: + age: 19 + is_in_non_advanced_education: true + age_started_or_accepted_current_education_or_training: 17 + pip_dl_category: STANDARD + benunits: + family: + members: [claimant, partner, young_person] + output: + severe_disability_premium: 0 + +- name: An 18-year-old in the benefit unit who is not a young person is a non-dependant + period: 2026 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 45 + is_parent: true + pip_dl_category: STANDARD + adult_child: + age: 18 + is_in_non_advanced_education: false + is_in_approved_training: false + benunits: + family: + members: [parent, adult_child] + output: + # Not in education or training, so not a qualifying young person (HB + # Regs reg 19; SSCBA s.142): not in the family, so a non-dependant. + is_child_or_qualifying_young_person_for_child_benefit: [false, false] + has_non_dependant_for_severe_disability_premium: true + severe_disability_premium: 0 + +- name: A 17-year-old single claimant qualifies in their own right + period: 2026 + absolute_error_margin: 0.01 + input: + age: 17 + pip_dl_category: STANDARD + output: + severe_disability_premium: 4474.60 + +# Carers (para 14(2)(a)(iii)). + +- name: A single claimant's own carer benefit is not paid for caring for them + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + pip_dl_category: STANDARD + receives_carer_benefit: true + output: + severe_disability_premium: 4474.60 + +- name: A carer benefit paid to a young person in the family bars a single claimant + period: 2026 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 40 + pip_dl_category: STANDARD + child: + age: 17 + receives_carer_benefit: true + benunits: + family: + members: [parent, child] + output: + severe_disability_premium: 0 + +# Non-dependants (para 14(2)(a)(ii) and (2)(b)(iii); para 14(4)). + +- name: A non-dependant aged 18 or over bars the premium + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 50 + pip_dl_category: STANDARD + son: + age: 25 + benunits: + claimant_family: + members: [claimant] + son_family: + members: [son] + households: + household: + members: [claimant, son] + output: + has_non_dependant_for_severe_disability_premium: [true, false] + severe_disability_premium: [0, 0] + +- name: A non-dependant who receives a qualifying benefit is ignored + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 50 + pip_dl_category: STANDARD + son: + age: 25 + pip_dl_category: STANDARD + benunits: + claimant_family: + members: [claimant] + son_family: + members: [son] + households: + household: + members: [claimant, son] + output: + # Each is the other's non-dependant, and each is ignored because they + # receive a qualifying benefit, so both get the single rate. + has_non_dependant_for_severe_disability_premium: [false, false] + severe_disability_premium: [4474.60, 4474.60] + +- name: A blind non-dependant is ignored + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 50 + pip_dl_category: STANDARD + son: + age: 25 + is_blind: true + benunits: + claimant_family: + members: [claimant] + son_family: + members: [son] + households: + household: + members: [claimant, son] + output: + severe_disability_premium: [4474.60, 0] + +- name: A non-dependant aged 17 does not bar the premium + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 50 + pip_dl_category: STANDARD + lodger: + age: 17 + benunits: + claimant_family: + members: [claimant] + lodger_family: + members: [lodger] + households: + household: + members: [claimant, lodger] + output: + severe_disability_premium: [4474.60, 0] + +- name: A disabled adult living with their parents has non-dependants + period: 2026 + absolute_error_margin: 0.01 + input: + people: + disabled_adult: + age: 30 + dla_sc_category: HIGHER + mother: + age: 58 + father: + age: 60 + benunits: + adult_family: + members: [disabled_adult] + parents: + members: [mother, father] + households: + household: + members: [disabled_adult, mother, father] + output: + # HB/IS reg 3: parents living with the claimant are non-dependants + # unless an exclusion applies (for example joint occupiers). + severe_disability_premium: [0, 0] + +- name: People in other households are not non-dependants + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 50 + pip_dl_category: STANDARD + neighbour: + age: 25 + benunits: + claimant_family: + members: [claimant] + neighbour_family: + members: [neighbour] + households: + claimant_household: + members: [claimant] + neighbour_household: + members: [neighbour] + output: + severe_disability_premium: [4474.60, 0] + +# Flow-through to the applicable amounts. + +- name: The premium is part of the legacy benefit premiums + # Isolates the severe premium. PIP also qualifies for the disability premium + # (HB Regs 2006 Sch 3 para 13(1)(a)(i)), but its flag is_disabled_for_benefits + # is an input with no formula (the Enhanced FRS supplies it), so it is set + # false here rather than left to its default. + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + pip_dl_category: STANDARD + is_disabled_for_benefits: false + output: + carer_premium: 0 + benefits_premiums: 4474.60 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/severe_disability_premium_commencement.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/severe_disability_premium_commencement.yaml new file mode 100644 index 0000000000..a45e73835c --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/severe_disability_premium_commencement.yaml @@ -0,0 +1,112 @@ +# Dates verified in the amending instruments: GB S.I. 2013/388 reg 2 and +# S.I. 2013/591 art 2; NI S.I. 2013/3021 art 1 and S.R. 2016/228 reg 1. +# Calendar-year cases exercise the list at 1 January: AFIP added on +# 24 December 2013 enters the 2014 snapshot; PIP added on 20 June 2016 enters +# the 2017 snapshot. These cases do not assert within-year payment proration. +# Pre-2015 cases supply receipt amounts directly because the AA and PIP rate +# parameters begin in 2015; they test qualifying lists, not historical rates. + +- name: GB PIP and AFIP do not qualify in model year 2013 + period: 2013 + input: + country: ENGLAND + attendance_allowance: 0 + pip_dl: 1 + armed_forces_independence_payment: 1 + output: + receives_severe_disability_premium_qualifying_benefit: false + +- name: GB PIP qualifies in model year 2014 + period: 2014 + input: + country: ENGLAND + attendance_allowance: 0 + pip_dl: 1 + output: + receives_severe_disability_premium_qualifying_benefit: true + +- name: GB AFIP qualifies in model year 2014 + period: 2014 + input: + country: ENGLAND + attendance_allowance: 0 + pip_dl: 0 + armed_forces_independence_payment: 1 + output: + receives_severe_disability_premium_qualifying_benefit: true + +- name: NI PIP and AFIP do not qualify in model year 2013 + period: 2013 + input: + country: NORTHERN_IRELAND + attendance_allowance: 0 + pip_dl: 1 + armed_forces_independence_payment: 1 + output: + receives_severe_disability_premium_qualifying_benefit: false + +- name: NI PIP does not qualify in model year 2014, unlike GB + period: 2014 + input: + country: NORTHERN_IRELAND + attendance_allowance: 0 + pip_dl: 1 + output: + receives_severe_disability_premium_qualifying_benefit: false + +- name: NI AFIP qualifies in model year 2014 + period: 2014 + input: + country: NORTHERN_IRELAND + attendance_allowance: 0 + pip_dl: 0 + armed_forces_independence_payment: 1 + output: + receives_severe_disability_premium_qualifying_benefit: true + +- name: NI AFIP remains qualifying in model year 2017 + period: 2017 + input: + country: NORTHERN_IRELAND + armed_forces_independence_payment: 1 + output: + receives_severe_disability_premium_qualifying_benefit: true + +- name: NI PIP does not qualify in model year 2016 + period: 2016 + input: + country: NORTHERN_IRELAND + pip_dl: 1 + output: + receives_severe_disability_premium_qualifying_benefit: false + +- name: NI PIP qualifies in model year 2017 + period: 2017 + input: + country: NORTHERN_IRELAND + pip_dl: 1 + output: + receives_severe_disability_premium_qualifying_benefit: true + +- name: Contemporary NI PIP and GB AFIP qualify in separate households + period: 2026 + input: + people: + pip_recipient: + pip_dl: 1 + afip_recipient: + armed_forces_independence_payment: 1 + benunits: + pip_family: + members: [pip_recipient] + afip_family: + members: [afip_recipient] + households: + ni_household: + members: [pip_recipient] + country: NORTHERN_IRELAND + gb_household: + members: [afip_recipient] + country: ENGLAND + output: + receives_severe_disability_premium_qualifying_benefit: [true, true] diff --git a/policyengine_uk/tests/test_severe_disability_premium_properties.py b/policyengine_uk/tests/test_severe_disability_premium_properties.py new file mode 100644 index 0000000000..3326a19210 --- /dev/null +++ b/policyengine_uk/tests/test_severe_disability_premium_properties.py @@ -0,0 +1,358 @@ +"""Property-based tests for the legacy severe disability premium. + +HB Regs 2006 Sch 3 para 14 (with IS Regs 1987 Sch 2 para 13, ESA Regs 2008 +Sch 4 para 6 and JSA Regs 1996 Sch 1 para 15) pay the premium to a claimant +who receives a qualifying benefit; for a couple, both partners must qualify +unless the other partner is blind. No non-dependant aged 18 or over may +reside with them (ignoring non-dependants who receive a qualifying benefit or +are blind). A single claimant must have no one paid a carer benefit for caring +for them; a couple who both qualify get the double rate when no carer benefit +is paid for either, the single rate when one is paid for only one of them, and +nothing when carers are paid for both. + +Invariants, for any generated population of households: + +1. Range: the premium is 0, the single rate or the double rate, and the double + rate goes only to a couple who both qualify. +2. Oracle: the premium equals a second, separately written implementation + of the rule, with its own benefit classification and a carer condition + that brute-forces the assignment of each carer award to a benefit-unit + member other than its recipient. It is algorithmically independent of the + model but not of the model's assumptions: it shares the carer attribution + (the model does not observe who is cared for, so both take the assignment + that covers the most qualifying members) and the symmetric blind-partner + rule (either partner may be the claimant). Agreement shows the model + implements those assumptions, not that they match the Regulations. +3. Metamorphic: adding a household member aged 18 or over, in another benefit + unit, who receives no qualifying benefit and is not blind, removes the + premium. The oracle also treats a benefit-unit member aged 18 or 19 who is + not a qualifying young person as a non-dependant (HB Regs regs 3, 19). +4. Metamorphic: paying anyone in the benefit unit a carer benefit never + increases the premium. +5. Metamorphic: giving anyone in the household a qualifying benefit, or making + them blind, never reduces the premium. +6. Differential: for a family with no children and no one else in the + household, the premium equals the Pension Credit severe disability + addition, which has the same qualifying benefits, couple, blind-partner and + carer rules and rates (SPC Regs 2002 Sch I para 1; reg 6(5)). This keeps + two encodings of the same rule in step; it is not an independent oracle. +""" + +from itertools import product + +import numpy as np +from hypothesis import HealthCheck, event, example, given, settings +from hypothesis import strategies as st + +from policyengine_uk import Simulation, parameters + +YEAR = 2026 +WEEKS = 52 +SINGLE = 86.05 * WEEKS +DOUBLE = 172.10 * WEEKS +PROPERTY_SETTINGS = settings( + max_examples=12, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) + + +def _qualifying_list(year, name): + return getattr(parameters(str(year)).gov.dwp.disability_premia, name) + + +def test_northern_ireland_commencements_by_model_year(): + # The model reads the list as at 1 January before 2015 and 30 April from + # 2015, so AFIP (24 December 2013) first qualifies in 2014 and PIP daily + # living (20 June 2016) in 2017. The Great Britain list adds both from + # 8 April 2013, so from 2014. + ni = "severe_qualifying_benefits_northern_ireland" + for benefit, last_year_without, first_year_with in ( + ("armed_forces_independence_payment", 2013, 2014), + ("pip_dl", 2016, 2017), + ): + assert benefit not in _qualifying_list(last_year_without, ni) + assert benefit in _qualifying_list(first_year_with, ni) + for benefit in ("armed_forces_independence_payment", "pip_dl"): + gb = "severe_qualifying_benefits" + assert benefit not in _qualifying_list(2013, gb) + assert benefit in _qualifying_list(2014, gb) + + +# (inputs, qualifies) for each benefit a person may receive. +BENEFITS = { + "none": ({}, False), + "aa_lower": ({"aa_category": "LOWER"}, True), + "aa_higher": ({"aa_category": "HIGHER"}, True), + "dla_lowest": ({"dla_sc_category": "LOWER"}, False), + "dla_middle": ({"dla_sc_category": "MIDDLE"}, True), + "dla_highest": ({"dla_sc_category": "HIGHER"}, True), + "pip_standard": ({"pip_dl_category": "STANDARD"}, True), + "pip_enhanced": ({"pip_dl_category": "ENHANCED"}, True), + "pip_mobility_only": ({"pip_m_category": "ENHANCED"}, False), + "afip": ({"armed_forces_independence_payment": 1_000.0}, True), + "afcs_other": ({"afcs_reported": 1_000.0}, False), +} +benefit = st.sampled_from(sorted(BENEFITS)) +# Adults aged 20 to 60 and children under 16 are the claimant and partner, and +# their children, under any reading of the benefit unit (18 and 19 year olds +# can be qualifying young persons). +ADULT_AGE = st.integers(20, 60) + + +@st.composite +def person(draw, age): + return dict( + age=draw(age), + benefit=draw(benefit), + blind=draw(st.booleans()), + # Carer benefits are rarer than not, so couples who both qualify with + # no carer (the double rate) are generated as well. + carer=draw(st.sampled_from([False, False, False, True])), + ) + + +@st.composite +def young_person(draw): + # A 16-19 year old in the benefit unit, who is a qualifying young person + # only if in non-advanced education and (at 19) started before 19. + return dict( + draw(person(st.integers(16, 19))), + in_education=draw(st.booleans()), + entry_age=draw(st.sampled_from([17, 19])), + ) + + +@st.composite +def households(draw): + young = draw(st.lists(young_person(), max_size=1)) + # With a 16-19 year old present, adults aged 40+ make them the head's + # presumed child under #1896's claimant and partner inference. + adult_age = st.integers(40, 60) if young else ADULT_AGE + adults = draw(st.lists(person(adult_age), min_size=1, max_size=2)) + children = draw(st.lists(person(st.integers(0, 15)), max_size=1)) + others = draw(st.lists(person(st.integers(15, 70)), max_size=2)) + return dict(adults=adults, children=children, young=young, others=others) + + +def family_members(unit): + return unit["adults"] + unit["children"] + unit.get("young", []) + + +def with_family(unit, family): + a, c = len(unit["adults"]), len(unit["children"]) + return dict( + unit, adults=family[:a], children=family[a : a + c], young=family[a + c :] + ) + + +def qualifies(p): + return BENEFITS[p["benefit"]][1] + + +def is_qualifying_young_person(p): + """Child Benefit qualifying young person (SSCBA s.142), as HB reg 19 uses.""" + return ( + 16 <= p["age"] < 20 + and p.get("in_education", False) + and (p["age"] < 19 or p.get("entry_age", 99) < 19) + ) + + +def person_inputs(p): + inputs = {"age": {YEAR: p["age"]}, "is_blind": {YEAR: p["blind"]}} + inputs["receives_carer_benefit"] = {YEAR: p["carer"]} + if "in_education" in p: + inputs["is_in_non_advanced_education"] = {YEAR: p["in_education"]} + inputs["age_started_or_accepted_current_education_or_training"] = { + YEAR: p["entry_age"] + } + for name, value in BENEFITS[p["benefit"]][0].items(): + inputs[name] = {YEAR: value} + return inputs + + +def simulate(units, variables=("severe_disability_premium",)): + """One simulation for many households; returns each primary family's values.""" + people, benunits, hh = {}, {}, {} + for i, unit in enumerate(units): + family = [] + for j, p in enumerate(family_members(unit)): + people[f"h{i}_f{j}"] = person_inputs(p) + family.append(f"h{i}_f{j}") + benunits[f"h{i}_family"] = {"members": family} + members = list(family) + for j, p in enumerate(unit["others"]): + people[f"h{i}_o{j}"] = person_inputs(p) + benunits[f"h{i}_o{j}"] = {"members": [f"h{i}_o{j}"]} + members.append(f"h{i}_o{j}") + hh[f"h{i}"] = {"members": members} + sim = Simulation( + situation={"people": people, "benunits": benunits, "households": hh} + ) + ids = list(sim.populations["benunit"].ids) + rows = [ids.index(f"h{i}_family") for i in range(len(units))] + return {v: np.asarray(sim.calculate(v, YEAR))[rows] for v in variables} + + +def simulate_before_after(units, changed): + """The premium for the original and changed households, in one simulation.""" + premium = simulate(units + changed)["severe_disability_premium"] + return premium[: len(units)], premium[len(units) :] + + +def oracle(unit): + """The premium from a separately written implementation of the rule. + + Independent of the model's code, but it shares the model's carer + attribution and symmetric blind-partner assumptions. + """ + adults, family = unit["adults"], family_members(unit) + # Non-dependants: other benefit units in the household, and anyone in the + # benefit unit who is not the claimant, partner, a child or a qualifying + # young person (HB Regs regs 3(2)(a), 19). + candidates = unit["others"] + [ + y for y in unit.get("young", []) if not is_qualifying_young_person(y) + ] + blocking = [ + o for o in candidates if o["age"] >= 18 and not qualifies(o) and not o["blind"] + ] + if blocking: + return 0.0 + qualifying = [i for i, a in enumerate(adults) if qualifies(a)] + if len(adults) == 2 and len(qualifying) == 1: + other = adults[1 - qualifying[0]] + if not other["blind"]: + return 0.0 + elif len(adults) == 2 and len(qualifying) == 0: + return 0.0 + elif len(adults) == 1 and not qualifying: + return 0.0 + # Assign each carer award to one family member other than its recipient, + # and count the most qualifying members that can be covered. + carers = [i for i, p in enumerate(family) if p["carer"]] + cared_for = 0 + for assignment in product(range(len(family)), repeat=len(carers)): + if any(c == target for c, target in zip(carers, assignment)): + continue + cared_for = max(cared_for, len(set(assignment) & set(qualifying))) + if len(adults) == 2 and len(qualifying) == 2: + return (2 - cared_for) * SINGLE + return SINGLE if cared_for == 0 else 0.0 + + +def _adult(benefit, blind=False, carer=False): + return dict(age=40, benefit=benefit, blind=blind, carer=carer) + + +@PROPERTY_SETTINGS +@given(st.lists(households(), min_size=1, max_size=10)) +@example( + [ + # Both qualify, no carer: the double rate. + dict( + adults=[_adult("pip_standard"), _adult("aa_lower")], + children=[], + others=[], + ), + # One qualifies, the other is blind: the single rate. + dict( + adults=[_adult("dla_middle"), _adult("none", blind=True)], + children=[], + others=[], + ), + # An 18-year-old in the benefit unit, not in education: a + # non-dependant, so no premium. + dict( + adults=[_adult("pip_standard")], + children=[], + young=[dict(_adult("none"), age=18, in_education=False, entry_age=17)], + others=[], + ), + # A 19-year-old qualifying young person: family, so the single rate. + dict( + adults=[_adult("pip_standard")], + children=[], + young=[dict(_adult("none"), age=19, in_education=True, entry_age=17)], + others=[], + ), + ] +) +def test_premium_matches_independent_oracle_and_range(units): + premium = simulate(units)["severe_disability_premium"] + for unit, value in zip(units, premium): + event( + f"{len(unit['adults'])} adult(s), premium " + f"{'double' if value > SINGLE + 1 else 'single' if value > 1 else 'none'}" + ) + assert np.isclose(value, oracle(unit), atol=0.01), unit + assert any(np.isclose(value, x, atol=0.01) for x in (0, SINGLE, DOUBLE)) + if np.isclose(value, DOUBLE, atol=0.01): + assert len(unit["adults"]) == 2 + assert all(qualifies(a) for a in unit["adults"]) + + +@PROPERTY_SETTINGS +@given(st.lists(households(), min_size=1, max_size=10), ADULT_AGE) +def test_counted_non_dependant_removes_premium(units, age): + non_dependant = dict(age=age, benefit="none", blind=False, carer=False) + added = [dict(u, others=u["others"] + [non_dependant]) for u in units] + premium = simulate(added)["severe_disability_premium"] + assert np.allclose(premium, 0) + + +@PROPERTY_SETTINGS +@given(st.lists(households(), min_size=1, max_size=10), st.integers(0, 2)) +def test_carer_benefit_never_increases_premium(units, index): + def pay_carer(unit): + family = family_members(unit) + i = index % len(family) + family = [dict(p, carer=p["carer"] or k == i) for k, p in enumerate(family)] + return with_family(unit, family) + + before, after = simulate_before_after(units, [pay_carer(u) for u in units]) + assert np.all(after <= before + 0.01) + + +@PROPERTY_SETTINGS +@given( + st.lists(households(), min_size=1, max_size=10), + st.integers(0, 4), + st.sampled_from(["pip_standard", "blind"]), +) +def test_qualifying_benefit_or_blindness_never_reduces_premium(units, index, change): + def apply(unit): + family = family_members(unit) + everyone = family + unit["others"] + i = index % len(everyone) + changed = [ + dict(p, **({"blind": True} if change == "blind" else {"benefit": change})) + if k == i + else p + for k, p in enumerate(everyone) + ] + return dict( + with_family(unit, changed[: len(family)]), others=changed[len(family) :] + ) + + before, after = simulate_before_after(units, [apply(u) for u in units]) + assert np.all(after >= before - 0.01) + + +@PROPERTY_SETTINGS +@given(st.lists(st.lists(person(ADULT_AGE), min_size=1, max_size=2), min_size=1)) +def test_matches_pension_credit_severe_disability_addition(families): + # PolicyEngine/policyengine-uk#1896's Pension Credit addition applies the + # same couple, blind-partner and carer rules, so every family with no one + # else in the household is compared, carers and mixed couples included. + units = [dict(adults=adults, children=[], others=[]) for adults in families] + values = simulate( + units, + ("severe_disability_premium", "severe_disability_minimum_guarantee_addition"), + ) + assert np.allclose( + values["severe_disability_premium"], + values["severe_disability_minimum_guarantee_addition"], + atol=0.01, + ) diff --git a/policyengine_uk/variables/gov/dwp/num_severely_disabled_claimants_or_partners_for_legacy_benefits.py b/policyengine_uk/variables/gov/dwp/num_severely_disabled_claimants_or_partners_for_legacy_benefits.py deleted file mode 100644 index 2d6f4987ad..0000000000 --- a/policyengine_uk/variables/gov/dwp/num_severely_disabled_claimants_or_partners_for_legacy_benefits.py +++ /dev/null @@ -1,22 +0,0 @@ -from policyengine_uk.model_api import * - - -class num_severely_disabled_claimants_or_partners_for_legacy_benefits(Variable): - value_type = int - entity = BenUnit - label = "Severely disabled claimants or partners for legacy benefits" - documentation = ( - "Claimants and partners satisfying the model's existing " - "is_severely_disabled_for_benefits indicator. This count does not " - "implement the separate statutory non-dependant or carer conditions." - ) - definition_period = YEAR - reference = ( - "https://www.legislation.gov.uk/uksi/1987/1967/schedule/2/paragraph/13", - "https://www.legislation.gov.uk/uksi/2006/213/schedule/3/paragraph/14", - ) - - def formula(benunit, period, parameters): - claimant_or_partner = benunit.members("is_claimant_or_partner", period) - disabled = benunit.members("is_severely_disabled_for_benefits", period) - return benunit.sum(claimant_or_partner & disabled) diff --git a/policyengine_uk/variables/household/demographic/has_non_dependant_for_severe_disability_premium.py b/policyengine_uk/variables/household/demographic/has_non_dependant_for_severe_disability_premium.py new file mode 100644 index 0000000000..5c6d489a77 --- /dev/null +++ b/policyengine_uk/variables/household/demographic/has_non_dependant_for_severe_disability_premium.py @@ -0,0 +1,65 @@ +from policyengine_uk.model_api import * + + +class has_non_dependant_for_severe_disability_premium(Variable): + value_type = bool + entity = BenUnit + label = "Has a non-dependant who blocks the severe disability premium" + documentation = ( + "A non-dependant aged 18 or over normally resides with the claimant, " + "which bars the legacy severe disability premium. Non-dependants who " + "receive a severe disability premium qualifying benefit, or who are " + "blind, are ignored. Every household member aged 18 or over is " + "treated as a non-dependant unless they are in the claimant's family: " + "the claimant, their partner, and children and qualifying young " + "persons (the Child Benefit definition that the Regulations' " + "'young person' uses). A 19-year-old is a young person only if their " + "course started, or they enrolled or were accepted, before 19 " + "(age_started_or_accepted_current_education_or_training; unknown " + "counts as not met). The Regulations' exclusion of young people who " + "claim benefits themselves (HB Regs reg 19(2), IS Regs reg 14(2)) is " + "approximated by receives_benefits_in_own_right. Their exclusion of " + "a young person to whom section 6 of the Children (Leaving Care) Act " + "2000 applies (HB Regs reg 19(2)(c), IS Regs reg 14(2)(c)) is not " + "modelled. The people in section 6(2)(a) to (bb) are children aged 16 " + "or 17, below the non-dependant age, so for them the omission cannot " + "change the premium; the people prescribed under section 6(4) " + "(looked after in Scotland) are also under 18 (S.I. 2004/747 reg " + "2(2)(a)). The care-leaver bursary and current local-authority care " + "inputs do not identify the historical care status needed for " + "section 6. The model cannot " + "identify the other people the " + "Regulations exclude from the definition (for example joint " + "occupiers, commercial lodgers or landlords, and carers engaged by a " + "charity), apply the 12-week rule for someone who moves in to care " + "(IS, ESA and JSA only), or treat someone as blind for 28 weeks after " + "regaining their sight." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2006/213/regulation/3", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/19", + "https://www.legislation.gov.uk/uksi/2006/213/schedule/3/paragraph/14", + "https://www.legislation.gov.uk/uksi/1987/1967/regulation/3", + "https://www.legislation.gov.uk/uksi/1987/1967/regulation/14", + "https://www.legislation.gov.uk/uksi/1987/1967/schedule/2/paragraph/13", + "https://www.legislation.gov.uk/ukpga/2000/35/section/6", + "https://www.legislation.gov.uk/uksi/2004/747/regulation/2", + ) + + def formula(benunit, period, parameters): + p = parameters(period).gov.dwp.disability_premia + person = benunit.members + counted = ( + (person("age", period) >= p.severe_non_dependant_age) + & ~person("receives_severe_disability_premium_qualifying_benefit", period) + & ~person("is_blind", period) + ) + # The claimant's family is never a non-dependant (HB Regs reg 3(2)(a); + # "young person" is a Child Benefit qualifying young person, reg 19). + family = person("is_claimant_or_partner", period) | person( + "is_child_or_qualifying_young_person_for_child_benefit", period + ) + # Counted residents of the household, less the claimant's family. + in_household = benunit.max(person.household.sum(counted)) + return in_household > benunit.sum(counted & family) diff --git a/policyengine_uk/variables/household/demographic/is_severely_disabled_for_benefits.py b/policyengine_uk/variables/household/demographic/is_severely_disabled_for_benefits.py index c648487f98..2a2ca1b08d 100644 --- a/policyengine_uk/variables/household/demographic/is_severely_disabled_for_benefits.py +++ b/policyengine_uk/variables/household/demographic/is_severely_disabled_for_benefits.py @@ -4,21 +4,71 @@ class is_severely_disabled_for_benefits(Variable): value_type = bool entity = Person - label = "Has a severe disability" - documentation = "Whether this person is severely disabled for benefits purposes" + label = "Severely disabled for the tax credit severe disability elements" + documentation = ( + "Approximates the severe disability condition of the Child Tax Credit " + "disability element (for a child or qualifying young person) and the " + "Working Tax Credit severe disability element (for a claimant): the " + "care component of disability living allowance at the highest rate, " + "the daily living component of personal independence payment at the " + "enhanced rate, attendance allowance at the higher rate (a Working " + "Tax Credit condition) or armed forces " + "independence payment. Other Armed Forces Compensation Scheme " + "payments do not count. The Scottish equivalents and benefit that " + "would be payable but for a hospital stay are not modelled. " + "Attendance allowance is read from its award category (aa_category), " + "which the Enhanced FRS holds after its data pipeline infers it from " + "reported amounts; it is not a directly observed award status. " + "Only where no category is given, as " + "when a household enters an attendance allowance amount directly, is " + "the amount compared with the annual higher rate, less £10 a week; " + "the Regulations have no such tolerance, so that fallback is an " + "approximation. The disability living allowance and personal " + "independence payment tests read amounts, which the model computes " + "from their categories, with the same tolerance for amounts entered " + "directly. The Enhanced FRS also stores this flag, and dataset runs " + "use the stored value instead of this formula " + "(policyengine-uk-data#494 aligns its definition with this one). " + "The legacy severe disability premium has its own, wider list " + "(receives_severe_disability_premium_qualifying_benefit). The flag " + "also gates the Universal Credit higher disabled child addition, " + "whose condition (UC Regs 2013 reg 24(2)(b)) adds blindness and has " + "no armed forces independence payment limb; that is not yet separated." + ) definition_period = YEAR - reference = "Child Tax Credit Regulations 2002 s. 8" + reference = ( + "https://www.legislation.gov.uk/uksi/2002/2007/regulation/8", + "https://www.legislation.gov.uk/uksi/2002/2005/regulation/17", + ) def formula(person, period, parameters): - benefit = parameters(period).gov.dwp + dwp = parameters(period).gov.dwp THRESHOLD_SAFETY_GAP = 10 * WEEKS_IN_YEAR - paragraph_3 = ( + dla_care_highest = ( person("dla_sc", period) - >= benefit.dla.self_care.higher * WEEKS_IN_YEAR - THRESHOLD_SAFETY_GAP + >= dwp.dla.self_care.higher * WEEKS_IN_YEAR - THRESHOLD_SAFETY_GAP ) - paragraph_4 = ( + pip_daily_living_enhanced = ( person("pip_dl", period) - >= benefit.pip.daily_living.enhanced * WEEKS_IN_YEAR - THRESHOLD_SAFETY_GAP + >= dwp.pip.daily_living.enhanced * WEEKS_IN_YEAR - THRESHOLD_SAFETY_GAP + ) + # WTC Regs 2002 reg 17(2): "an attendance allowance at the higher + # rate". The award category decides; an amount is read only when no + # category is given. + aa_category = person("aa_category", period) + aa_categories = aa_category.possible_values + attendance_allowance_higher = where( + aa_category == aa_categories.NONE, + person("attendance_allowance", period) + >= dwp.attendance_allowance.higher * WEEKS_IN_YEAR - THRESHOLD_SAFETY_GAP, + aa_category == aa_categories.HIGHER, + ) + armed_forces_independence_payment = ( + person("armed_forces_independence_payment", period) > 0 + ) + return ( + dla_care_highest + | pip_daily_living_enhanced + | attendance_allowance_higher + | armed_forces_independence_payment ) - paragraph_5 = person("afcs", period) > 0 - return sum([paragraph_3, paragraph_4, paragraph_5]) > 0 diff --git a/policyengine_uk/variables/household/demographic/receives_severe_disability_premium_qualifying_benefit.py b/policyengine_uk/variables/household/demographic/receives_severe_disability_premium_qualifying_benefit.py new file mode 100644 index 0000000000..be318a73d9 --- /dev/null +++ b/policyengine_uk/variables/household/demographic/receives_severe_disability_premium_qualifying_benefit.py @@ -0,0 +1,54 @@ +from policyengine_uk.model_api import * + + +class receives_severe_disability_premium_qualifying_benefit(Variable): + value_type = bool + entity = Person + label = "Receives a severe disability premium qualifying benefit" + documentation = ( + "In receipt of a benefit that makes a claimant or partner severely " + "disabled for the legacy severe disability premium: attendance " + "allowance (either rate), the care component of disability living " + "allowance at the highest or middle rate, the daily living component " + "of personal independence payment at either rate, or armed forces " + "independence payment. The same receipt makes a non-dependant " + "ignored in the premium's residence condition. Armed Forces " + "Compensation Scheme payments other than armed forces independence " + "payment do not qualify. The Scottish equivalents (adult disability " + "payment, pension age disability payment, Scottish adult disability " + "living allowance and, in Housing Benefit and the Scottish Council " + "Tax Reduction scheme, the care component of child disability " + "payment) are not separate model variables; the " + "lists differ slightly between instruments (pension age disability " + "payment is not in the IS and JSA single-claimant lists). The " + "hospital and concessionary-payment rules are not modelled. " + "Household country selects the qualifying-benefit list: Northern " + "Ireland adds armed forces independence payment from 24 December " + "2013 and PIP daily living from 20 June 2016; Great Britain adds " + "both from 8 April 2013. The model reads each list as at 30 April " + "of the year from 2015 and at 1 January before that, without " + "within-year proration. The initial parameter " + "value date preserves the shared model baseline; Northern Ireland " + "historical coverage before 20 November 2006 has not been verified." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2006/213/schedule/3/paragraph/14", + "https://www.legislation.gov.uk/uksi/1987/1967/schedule/2/paragraph/13", + "https://www.legislation.gov.uk/uksi/2008/794/schedule/4/paragraph/6", + "https://www.legislation.gov.uk/uksi/1996/207/schedule/1/paragraph/15", + "https://www.legislation.gov.uk/nisr/2006/405/schedule/4/paragraph/14", + "https://www.legislation.gov.uk/nisr/2006/405/regulation/1/made", + "https://www.legislation.gov.uk/uksi/2013/3021/article/1", + "https://www.legislation.gov.uk/nisr/2016/228/regulation/1", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.dwp.disability_premia + country = person.household("country", period) + northern_ireland = country == country.possible_values.NORTHERN_IRELAND + return where( + northern_ireland, + add(person, period, p.severe_qualifying_benefits_northern_ireland) > 0, + add(person, period, p.severe_qualifying_benefits) > 0, + ) diff --git a/policyengine_uk/variables/household/demographic/severe_disability_premium.py b/policyengine_uk/variables/household/demographic/severe_disability_premium.py index d2de6c640c..4621a87000 100644 --- a/policyengine_uk/variables/household/demographic/severe_disability_premium.py +++ b/policyengine_uk/variables/household/demographic/severe_disability_premium.py @@ -6,31 +6,88 @@ class severe_disability_premium(Variable): entity = BenUnit label = "Severe disability premium" documentation = ( - "Legacy benefit severe disability premium using the model's existing " - "severe-disability indicator for the claimant or partner. The current " - "approximation pays the couple rate when either partner qualifies; " - "the statutory requirement for both partners to qualify and the " - "non-dependant and carer exclusions remain unmodelled." + "Legacy benefit severe disability premium. A single claimant qualifies " + "if they receive a qualifying benefit; a couple qualifies only if both " + "partners do, or if one does and the other is blind (the blind " + "partner is then treated as absent and the single rate applies). The " + "Regulations treat only the claimant's blind partner as absent; the " + "model assumes the qualifying partner is the claimant, as a couple " + "can arrange for Housing Benefit (HB Regs reg 82(1)). There must be " + "no non-dependant aged 18 or over, other than one who receives a " + "qualifying benefit or is blind. A single claimant (or one whose blind " + "partner is treated as absent) must have no one paid a carer benefit " + "for caring for them. A couple who both qualify get the double rate " + "when no carer benefit is paid for either of them, the single rate " + "when one is paid for only one of them, and nothing when carers are " + "paid for both. The law also counts a Universal Credit award with the " + "carer element, which the model does not. Not modelled: a carer's " + "allowance or carer element that would be paid but for a loss of " + "benefit restriction under section 6B or 7 of the Social Security " + "Fraud Act 2001 also counts (HB Regs 2006 Sch 3 para 14(7), IS Regs " + "1987 Sch 2 para 13(5), ESA Regs 2008 Sch 4 para 6(8), JSA Regs 1996 " + "Sch 1 para 15(9)); the model has no input for such a restriction, so " + "where one applies it can pay a premium the law withholds. The " + "Jobseeker's Allowance savings for people protected by the Income " + "Support (General) Amendment (No. 6) Regulations 1991 (JSA Regs 1996 " + "Sch 1 para 15(8)) are not modelled; income-based Jobseeker's " + "Allowance is a reported amount in the model, so this changes no " + "modelled payment." ) definition_period = YEAR reference = ( - "https://www.legislation.gov.uk/uksi/1987/1967/schedule/2/paragraph/13", "https://www.legislation.gov.uk/uksi/2006/213/schedule/3/paragraph/14", + "https://www.legislation.gov.uk/uksi/2006/213/schedule/3/part/4", + "https://www.legislation.gov.uk/uksi/1987/1967/schedule/2/paragraph/13", + "https://www.legislation.gov.uk/uksi/1987/1967/schedule/2/paragraph/15", + "https://www.legislation.gov.uk/uksi/2008/794/schedule/4/paragraph/6", + "https://www.legislation.gov.uk/uksi/1996/207/schedule/1/paragraph/15", + "https://www.legislation.gov.uk/ukpga/2001/11/section/6B", + "https://www.legislation.gov.uk/ukpga/2001/11/section/7", ) unit = GBP def formula(benunit, period, parameters): - dis = parameters(period).gov.dwp.disability_premia - single = benunit("is_single", period.this_year) - couple = benunit("is_couple", period.this_year) - single_premium = single * dis.severe_single - couple_premium = couple * dis.severe_couple - has_severely_disabled_claimant_or_partner = ( - benunit( - "num_severely_disabled_claimants_or_partners_for_legacy_benefits", - period, - ) - > 0 + # The person cared for is not observed. A carer benefit paid to + # someone in the benefit unit is assumed to be for a claimant or + # partner other than its recipient, one person per award. Carers in + # other benefit units are not counted, and carers in other households + # are not observed. The hospital rules that keep a patient treated as + # in receipt (and then pay the single rate) are not modelled. + p = parameters(period).gov.dwp.disability_premia + person = benunit.members + claimant_or_partner = person("is_claimant_or_partner", period) + qualifies = person( + "receives_severe_disability_premium_qualifying_benefit", period + ) + qualifying_member = claimant_or_partner & qualifies + qualifying = benunit.sum(qualifying_member) + partner_treated_as_absent = benunit.any( + claimant_or_partner & ~qualifies & person("is_blind", period) + ) + carer = person("receives_carer_benefit", period) + carers = benunit.sum(carer) + carers_for_qualifying_member = benunit.sum(carer & ~qualifying_member) + # Number of single rates payable: two for a couple who both qualify + # with no carer paid for either, one when a carer is paid for only + # one of them, and one for a single claimant (or a couple whose + # other partner is blind) with no carer paid for them. + couple = benunit("is_couple", period) + single_condition = where( + couple, + (qualifying == 1) & partner_treated_as_absent, + qualifying >= 1, + ) & (carers_for_qualifying_member == 0) + rates = where( + couple & (qualifying >= 2), + max_(2 - carers, 0), + single_condition, + ) + weekly_amount = select( + [rates >= 2, rates == 1], + [p.severe_couple, p.severe_single], + default=0, + ) + no_non_dependant = ~benunit( + "has_non_dependant_for_severe_disability_premium", period ) - weekly_amount = single_premium + couple_premium - return weekly_amount * WEEKS_IN_YEAR * has_severely_disabled_claimant_or_partner + return weekly_amount * WEEKS_IN_YEAR * no_non_dependant