diff --git a/changelog.d/uc-unearned-reg66-benefits.fixed.md b/changelog.d/uc-unearned-reg66-benefits.fixed.md new file mode 100644 index 0000000000..ed7eb0397c --- /dev/null +++ b/changelog.d/uc-unearned-reg66-benefits.fixed.md @@ -0,0 +1 @@ +Count contributory Employment and Support Allowance, Maternity Allowance, industrial injuries benefit and (from 19 November 2023) Scottish Carer Support Payment as Universal Credit unearned income, as UC Regs 2013 reg. 66(1)(b)(ii), (viii), (ix) and (iiia) require. Carer Support Payment counts only its carer support payment component (not the Scottish Carer Supplement) and only up to a year of Carer's Allowance. diff --git a/policyengine_uk/parameters/gov/dwp/universal_credit/means_test/income_definitions/unearned.yaml b/policyengine_uk/parameters/gov/dwp/universal_credit/means_test/income_definitions/unearned.yaml index 489abe3698..0d7a4331b1 100644 --- a/policyengine_uk/parameters/gov/dwp/universal_credit/means_test/income_definitions/unearned.yaml +++ b/policyengine_uk/parameters/gov/dwp/universal_credit/means_test/income_definitions/unearned.yaml @@ -8,6 +8,14 @@ metadata: reference: - title: The Universal Credit Regulations 2013 reg. 66 href: https://www.legislation.gov.uk/uksi/2013/376/regulation/66 + - title: The Universal Credit Regulations 2013 reg. 66(1)(b)(ii), (viii) and (ix) (contributory ESA, maternity allowance, industrial injuries benefit) + href: https://www.legislation.gov.uk/uksi/2013/376/regulation/66 + - title: The Universal Credit Regulations 2013 reg. 2 (employment and support allowance and jobseeker's allowance mean the contributory allowances; industrial injuries benefit means benefit under SSCBA 1992 Part 5) + href: https://www.legislation.gov.uk/uksi/2013/376/regulation/2 + - title: S.I. 2023/1218 art. 23(2) and (5) (defines carer support payment in reg. 2 and inserts reg. 66(1)(b)(iiia), from 19 November 2023) + href: https://www.legislation.gov.uk/uksi/2023/1218/article/23 + - title: S.I. 2026/246 art. 25 (from 15 March 2026 carer support payment means the carer support payment component of carer support) + href: https://www.legislation.gov.uk/uksi/2026/246/article/25 - title: The Universal Credit Regulations 2013 reg. 72 href: https://www.legislation.gov.uk/uksi/2013/376/regulation/72 @@ -16,6 +24,21 @@ values: 2013-04-29: - carers_allowance - jsa_contrib + - esa_contrib + - maternity_allowance + - iidb + - private_pension_income + - uc_tariff_income + - savings_interest_income + - dividend_income + - property_income + 2023-11-19: + - carers_allowance + - uc_unearned_carer_support_payment + - jsa_contrib + - esa_contrib + - maternity_allowance + - iidb - private_pension_income - uc_tariff_income - savings_interest_income diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_unearned_benefits.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_unearned_benefits.yaml new file mode 100644 index 0000000000..3841e1e563 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_unearned_benefits.yaml @@ -0,0 +1,311 @@ +# Benefits that UC Regs 2013 reg. 66(1)(b) counts as unearned income, in full +# and pound for pound (reg. 22(1)(a)): +# - (ii) employment and support allowance, which reg. 2 limits to the +# contributory allowance (esa_contrib); +# - (iiia) carer support payment, from 19 November 2023, "but only up to a +# maximum of the amount a claimant would receive if they had an entitlement +# to carer's allowance"; from 15 March 2026 reg. 2 limits it to the carer +# support payment component of carer support (S.I. 2026/246 art. 25), so +# the Scottish Carer Supplement is left out; +# - (viii) maternity allowance; +# - (ix) industrial injuries benefit (SSCBA 1992 Part 5, reg. 2), excluding +# the s. 104 and s. 105 increases. +# +# Hand calculations use the 2026-27 rates read in April 2026: +# - couple standard allowance (one over 25): 666.97 a month = 8,003.64 a year; +# - carer element: 209.34 a month = 2,512.08 a year; +# - Carer's Allowance and the Carer Support Payment component: 86.45 a week, +# so 86.45 x 52 = 4,495.40 a year; Scottish Carer Supplement 11.70 a week, +# so Carer Support Payment is (86.45 + 11.70) x 52 = 5,103.80 a year; +# - council rent of 6,240 a year is met in full by the housing costs element. +# So a couple's maximum amount is 8,003.64 + 6,240 = 14,243.64, or +# 16,755.72 with the carer element. + +- name: Contributory ESA counts as unearned income + period: 2026 + absolute_error_margin: 0.01 + input: + esa_contrib: 5_000 + output: + uc_unearned_income: 5_000 + +- name: Reported contributory ESA flows through to unearned income + period: 2026 + absolute_error_margin: 0.01 + input: + esa_contrib_reported: 5_000 + output: + esa_contrib: 5_000 + uc_unearned_income: 5_000 + +- name: Maternity Allowance counts as unearned income + period: 2026 + absolute_error_margin: 0.01 + input: + maternity_allowance: 3_000 + output: + uc_unearned_income: 3_000 + +- name: Industrial injuries benefit counts as unearned income + period: 2026 + absolute_error_margin: 0.01 + input: + iidb: 4_000 + output: + uc_unearned_income: 4_000 + +- name: The added benefits sum with the other unearned income + period: 2026 + absolute_error_margin: 0.01 + input: + esa_contrib: 5_000 + maternity_allowance: 1_000 + iidb: 2_000 + private_pension_income: 1_000 + output: + uc_unearned_income: 9_000 + +- name: Couple renting from the council, contributory ESA reduces UC pound for pound + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + esa_contrib: 5_000 + partner: + age: 38 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + tenure_type: RENT_FROM_COUNCIL + rent: 6_240 + output: + uc_maximum_amount: 14_243.64 + uc_unearned_income: 5_000 + uc_income_reduction: 5_000 + # 14,243.64 - 5,000. Before this fix the award was 14,243.64. + universal_credit: 9_243.64 + +- name: Same couple with the same amount of private pension instead gets the same UC + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + private_pension_income: 5_000 + partner: + age: 38 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + tenure_type: RENT_FROM_COUNCIL + rent: 6_240 + output: + uc_unearned_income: 5_000 + universal_credit: 9_243.64 + +- name: Maternity Allowance reduces UC pound for pound + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 30 + maternity_allowance: 3_000 + partner: + age: 32 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + tenure_type: RENT_FROM_COUNCIL + rent: 6_240 + output: + uc_unearned_income: 3_000 + # 14,243.64 - 3,000. + universal_credit: 11_243.64 + +- name: Industrial injuries benefit reduces UC pound for pound + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 50 + iidb: 4_000 + partner: + age: 48 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + tenure_type: RENT_FROM_COUNCIL + rent: 6_240 + output: + uc_unearned_income: 4_000 + # 14,243.64 - 4,000. + universal_credit: 10_243.64 + +- name: Contributory ESA above the maximum amount removes UC entirely + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + esa_contrib: 20_000 + partner: + age: 38 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + tenure_type: RENT_FROM_COUNCIL + rent: 6_240 + output: + uc_unearned_income: 20_000 + # The reduction is capped at the maximum amount. + uc_income_reduction: 14_243.64 + universal_credit: 0 + +- name: Scottish carer on Carer Support Payment, only the component up to Carer's Allowance counts + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + care_hours: 40 + partner: + age: 38 + benunits: + benunit: + members: [carer, partner] + households: + household: + members: [carer, partner] + country: SCOTLAND + tenure_type: RENT_FROM_COUNCIL + rent: 6_240 + output: + carers_allowance: [0, 0] + # (86.45 + 11.70) x 52. + carer_support_payment: [5_103.80, 0] + # Capped at a year of Carer's Allowance, 86.45 x 52, which is also the + # carer support payment component without the supplement. + uc_unearned_carer_support_payment: [4_495.40, 0] + uc_unearned_income: 4_495.40 + uc_maximum_amount: 16_755.72 + # 16,755.72 - 4,495.40. Before this fix the award was 16,755.72. + universal_credit: 12_260.32 + +- name: Same carer in England gets Carer's Allowance and the same UC + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + care_hours: 40 + partner: + age: 38 + benunits: + benunit: + members: [carer, partner] + households: + household: + members: [carer, partner] + country: ENGLAND + tenure_type: RENT_FROM_COUNCIL + rent: 6_240 + output: + carers_allowance: [4_495.40, 0] + carer_support_payment: [0, 0] + uc_unearned_carer_support_payment: [0, 0] + # Carer's Allowance alone, not counted a second time as Carer Support + # Payment. + uc_unearned_income: 4_495.40 + uc_maximum_amount: 16_755.72 + universal_credit: 12_260.32 + +- name: Carer Support Payment below a year of Carer's Allowance counts in full + period: 2026 + absolute_error_margin: 0.01 + input: + carer_support_payment: 3_000 + output: + # Under the cap of 86.45 x 52 = 4,495.40. + uc_unearned_carer_support_payment: 3_000 + uc_unearned_income: 3_000 + +- name: Carer Support Payment above a year of Carer's Allowance is capped + period: 2026 + absolute_error_margin: 0.01 + input: + carer_support_payment: 6_000 + output: + # Capped at 86.45 x 52 = 4,495.40. + uc_unearned_carer_support_payment: 4_495.40 + uc_unearned_income: 4_495.40 + +- name: Carer Support Payment does not count in 2023-24 + period: 2023 + absolute_error_margin: 0.01 + input: + carer_support_payment: 3_000 + output: + # Reg. 66(1)(b)(iiia) starts on 19 November 2023, part-way through + # 2023-24. The yearly model takes each parameter's value on 30 April of + # the fiscal year (convert_to_fiscal_year_parameters), so Carer Support + # Payment first counts in 2024-25. + uc_unearned_carer_support_payment: 3_000 + uc_unearned_income: 0 + +- name: Carer Support Payment counts in 2024-25, before the Scottish Carer Supplement + period: 2024 + absolute_error_margin: 0.01 + input: + carer_support_payment: 3_000 + output: + # Under the 2024-25 cap of 81.90 x 52 = 4,258.80. + uc_unearned_carer_support_payment: 3_000 + uc_unearned_income: 3_000 + +- name: Contributory ESA also counts in 2020-21 + period: 2020 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + esa_contrib: 5_000 + partner: + age: 38 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + tenure_type: RENT_FROM_COUNCIL + rent: 6_240 + output: + # The whole 5,000 is unearned income and comes off the maximum amount, + # which it does not exceed. (The maximum amount itself is not asserted: + # the 2020-21 standard allowance parameter holds the 2021-22 figures.) + uc_unearned_income: 5_000 + uc_income_reduction: 5_000 diff --git a/policyengine_uk/tests/test_uc_unearned_benefits_properties.py b/policyengine_uk/tests/test_uc_unearned_benefits_properties.py new file mode 100644 index 0000000000..4a2cba3ae6 --- /dev/null +++ b/policyengine_uk/tests/test_uc_unearned_benefits_properties.py @@ -0,0 +1,338 @@ +"""Property-based tests for the reg. 66(1)(b) benefits in the UC means test. + +UC Regs 2013 reg. 66(1)(b) counts contributory employment and support +allowance (ii), carer support payment up to the Carer's Allowance amount +(iiia), maternity allowance (viii) and industrial injuries benefit (ix) as +unearned income, and reg. 22(1)(a) deducts all unearned income from the +maximum amount. + +Invariants, for any generated population of working-age families: + +1. Monotone: the UC award before the benefit cap is non-increasing in each + of the four benefits, the maximum amount does not change, and unearned + income rises by exactly the amount that counts: the whole increase for + ESA, maternity allowance and industrial injuries benefit, and for carer + support payment the increase in min(payment, a year of Carer's + Allowance). The award after the benefit cap is non-increasing too for + families that already received the benefit; starting to receive + contributory ESA or industrial injuries benefit can lift the cap, because + receipt exempts the family from it. +2. Pound for pound: with no earnings in the family, raising one of the + benefits by d lowers the award before the benefit cap by exactly + min(counted increase, award). +3. Equivalence: with no earnings in the family, UC before the benefit cap + with x of the benefit equals UC with the counted amount of private pension + received by the same person instead. For carer support payment both + families keep the carer's caring hours, so both get the carer element. + +Invariants 2 and 3, and invariant 1 for carer support payment, are +restricted to families without earnings because the model deducts the whole +benefit unit's income tax from its earnings +(PolicyEngine/policyengine-uk#1942), so tax on a taxable benefit or pension +reduces earned income. Carer support payment is taxable, so above the cap, +where more of it adds nothing to unearned income, the carer's extra tax +lowers the partner's earned income and raises the award. The strict xfail +below pins that case and will flip when #1942 is fixed; widen these +invariants to all families then. They compare the award before the benefit cap because +contributory ESA and industrial injuries benefit trigger benefit cap +exemptions and ESA counts towards the cap, which private pension does not. +""" + +import numpy as np +import pytest +from hypothesis import HealthCheck, example, given, settings +from hypothesis import strategies as st + +from policyengine_uk import Simulation + +PROPERTY_SETTINGS = settings( + max_examples=10, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) +# 2020 has the temporary standard allowance uplift; 2025 has Carer Support +# Payment without the Scottish Carer Supplement, 2026 with it. +YEARS = [2020, 2025, 2026] +CSP_YEARS = [2025, 2026] +# Contributory ESA is entered as the reported amount, which income tax also +# sees, so tests with earnings exercise the tax path (#1942). +BENEFITS = ["esa_contrib_reported", "maternity_allowance", "iidb"] +TENURES = [ + "RENT_FROM_COUNCIL", + "RENT_FROM_HA", + "RENT_PRIVATELY", + "OWNED_OUTRIGHT", + "OWNED_WITH_MORTGAGE", +] +# A lone parent of two in 2026 whose private rent takes UC over the benefit +# cap: starting contributory ESA exempts the family from the cap, so the award +# after the cap rises even though the award before it falls. +CAPPED_LONE_PARENT = dict( + ages=[30], + children=[3, 5], + tenure="RENT_PRIVATELY", + rent=25_000.0, + savings=0.0, + earnings=0.0, + amount=0.0, +) +WORKING_AGE = st.integers(18, 60) +money = st.floats(0, 30_000, allow_nan=False, allow_infinity=False) +UC_VARIABLES = [ + "universal_credit", + "universal_credit_pre_benefit_cap", + "uc_earned_income", + "uc_unearned_income", + "uc_income_reduction", + "uc_maximum_amount", +] + + +@st.composite +def families(draw, with_earnings=True): + earnings = draw(st.one_of(st.just(0.0), money)) if with_earnings else 0.0 + return dict( + ages=[draw(WORKING_AGE) for _ in range(draw(st.integers(1, 2)))], + children=[draw(st.integers(0, 15)) for _ in range(draw(st.integers(0, 2)))], + tenure=draw(st.sampled_from(TENURES)), + rent=draw(money), + savings=draw(st.one_of(st.just(0.0), st.floats(0, 20_000))), + earnings=earnings, + amount=draw(money), + ) + + +def situation(units, year, income_variable, bump=0.0, carer=False): + """Build one simulation holding every family. + + The first adult receives the family's ``amount`` (plus ``bump``) under + ``income_variable``; a partner receives the family's earnings. With + ``carer``, the first adult cares for 40 hours a week in Scotland and has + carer support payment set explicitly (zero unless it is the income + variable), so the carer element applies whatever the income. + """ + people, benunits, households = {}, {}, {} + for i, unit in enumerate(units): + names = [] + for j, age in enumerate(unit["ages"]): + name = f"p{i}_{j}" + person = {"age": {year: age}} + if j == 0: + if carer: + person["care_hours"] = {year: 40} + person["carer_support_payment"] = {year: 0.0} + person[income_variable] = {year: unit["amount"] + bump} + else: + person["employment_income"] = {year: unit["earnings"]} + people[name] = person + names.append(name) + for k, age in enumerate(unit["children"]): + name = f"c{i}_{k}" + people[name] = {"age": {year: age}} + names.append(name) + benunits[f"b{i}"] = {"members": names} + households[f"h{i}"] = { + "members": names, + "rent": {year: unit["rent"]}, + "tenure_type": {year: unit["tenure"]}, + "savings": {year: unit["savings"]}, + "country": {year: "SCOTLAND" if carer else "ENGLAND"}, + } + return {"people": people, "benunits": benunits, "households": households} + + +def calculate(units, year, income_variable, **kwargs): + sim = Simulation(situation=situation(units, year, income_variable, **kwargs)) + values = {v: np.asarray(sim.calculate(v, year)) for v in UC_VARIABLES} + counted = np.asarray(sim.calculate("uc_unearned_carer_support_payment", year)) + values["counted_csp"] = np.asarray( + sim.map_result(counted, "person", "benunit", how="sum") + ) + return values + + +def assert_same(a, b, variables, message): + for variable in variables: + np.testing.assert_allclose( + a[variable], b[variable], atol=0.01, err_msg=f"{variable}: {message}" + ) + + +def assert_monotone(low, high, increase, units): + pre_cap = "universal_credit_pre_benefit_cap" + assert np.all(high[pre_cap] <= low[pre_cap] + 0.01), units + received = np.array([unit["amount"] > 0 for unit in units]) + capped = high["universal_credit"][received] + assert np.all(capped <= low["universal_credit"][received] + 0.01), units + np.testing.assert_allclose( + high["uc_maximum_amount"], low["uc_maximum_amount"], atol=0.01 + ) + np.testing.assert_allclose( + high["uc_unearned_income"] - low["uc_unearned_income"], + increase, + atol=0.01, + err_msg=str(units), + ) + + +@PROPERTY_SETTINGS +@given( + units=st.lists(families(), min_size=1, max_size=20), + benefit=st.sampled_from(BENEFITS), + bump=st.floats(0, 20_000, allow_nan=False, allow_infinity=False), + year=st.sampled_from(YEARS), +) +@example( + units=[CAPPED_LONE_PARENT], + benefit="esa_contrib_reported", + bump=1_000.0, + year=2026, +) +@example( + units=[dict(CAPPED_LONE_PARENT, amount=500.0)], + benefit="esa_contrib_reported", + bump=1_000.0, + year=2026, +) +def test_uc_is_non_increasing_in_each_benefit(units, benefit, bump, year): + low = calculate(units, year, benefit) + high = calculate(units, year, benefit, bump=bump) + assert_monotone(low, high, bump, units) + + +@PROPERTY_SETTINGS +@given( + units=st.lists(families(with_earnings=False), min_size=1, max_size=20), + bump=st.floats(0, 20_000, allow_nan=False, allow_infinity=False), + year=st.sampled_from(CSP_YEARS), +) +def test_uc_is_non_increasing_in_carer_support_payment(units, bump, year): + low = calculate(units, year, "carer_support_payment", carer=True) + high = calculate(units, year, "carer_support_payment", bump=bump, carer=True) + increase = high["counted_csp"] - low["counted_csp"] + assert np.all(increase >= -0.01), units + assert_monotone(low, high, increase, units) + + +@PROPERTY_SETTINGS +@given( + units=st.lists(families(with_earnings=False), min_size=1, max_size=20), + benefit=st.sampled_from(BENEFITS), + bump=st.floats(0, 20_000, allow_nan=False, allow_infinity=False), + year=st.sampled_from(YEARS), +) +def test_uc_falls_pound_for_pound_in_each_benefit(units, benefit, bump, year): + low = calculate(units, year, benefit) + high = calculate(units, year, benefit, bump=bump) + award = low["universal_credit_pre_benefit_cap"] + np.testing.assert_allclose( + high["universal_credit_pre_benefit_cap"], + award - np.minimum(bump, award), + atol=0.01, + err_msg=str(units), + ) + + +@PROPERTY_SETTINGS +@given( + units=st.lists(families(with_earnings=False), min_size=1, max_size=20), + bump=st.floats(0, 20_000, allow_nan=False, allow_infinity=False), + year=st.sampled_from(CSP_YEARS), +) +def test_uc_falls_pound_for_pound_in_counted_carer_support_payment(units, bump, year): + low = calculate(units, year, "carer_support_payment", carer=True) + high = calculate(units, year, "carer_support_payment", bump=bump, carer=True) + award = low["universal_credit_pre_benefit_cap"] + increase = high["counted_csp"] - low["counted_csp"] + np.testing.assert_allclose( + high["universal_credit_pre_benefit_cap"], + award - np.minimum(increase, award), + atol=0.01, + err_msg=str(units), + ) + + +@PROPERTY_SETTINGS +@given( + units=st.lists(families(with_earnings=False), min_size=1, max_size=20), + benefit=st.sampled_from(BENEFITS), + year=st.sampled_from(YEARS), +) +def test_each_benefit_counts_like_private_pension(units, benefit, year): + assert_same( + calculate(units, year, benefit), + calculate(units, year, "private_pension_income"), + [v for v in UC_VARIABLES if v != "universal_credit"], + str(units), + ) + + +@PROPERTY_SETTINGS +@given( + units=st.lists(families(with_earnings=False), min_size=1, max_size=20), + year=st.sampled_from(CSP_YEARS), +) +def test_carer_support_payment_counts_like_capped_private_pension(units, year): + with_csp = calculate(units, year, "carer_support_payment", carer=True) + # The same family with the counted amount of Carer Support Payment + # received as private pension instead. + counted = [dict(unit, amount=c) for unit, c in zip(units, with_csp["counted_csp"])] + with_pension = calculate(counted, year, "private_pension_income", carer=True) + assert_same( + with_csp, + with_pension, + [v for v in UC_VARIABLES if v != "universal_credit"], + str(units), + ) + + +@pytest.mark.xfail( + strict=True, + reason=( + "PolicyEngine/policyengine-uk#1942: uc_earned_income deducts the whole " + "benefit unit's income tax, including the carer's tax on Carer Support " + "Payment, from the partner's earnings" + ), +) +def test_carer_support_payment_above_the_cap_does_not_change_uc(): + # 2026, Scotland: a carer aged 40 caring 40 hours a week with private + # pension of 9,000 and a partner aged 38 earning 4,000 (under the personal + # allowance and the NI primary threshold, so no tax or NI of their own), + # council rent 6,240. Carer Support Payment of 6,000 and of 7,000 both + # count as the cap, 86.45 x 52 = 4,495.40. The carer pays more income tax + # on the larger payment, but reg. 55(5)(b) and reg. 57 step 3 allow only + # tax on the partner's own earnings, so earned income stays 4,000 and the + # award is the same: + # maximum amount = 8,003.64 + 6,240 + 2,512.08 = 16,755.72; + # UC = 16,755.72 - (4,495.40 + 9,000) - 0.55 x 4,000 = 1,060.32. + for carer_support_payment in [6_000, 7_000]: + people = { + "carer": { + "age": {2026: 40}, + "care_hours": {2026: 40}, + "carer_support_payment": {2026: carer_support_payment}, + "private_pension_income": {2026: 9_000}, + }, + "partner": {"age": {2026: 38}, "employment_income": {2026: 4_000}}, + } + members = list(people) + sim = Simulation( + situation={ + "people": people, + "benunits": {"benunit": {"members": members}}, + "households": { + "household": { + "members": members, + "country": {2026: "SCOTLAND"}, + "tenure_type": {2026: "RENT_FROM_COUNCIL"}, + "rent": {2026: 6_240}, + } + }, + } + ) + assert sim.calculate("income_tax", 2026)[0] > 0 + earned = sim.calculate("uc_earned_income", 2026)[0] + award = sim.calculate("universal_credit", 2026)[0] + assert earned == pytest.approx(4_000, abs=0.01) + assert award == pytest.approx(1_060.32, abs=0.01) diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/income/uc_unearned_carer_support_payment.py b/policyengine_uk/variables/gov/dwp/universal_credit/income/uc_unearned_carer_support_payment.py new file mode 100644 index 0000000000..376fd3c41d --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/universal_credit/income/uc_unearned_carer_support_payment.py @@ -0,0 +1,32 @@ +from policyengine_uk.model_api import * + + +class uc_unearned_carer_support_payment(Variable): + value_type = float + entity = Person + label = "Carer Support Payment counted as Universal Credit unearned income" + documentation = ( + "Carer Support Payment counts as unearned income 'but only up to a " + "maximum of the amount a claimant would receive if they had an " + "entitlement to carer's allowance' (UC Regs 2013 reg. 66(1)(b)(iiia), " + "from 19 November 2023), so it is capped at a year of Carer's " + "Allowance. From 15 March 2026 reg. 2 limits 'carer support payment' " + "to the carer support payment component of carer support (S.I. " + "2026/246 art. 25), which excludes the Scottish Carer Supplement. The " + "component is paid at the Carer's Allowance rate, so for a full year " + "of Carer Support Payment the cap also removes the supplement that " + "carer_support_payment currently includes." + ) + definition_period = YEAR + unit = GBP + reference = [ + "https://www.legislation.gov.uk/uksi/2013/376/regulation/66", + "https://www.legislation.gov.uk/uksi/2013/376/regulation/2", + "https://www.legislation.gov.uk/uksi/2023/1218/article/23", + "https://www.legislation.gov.uk/uksi/2026/246/article/25", + ] + + def formula(person, period, parameters): + ca = parameters(period).gov.dwp.carers_allowance + carer_support_payment = person("carer_support_payment", period) + return min_(carer_support_payment, ca.rate * WEEKS_IN_YEAR)