diff --git a/changelog.d/2028.fixed.md b/changelog.d/2028.fixed.md new file mode 100644 index 0000000000..991017c0d1 --- /dev/null +++ b/changelog.d/2028.fixed.md @@ -0,0 +1 @@ +- Limited Carer's Allowance and Carer Support Payment to one eligible partner when a couple cares for the same person, preserving reported-award defaults and underlying entitlement before overlapping benefits. diff --git a/changelog.d/carer-claimant-selection-assumption.changed.md b/changelog.d/carer-claimant-selection-assumption.changed.md new file mode 100644 index 0000000000..014f7cd571 --- /dev/null +++ b/changelog.d/carer-claimant-selection-assumption.changed.md @@ -0,0 +1 @@ +Document that the inferred carer claimant convention can select an unpaid partner and does not maximise the couple's Carer's Allowance or Carer Support Payment. diff --git a/docs/book/assumptions/carer-support-payment-earnings.md b/docs/book/assumptions/carer-support-payment-earnings.md index eeaa6948e0..432d00ca75 100644 --- a/docs/book/assumptions/carer-support-payment-earnings.md +++ b/docs/book/assumptions/carer-support-payment-earnings.md @@ -75,3 +75,44 @@ The open [PR #2518](https://github.com/PolicyEngine/policyengine-uk/pull/2518) changes a shared Carer’s Allowance earnings parameter. Once this reader is shared with CSP, that parameter’s effects on CSP require coordination and validation; this page does not assume the two benefits remain independent of that parameter. + +## Couples caring for the same person + +[SSCBA 1992 section 70(7ZA)](https://www.legislation.gov.uk/ukpga/1992/4/section/70), +the [Northern Ireland counterpart, section 70(7ZA)](https://www.legislation.gov.uk/ukpga/1992/7/section/70), +and [CSP regulation 5(3)](https://www.legislation.gov.uk/ssi/2023/302/regulation/5) +restrict multiple relevant entitlements for the same cared-for person. The +model applies the allowance restriction to the claimant and partner when +`partners_care_for_same_severely_disabled_person` is true. It removes the +second candidate entitlement before reducing either payment for overlapping +benefits. A selected carer whose overlapping benefit removes the payment +still retains the underlying entitlement. + +The law provides election or decision rules; the model does not observe that +choice. Among otherwise eligible partners, it prefers a reported recipient, +then an eligible benefit-unit head, then the eldest eligible partner. Member +order breaks an age tie. This is a modelling convention, not statutory +priority. An ineligible reported recipient or head cannot displace an eligible +partner. The caring-hours, earnings, age and take-up conditions are unchanged. + +The convention does not maximise the couple's payment. It can select a partner +whose overlapping benefits reduce CA or CSP to zero, while suppressing a +payment that the other otherwise-eligible partner could receive if selected. + +The existing same-person default remains: two qualifying reported awards, or +awards that caring hours and take-up cannot explain, indicate different care +targets. Directly supplied payment, pre-overlap or entitlement inputs remain +authoritative. The default reads candidate amounts and supplied inputs before +the couple restriction, so it does not depend on the final awards it limits. +A cached calculation is not treated as a supplied award. Where relationships +are known, supply the same-person flag and claimant/partner flags explicitly. + +This restriction covers units with exactly two claimant/partner flags. It +does not identify care targets across benefit units, allocate awards to other +members, or settle malformed units with more than two partners. The model +still uses caring hours or reported receipt as a proxy for the cared-for +person's qualifying conditions. The statutory coordination with another +person's UC carer element is a separate limitation: the existing UC allocation +can choose a different person from the allowance convention. The couple fix +does not certify that cross-programme allocation. Scottish Carer Supplement +remains separate from the CSP component and follows CSP actually payable. diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/couple_carer_award.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/couple_carer_award.yaml new file mode 100644 index 0000000000..2dbd905a88 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/couple_carer_award.yaml @@ -0,0 +1,635 @@ +# Couple-only Carer’s Allowance and Carer Support Payment regressions (#2028). +# SSCBA 1992 s70(7ZA) and SSI 2023/302 reg5(3) prevent two relevant +# entitlements for the same cared-for person. These synthetic households use +# the model’s qualifying-caring proxy; they do not establish a disability +# award or reproduce individual election/discretion decisions. +# The recorded-award/head fallback is a model convention, not legal priority. +# Different-target defaults and authoritative directly supplied awards remain +# covered by carer_premium.yaml. Base cases explicitly decline UC; the two +# UC controls align both programmes on the elder carer. Cross-programme +# allocation where an election differs from the UC elder default is outside +# this couple-allowance fix. +# The annual rate oracle is 86.45 * 52 = 4,495.40 (current model parameter / +# DWP published 2026-27 table; CSP enacted by SSI 2026/170 reg12(3)(a)). +# Premium: 48.15 * 52 = 2,503.80. UC carer element: 209.34 * 12 = 2,512.08. + +- name: England default same-person couple has one award + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [4495.4, 0] + carers_allowance: [4495.4, 0] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [true, false] + carer_premium: 2503.8 + universal_credit: 0 + +- name: England different care targets preserve both awards + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + partners_care_for_same_severely_disabled_person: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: false + carers_allowance_pre_overlap: [4495.4, 4495.4] + carers_allowance: [4495.4, 4495.4] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [true, true] + carer_premium: 5007.6 + universal_credit: 0 + +- name: England only the partner meets caring conditions + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 0 + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 4495.4] + carers_allowance: [0, 4495.4] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2503.8 + universal_credit: 0 + +- name: England eligible reported partner takes the model priority + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + person2: + age: 38 + care_hours: 0 + carers_allowance_reported: 4000 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 4495.4] + carers_allowance: [0, 4495.4] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2503.8 + universal_credit: 0 + +- name: England ineligible reported claimant cannot displace eligible partner + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + carers_allowance_reported: 4000 + would_claim_carers_allowance: false + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 4495.4] + carers_allowance: [0, 4495.4] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2503.8 + universal_credit: 0 + +- name: England two reported awards preserve the different-target default + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 0 + carers_allowance_reported: 4000 + person2: + age: 38 + care_hours: 0 + carers_allowance_reported: 4000 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: false + carers_allowance_pre_overlap: [4495.4, 4495.4] + carers_allowance: [4495.4, 4495.4] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [true, true] + carer_premium: 5007.6 + universal_credit: 0 + +- name: England member order does not displace the older default head + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + care_hours: 35 + person2: + age: 40 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 4495.4] + carers_allowance: [0, 4495.4] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2503.8 + universal_credit: 0 + +- name: England eligible younger supplied head takes the model fallback + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + care_hours: 35 + is_benunit_head: true + person2: + age: 40 + care_hours: 35 + is_benunit_head: false + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [4495.4, 0] + carers_allowance: [4495.4, 0] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [true, false] + carer_premium: 2503.8 + universal_credit: 0 + +- name: England neither partner meets caring conditions + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 0 + person2: + age: 38 + care_hours: 34 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [false, false] + carer_premium: 0.0 + universal_credit: 0 + +- name: England elder-aligned UC carer element counts only one allowance + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: true + households: + household: + members: [person1, person2] + country: ENGLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [4495.4, 0] + carers_allowance: [4495.4, 0] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [true, false] + carer_premium: 2503.8 + uc_carer_element_included_for_claimant: [true, false] + uc_carer_element: 2512.08 + uc_unearned_income: 4495.4 + +- name: Scotland default same-person couple has one award + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [4495.4, 0] + carer_support_payment: [4495.4, 0] + is_entitled_to_carer_benefit: [true, false] + carer_premium: 2503.8 + universal_credit: 0 + +- name: Scotland different care targets preserve both awards + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + partners_care_for_same_severely_disabled_person: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: false + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [4495.4, 4495.4] + carer_support_payment: [4495.4, 4495.4] + is_entitled_to_carer_benefit: [true, true] + carer_premium: 5007.6 + universal_credit: 0 + +- name: Scotland only the partner meets caring conditions + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 0 + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [0, 4495.4] + carer_support_payment: [0, 4495.4] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2503.8 + universal_credit: 0 + +- name: Scotland eligible reported partner takes the model priority + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + person2: + age: 38 + care_hours: 0 + carers_allowance_reported: 4000 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [0, 4495.4] + carer_support_payment: [0, 4495.4] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2503.8 + universal_credit: 0 + +- name: Scotland ineligible reported claimant cannot displace eligible partner + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + carers_allowance_reported: 4000 + would_claim_carers_allowance: false + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [0, 4495.4] + carer_support_payment: [0, 4495.4] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2503.8 + universal_credit: 0 + +- name: Scotland two reported awards preserve the different-target default + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 0 + carers_allowance_reported: 4000 + person2: + age: 38 + care_hours: 0 + carers_allowance_reported: 4000 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: false + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [4495.4, 4495.4] + carer_support_payment: [4495.4, 4495.4] + is_entitled_to_carer_benefit: [true, true] + carer_premium: 5007.6 + universal_credit: 0 + +- name: Scotland member order does not displace the older default head + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + care_hours: 35 + person2: + age: 40 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [0, 4495.4] + carer_support_payment: [0, 4495.4] + is_entitled_to_carer_benefit: [false, true] + carer_premium: 2503.8 + universal_credit: 0 + +- name: Scotland eligible younger supplied head takes the model fallback + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + care_hours: 35 + is_benunit_head: true + person2: + age: 40 + care_hours: 35 + is_benunit_head: false + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [4495.4, 0] + carer_support_payment: [4495.4, 0] + is_entitled_to_carer_benefit: [true, false] + carer_premium: 2503.8 + universal_credit: 0 + +- name: Scotland neither partner meets caring conditions + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 0 + person2: + age: 38 + care_hours: 34 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: false + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [0, 0] + carer_support_payment: [0, 0] + is_entitled_to_carer_benefit: [false, false] + carer_premium: 0.0 + universal_credit: 0 + +- name: Scotland elder-aligned UC carer element counts only one allowance + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + care_hours: 35 + person2: + age: 38 + care_hours: 35 + benunits: + benunit: + members: [person1, person2] + would_claim_uc: true + households: + household: + members: [person1, person2] + country: SCOTLAND + output: + is_claimant_or_partner: [true, true] + partners_care_for_same_severely_disabled_person: true + carers_allowance_pre_overlap: [0, 0] + carers_allowance: [0, 0] + carer_support_payment_pre_overlap: [4495.4, 0] + carer_support_payment: [4495.4, 0] + is_entitled_to_carer_benefit: [true, false] + carer_premium: 2503.8 + uc_carer_element_included_for_claimant: [true, false] + uc_carer_element: 2512.08 + uc_unearned_income: 4495.4 + diff --git a/policyengine_uk/tests/test_legacy_carer_premium_properties.py b/policyengine_uk/tests/test_legacy_carer_premium_properties.py index 79c0c51fbf..c8a5df1670 100644 --- a/policyengine_uk/tests/test_legacy_carer_premium_properties.py +++ b/policyengine_uk/tests/test_legacy_carer_premium_properties.py @@ -200,13 +200,32 @@ def test_dependants_caring_never_changes_premium_or_is_eligibility(drawn): ) for member in units[i][:n] ] - assert list(entitled[adult_slice]) == claims, units[i] awards = sum( claim and member["carers_allowance_reported"] > 0 for claim, member in zip(claims, units[i][:n]) ) - assert same_person[i] == (awards < 2), units[i] - qualifying = sum(claims) + expected_same = awards < 2 + assert same_person[i] == expected_same, units[i] + # The statutory same-person restriction permits only one couple + # entitlement. Election/discretion is unobserved: this model uses an + # eligible reported award, then the head (the elder in these generated + # families, with the first member winning an age tie). This oracle + # derives the recipient from the fixture inputs, not model outputs. + expected_entitlement = claims.copy() + if n == 2 and expected_same and all(claims): + reported = [ + j + for j, member in enumerate(units[i][:n]) + if member["carers_allowance_reported"] > 0 + ] + recipient = ( + reported[0] + if reported + else max(range(n), key=lambda j: units[i][j]["age"]) + ) + expected_entitlement = [j == recipient for j in range(n)] + assert list(entitled[adult_slice]) == expected_entitlement, units[i] + qualifying = sum(expected_entitlement) if same_person[i]: qualifying = min(qualifying, 1) assert abs(premium[i] - qualifying * amount * WEEKS) < 0.01, units[i] diff --git a/policyengine_uk/utils/couple_carer_award.py b/policyengine_uk/utils/couple_carer_award.py new file mode 100644 index 0000000000..e5d4ca950d --- /dev/null +++ b/policyengine_uk/utils/couple_carer_award.py @@ -0,0 +1,64 @@ +"""Couple-only carer award selection, without reading its own final awards.""" + +import numpy as np + +from policyengine_uk.utils.supplied_inputs import supplied_input + + +def _supplied_receipt(person, period, receipt_name, amount_name): + receipt = supplied_input(person, receipt_name, period) + if receipt is not None: + return receipt + amount = supplied_input(person, amount_name, period) + return np.zeros(person.count, dtype=bool) if amount is None else amount > 0 + + +def unlimited_carer_benefit_entitlement(person, period): + """Keep the existing award inference independent of the couple limit. + + Direct inputs remain authoritative; cached formula results are not inputs. + This mirrors the entitlement reader before the restriction, so the shared + care-target default does not depend on the awards it now restricts. + """ + supplied = supplied_input(person, "is_entitled_to_carer_benefit", period) + if supplied is not None: + return supplied + amounts = [] + for name in ("carers_allowance", "carer_support_payment"): + amount = supplied_input(person, name + "_pre_overlap", period) + if amount is None: + amount = person(name + "_pre_couple_limit", period) + amounts.append(amount) + receives = supplied_input(person, "receives_carer_benefit", period) + if receives is None: + receives = _supplied_receipt( + person, period, "receives_carers_allowance", "carers_allowance" + ) | _supplied_receipt( + person, period, "receives_carer_support_payment", "carer_support_payment" + ) + return (amounts[0] + amounts[1] > 0) | receives + + +def limit_carer_benefit_to_one_partner(person, period, candidate): + """One candidate award for a same-target couple, before overlap reductions. + + Election/discretion is not observed. Prefer an eligible reported recipient, + then an eligible benefit-unit head, then the eldest eligible partner (stable + member order breaks age ties). Other members and units with other than two + claimant/partner flags are outside this couple-only restriction. + """ + benunit = person.benunit + partner = person("is_claimant_or_partner", period) + eligible = partner & (candidate > 0) + reported = eligible & (person("carers_allowance_reported", period) > 0) + preferred = np.where(benunit.any(reported), reported, eligible) + head = preferred & person("is_benunit_head", period) + preferred = np.where(benunit.any(head), head, preferred) + rank = person.get_rank(benunit, -person("age", period), condition=preferred) + selected = preferred & (rank == 0) + restricted = ( + partner + & (benunit.sum(partner) == 2) + & benunit("partners_care_for_same_severely_disabled_person", period) + ) + return np.where(restricted & ~selected, 0, candidate) diff --git a/policyengine_uk/utils/supplied_inputs.py b/policyengine_uk/utils/supplied_inputs.py index 58bc6f0cef..394c8cedbb 100644 --- a/policyengine_uk/utils/supplied_inputs.py +++ b/policyengine_uk/utils/supplied_inputs.py @@ -40,6 +40,14 @@ SUPPLIED_INPUT_VARIABLES = frozenset( { "adjusted_net_income", + "carers_allowance", + "carers_allowance_pre_overlap", + "carer_support_payment", + "carer_support_payment_pre_overlap", + "is_entitled_to_carer_benefit", + "receives_carer_benefit", + "receives_carers_allowance", + "receives_carer_support_payment", "bus_fare_spending", "bus_in_london_trips", "current_education", diff --git a/policyengine_uk/variables/gov/dwp/carers_allowance_pre_couple_limit.py b/policyengine_uk/variables/gov/dwp/carers_allowance_pre_couple_limit.py new file mode 100644 index 0000000000..d2fb955e66 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/carers_allowance_pre_couple_limit.py @@ -0,0 +1,42 @@ +from policyengine_uk.model_api import * + + +class carers_allowance_pre_couple_limit(Variable): + value_type = float + entity = Person + label = "Carer's Allowance before the couple and overlap restrictions" + documentation = ( + "The existing age, caring, earnings and take-up calculation before " + "the same-person couple restriction and overlapping-benefit adjustment. " + "This candidate amount is not final entitlement or payment." + ) + definition_period = YEAR + unit = GBP + reference = ( + "https://www.legislation.gov.uk/ukpga/1992/4/section/70", + "https://www.legislation.gov.uk/ukpga/1992/7/section/70", + ) + + def formula(person, period, parameters): + in_scotland = person.household("country", period).decode_to_str() == "SCOTLAND" + csp_replaces_ca = period.start.year >= 2025 + receives_ca = person("carers_allowance_reported", period) > 0 + ca = parameters(period).gov.dwp.carers_allowance + meets_age_condition = person("age", period) >= ca.min_age + weekly_care_hours = person("care_hours", period) + meets_work_condition = weekly_care_hours >= ca.min_hours + would_claim = person("would_claim_carers_allowance", period) + # SSCBA 1992 s. 70(1)(b): no allowance for anyone gainfully employed, + # which reg. 8 of the 1976 Regulations defines by an earnings limit. + # It applies to reported recipients too. + gainfully_employed = person( + "is_gainfully_employed_for_carers_allowance", period + ) + eligible = ( + ~(in_scotland & csp_replaces_ca) + & (meets_work_condition | receives_ca) + & ~gainfully_employed + & would_claim + & meets_age_condition + ) + return eligible * ca.rate * WEEKS_IN_YEAR diff --git a/policyengine_uk/variables/gov/dwp/carers_allowance_pre_overlap.py b/policyengine_uk/variables/gov/dwp/carers_allowance_pre_overlap.py index 0227da876a..c251fc77d7 100644 --- a/policyengine_uk/variables/gov/dwp/carers_allowance_pre_overlap.py +++ b/policyengine_uk/variables/gov/dwp/carers_allowance_pre_overlap.py @@ -1,4 +1,5 @@ from policyengine_uk.model_api import * +from policyengine_uk.utils.couple_carer_award import limit_carer_benefit_to_one_partner class carers_allowance_pre_overlap(Variable): @@ -6,6 +7,9 @@ class carers_allowance_pre_overlap(Variable): entity = Person label = "Carer's Allowance before the overlapping-benefit adjustment" documentation = ( + "The same-person couple restriction is applied before overlapping " + "benefits, using the reported-award/head modelling convention described " + "in the carer benefit assumptions. " "The Carer's Allowance a person is entitled to before the Social " "Security (Overlapping Benefits) Regulations 1979 reduce it by another " "personal benefit. A person whose allowance is reduced to nil keeps " @@ -15,28 +19,11 @@ class carers_allowance_pre_overlap(Variable): ) definition_period = YEAR unit = GBP - reference = "https://www.legislation.gov.uk/ukpga/1992/4/section/70" + reference = ( + "https://www.legislation.gov.uk/ukpga/1992/4/section/70", + "https://www.legislation.gov.uk/ukpga/1992/7/section/70", + ) def formula(person, period, parameters): - in_scotland = person.household("country", period).decode_to_str() == "SCOTLAND" - csp_replaces_ca = period.start.year >= 2025 - receives_ca = person("carers_allowance_reported", period) > 0 - ca = parameters(period).gov.dwp.carers_allowance - meets_age_condition = person("age", period) >= ca.min_age - weekly_care_hours = person("care_hours", period) - meets_work_condition = weekly_care_hours >= ca.min_hours - would_claim = person("would_claim_carers_allowance", period) - # SSCBA 1992 s. 70(1)(b): no allowance for anyone gainfully employed, - # which reg. 8 of the 1976 Regulations defines by an earnings limit. - # It applies to reported recipients too. - gainfully_employed = person( - "is_gainfully_employed_for_carers_allowance", period - ) - eligible = ( - ~(in_scotland & csp_replaces_ca) - & (meets_work_condition | receives_ca) - & ~gainfully_employed - & would_claim - & meets_age_condition - ) - return eligible * ca.rate * WEEKS_IN_YEAR + candidate = person("carers_allowance_pre_couple_limit", period) + return limit_carer_benefit_to_one_partner(person, period, candidate) 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 new file mode 100644 index 0000000000..775a09b2e4 --- /dev/null +++ b/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_couple_limit.py @@ -0,0 +1,53 @@ +from policyengine_uk.model_api import * + + +class carer_support_payment_pre_couple_limit(Variable): + value_type = float + entity = Person + label = "Carer Support Payment before the couple and overlap restrictions" + documentation = ( + "The existing age, caring, earnings and take-up calculation before " + "the same-person couple restriction and overlapping-benefit adjustment. " + "This candidate amount is not final entitlement or payment." + ) + definition_period = YEAR + unit = GBP + reference = ( + "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/16", + "https://www.legislation.gov.uk/ssi/2023/302/regulation/14", + "https://www.legislation.gov.uk/ssi/2023/302/schedule/2/paragraph/4", + ) + + def formula(person, period, parameters): + in_scotland = person.household("country", period).decode_to_str() == "SCOTLAND" + csp_in_effect = period.start.year >= 2025 + if not csp_in_effect: + return person.empty_array() + 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 + receives_ca = person("carers_allowance_reported", period) > 0 + would_claim = person("would_claim_carers_allowance", period) + earnings = person("carers_allowance_earnings", period) + # Schedule 2 paragraph 4 disregards an adverse fraction of a penny. + # The first excluded weekly amount is the limit plus one penny. + # Compare annual amounts in the reader's dtype so the encoded exact + # penny boundary is not admitted through scalar/array rounding. + first_excluded_annual_earnings = np.asarray( + (csp.earnings_limit + csp.earnings_rounding_precision) * WEEKS_IN_YEAR, + dtype=earnings.dtype, + ) + meets_earnings = earnings < first_excluded_annual_earnings + eligible = ( + in_scotland + & csp_in_effect + & (meets_hours | receives_ca) + & meets_earnings + & meets_age_condition + & would_claim + ) + return eligible * csp.rate * WEEKS_IN_YEAR diff --git a/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_overlap.py b/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_overlap.py index 83dd4aed74..f6c51aeb21 100644 --- a/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_overlap.py +++ b/policyengine_uk/variables/gov/social_security_scotland/carer_support_payment_pre_overlap.py @@ -1,4 +1,5 @@ from policyengine_uk.model_api import * +from policyengine_uk.utils.couple_carer_award import limit_carer_benefit_to_one_partner class carer_support_payment_pre_overlap(Variable): @@ -6,6 +7,9 @@ class carer_support_payment_pre_overlap(Variable): entity = Person label = "Carer Support Payment before the overlapping-benefit reduction" documentation = ( + "The same-person couple restriction is applied before overlapping " + "benefits, using the reported-award/head modelling convention described " + "in the carer benefit assumptions. " "The Carer Support Payment component a carer in Scotland is entitled " "to before regulation 16(2) of the Carer Support Payment Regulations " "reduces it by an overlapping benefit. A carer whose payment is " @@ -23,38 +27,12 @@ class carer_support_payment_pre_overlap(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", ) def formula(person, period, parameters): - in_scotland = person.household("country", period).decode_to_str() == "SCOTLAND" - csp_in_effect = period.start.year >= 2025 - if not csp_in_effect: - return person.empty_array() - 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 - receives_ca = person("carers_allowance_reported", period) > 0 - would_claim = person("would_claim_carers_allowance", period) - earnings = person("carers_allowance_earnings", period) - # Schedule 2 paragraph 4 disregards an adverse fraction of a penny. - # The first excluded weekly amount is the limit plus one penny. - # Compare annual amounts in the reader's dtype so the encoded exact - # penny boundary is not admitted through scalar/array rounding. - first_excluded_annual_earnings = np.asarray( - (csp.earnings_limit + csp.earnings_rounding_precision) * WEEKS_IN_YEAR, - dtype=earnings.dtype, - ) - meets_earnings = earnings < first_excluded_annual_earnings - eligible = ( - in_scotland - & csp_in_effect - & (meets_hours | receives_ca) - & meets_earnings - & meets_age_condition - & would_claim - ) - return eligible * csp.rate * WEEKS_IN_YEAR + candidate = person("carer_support_payment_pre_couple_limit", period) + return limit_carer_benefit_to_one_partner(person, period, candidate) 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 9b22fbf4bc..89d137939c 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 @@ -1,4 +1,5 @@ from policyengine_uk.model_api import * +from policyengine_uk.utils.couple_carer_award import unlimited_carer_benefit_entitlement class partners_care_for_same_severely_disabled_person(Variable): @@ -29,19 +30,22 @@ class partners_care_for_same_severely_disabled_person(Variable): "would claim is not read as an award. " "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 entitlements follow " - "caring hours or a reported award, and do not read this variable." + "Carer's Allowance and Carer Support Payment candidate amounts follow " + "caring hours or a reported award. 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." ) definition_period = YEAR reference = ( "https://www.legislation.gov.uk/ukpga/1992/4/section/70", + "https://www.legislation.gov.uk/ukpga/1992/7/section/70", "https://www.legislation.gov.uk/ssi/2023/302/regulation/5", "https://www.legislation.gov.uk/ssi/2021/249/schedule/1/paragraph/5", ) def formula(benunit, period, parameters): claimant_or_partner = benunit.members("is_claimant_or_partner", period) - entitled = benunit.members("is_entitled_to_carer_benefit", period) + 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