diff --git a/changelog.d/pc-earnings-disregard.fixed.md b/changelog.d/pc-earnings-disregard.fixed.md new file mode 100644 index 000000000..8a95e17db --- /dev/null +++ b/changelog.d/pc-earnings-disregard.fixed.md @@ -0,0 +1 @@ +Apply the Pension Credit earnings disregards of SPC Regs 2002 Schedule VI: 20 pounds a week for lone parents, carers and claimants or partners on a listed disability benefit or certified blind, otherwise 5 pounds (single) or 10 pounds (couple), capped at earnings. diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/amount.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/amount.yaml new file mode 100644 index 000000000..bc51f7354 --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/amount.yaml @@ -0,0 +1,10 @@ +description: Weekly earnings disregarded from Pension Credit income for a lone parent, a carer, or a claimant or partner on a listed disability benefit or certified blind. It is the most that can be disregarded however many conditions are met. +values: + 2003-10-06: 20 +metadata: + unit: currency-GBP + period: week + label: Pension Credit higher earnings disregard + reference: + - title: The State Pension Credit Regulations 2002 Sch. VI paras. 1, 3, 4 and 4A + href: https://www.legislation.gov.uk/uksi/2002/1792/schedule/VI diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/disability_benefit_unit_benefits.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/disability_benefit_unit_benefits.yaml new file mode 100644 index 000000000..8e31a2865 --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/disability_benefit_unit_benefits.yaml @@ -0,0 +1,19 @@ +description: > + Benefit-unit awards whose receipt qualifies the benefit unit for the higher + Pension Credit earnings disregard (Sch. VI para. 4(1)(a)(vii), employment + and support allowance, from 27 October 2008). The model holds income-related + employment and support allowance on the benefit unit, as the claimant's + award; contributory employment and support allowance is a person-level + benefit in `disability_benefits`. +metadata: + label: Pension Credit higher earnings disregard benefit-unit disability benefits + unit: list + reference: + - title: The State Pension Credit Regulations 2002 Sch. VI para. 4(1)(a)(vii) + href: https://www.legislation.gov.uk/uksi/2002/1792/schedule/VI/paragraph/4 + - title: The Employment and Support Allowance (Consequential Provisions) (No. 2) Regulations 2008 reg. 4(10)(a)(ii) + href: https://www.legislation.gov.uk/uksi/2008/1554/regulation/4 +values: + 2003-10-06: [] + 2008-10-27: + - esa_income diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/disability_benefits.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/disability_benefits.yaml new file mode 100644 index 000000000..e2ea6f332 --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/higher/disability_benefits.yaml @@ -0,0 +1,46 @@ +description: > + Person-level benefits whose receipt by the claimant or partner qualifies the + benefit unit for the higher Pension Credit earnings disregard (Sch. VI para. + 4(1)(a)). Income-related employment and support allowance, a benefit-unit + award, is in `disability_benefit_unit_benefits`. + `incapacity_benefit` stands for long-term incapacity benefit (para. + 4(1)(a)(i)); the model does not separate the short-term rates. Not modelled: + the war pensions mobility supplement (v), which has no variable; pension age + disability payment (iiia, from 21 October 2024), Scottish adult disability + living allowance (iva, from 21 March 2025) and adult disability payment + (viiia, from 21 March 2022), which have no separate variables; and the + working tax credit disability elements (vi), left out because in the model + they follow from DLA or PIP, which are listed, and working tax credit ended + in April 2025. +metadata: + label: Pension Credit higher earnings disregard disability benefits + unit: list + reference: + - title: The State Pension Credit Regulations 2002 Sch. VI para. 4(1)(a) + href: https://www.legislation.gov.uk/uksi/2002/1792/schedule/VI/paragraph/4 + - title: The Employment and Support Allowance (Consequential Provisions) (No. 2) Regulations 2008 reg. 4(10)(a)(ii) (ESA, from 27 October 2008) + href: https://www.legislation.gov.uk/uksi/2008/1554/regulation/4 + - title: The Personal Independence Payment (Supplementary Provisions and Consequential Amendments) Regulations 2013 Sch. para. 27(8)(b) (PIP, from 8 April 2013) + href: https://www.legislation.gov.uk/uksi/2013/388/schedule/paragraph/27 + - title: "The Armed Forces and Reserve Forces Compensation Scheme (Consequential Provisions: Subordinate Legislation) Order 2013 Sch. para. 23(8)(b) (AFIP, from 8 April 2013)" + href: https://www.legislation.gov.uk/uksi/2013/591/schedule/paragraph/23 +values: + 2003-10-06: + - incapacity_benefit + - sda + - attendance_allowance + - dla + 2008-10-27: + - incapacity_benefit + - sda + - attendance_allowance + - dla + - esa_contrib + 2013-04-08: + - incapacity_benefit + - sda + - attendance_allowance + - dla + - esa_contrib + - pip + - armed_forces_independence_payment diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/standard.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/standard.yaml new file mode 100644 index 000000000..80ffae79f --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/pension_credit/earnings_disregard/standard.yaml @@ -0,0 +1,20 @@ +description: Weekly earnings disregarded from Pension Credit income where neither the claimant nor a partner qualifies for the higher disregard. +SINGLE: + values: + 2003-10-06: 5 + metadata: + label: Pension Credit standard earnings disregard (single) +COUPLE: + values: + 2003-10-06: 10 + metadata: + label: Pension Credit standard earnings disregard (couple) +metadata: + unit: currency-GBP + period: week + propagate_metadata_to_children: true + reference: + - title: The State Pension Credit Regulations 2002 Sch. VI para. 5 + href: https://www.legislation.gov.uk/uksi/2002/1792/schedule/VI/paragraph/5 + - title: The State Pension Credit Regulations 2002 reg. 17(9) + href: https://www.legislation.gov.uk/uksi/2002/1792/regulation/17 diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/claimant_partner_income_and_carers.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/claimant_partner_income_and_carers.yaml index 462cdd1fc..a54bf6b73 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/claimant_partner_income_and_carers.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/claimant_partner_income_and_carers.yaml @@ -160,9 +160,13 @@ is_claimant_or_partner: [true, true] # SPCA 2002 s.5: gross = 5,000 + 1,000 + 100 + 2,000 + 500 + 200 # + 104 = 8,904; deductions = 100 + 50 + 25 + 50% * 300 = 325. - pension_credit_income: 8_579 + # Sch VI para 3 (both carers): 20 pounds a week, capped at net earnings + # (claimant 1,000 - 100 tax - 100 half contributions = 800; partner + # 500 - 25 NI - 50 tax - 50 = 375; 1,175), so 1,040 is disregarded: + # 8,904 - 325 - 1,040. + pension_credit_income: 7_539 # Reg.9: remove the claimant's 100 JSA and partner's 200 ESA. - savings_credit_income: 8_279 + savings_credit_income: 7_239 # Sch.I para.4 and the 2026 carer addition: 2 * 48.15 * 52 = 5,007.60. carer_minimum_guarantee_addition: 5_007.60 diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_earnings_disregard.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_earnings_disregard.yaml new file mode 100644 index 000000000..709c69578 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_earnings_disregard.yaml @@ -0,0 +1,407 @@ +# Expected values are hand-computed from SPC Regs 2002 Sch VI (paras 1, 3, 4, +# 4A and 5): weekly amounts times 52 weeks, capped at the earnings. + +- name: A single claimant with earnings has 5 pounds a week disregarded (para 5(a)). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 5 * 52 + +- name: A couple with earnings has 10 pounds a week disregarded (para 5(b)). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + partner: + age: 70 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + output: + pension_credit_earnings_disregard: 10 * 52 + +- name: A claimant on attendance allowance has 20 pounds a week disregarded (para 4(1)(a)(iii)). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + attendance_allowance: 3000 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 20 * 52 + +- name: A partner's personal independence payment qualifies the couple (para 4(1)(a)(viii)). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + partner: + age: 70 + pip_dl: 3000 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + output: + pension_credit_earnings_disregard: 20 * 52 + +- name: A carer satisfying Sch I para 4 has 20 pounds a week disregarded (para 3). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + is_entitled_to_carer_benefit: true + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 20 * 52 + +- name: A lone parent has 20 pounds a week disregarded (para 1). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + child: + age: 10 + benunits: + benunit: + members: [claimant, child] + households: + household: + members: [claimant, child] + output: + pension_credit_earnings_disregard: 20 * 52 + +- name: A claimant certified blind has 20 pounds a week disregarded (para 4(1)(b)). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + is_blind: true + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 20 * 52 + +- name: 20 pounds is the most disregarded when both partners qualify (para 4A). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + attendance_allowance: 3000 + partner: + age: 70 + employment_income: 2000 + dla_sc: 3000 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + output: + pension_credit_earnings_disregard: 20 * 52 + +- name: The disregard never exceeds the earnings. + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 100 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 100 + +- name: Self-employed earnings get the same disregard. + period: 2024 + input: + people: + claimant: + age: 70 + self_employment_income: 2000 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 5 * 52 + +- name: Without earnings there is nothing to disregard. + period: 2024 + input: + people: + claimant: + age: 70 + attendance_allowance: 3000 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 0 + +- name: A dependant child's disability benefit does not qualify a couple for the higher disregard. + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + partner: + age: 70 + child: + age: 10 + dla_sc: 3000 + benunits: + benunit: + members: [claimant, partner, child] + households: + household: + members: [claimant, partner, child] + output: + pension_credit_earnings_disregard: 10 * 52 + +- name: Income-related ESA, a benefit-unit award, qualifies for the higher disregard. + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + benunits: + benunit: + members: [claimant] + esa_income: 1000 + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 20 * 52 + +- name: The disregard comes off Pension Credit income and raises the guarantee credit. + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2000 + state_pension: 9000 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + # minimum guarantee 218.15 a week in 2024-25 (SI 2024/242) + pension_credit_income: 9_000 + 2_000 - 5 * 52 + guarantee_credit: 218.15 * 52 - (9_000 + 2_000 - 5 * 52) + +- name: A taxpayer's disregard is capped at net earnings, so earnings below the disregard leave Pension Credit income unchanged (reg 17(9), 17(10)). + period: 2024 + input: + people: + claimant: + age: 70 + state_pension: 12_000 + private_pension_income: 3_000 + attendance_allowance: 3_000 + employment_income: 1_040 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + # Income tax (16,040 - 12,570) x 20% = 694. Tax on the earnings is the + # lesser of 694 and 20% x 1,040 = 208, so net earnings are 832; the 20 + # pound (attendance allowance) disregard of 1,040 is capped at 832. + pension_credit_earnings_disregard: 832 + # 16,040 - 694 - 832, the same as with no earnings (next case). + pension_credit_income: 14_514 + +- name: The same claimant with no earnings has the same Pension Credit income. + period: 2024 + input: + people: + claimant: + age: 70 + state_pension: 12_000 + private_pension_income: 3_000 + attendance_allowance: 3_000 + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + # 15,000 - (15,000 - 12,570) x 20% + pension_credit_earnings_disregard: 0 + pension_credit_income: 14_514 + +- name: A dependant's caring does not qualify a couple for the higher disregard (Sch I para 4 is the claimant's or partner's). + period: 2024 + input: + people: + claimant: + age: 70 + employment_income: 2_000 + partner: + age: 70 + child: + age: 17 + is_entitled_to_carer_benefit: true + benunits: + benunit: + members: [claimant, partner, child] + households: + household: + members: [claimant, partner, child] + output: + pension_credit_earnings_disregard: 10 * 52 + +- name: A Scottish taxpayer's tax on earnings is their top slice on the Scottish schedule, so Pension Credit income does not fall with earnings. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 70 + state_pension: 12_000 + private_pension_income: 16_000 + attendance_allowance: 5_000 + employment_income: 1_040 + partner: + age: 70 + attendance_allowance: 5_000 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + country: SCOTLAND + output: + # The 1,040 of earnings add 210.89 of income tax (they cross into the + # Scottish intermediate band), so net earnings are 829.11 and the 20 pound + # disregard of 1,040 is capped there; income is as with no earnings (next). + income_tax: [3_016.62, 0] + pension_credit_earnings_disregard: 829.11 + pension_credit_income: 25_194.27 + +- name: The same Scottish couple with no earnings has the same Pension Credit income. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 70 + state_pension: 12_000 + private_pension_income: 16_000 + attendance_allowance: 5_000 + partner: + age: 70 + attendance_allowance: 5_000 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + country: SCOTLAND + output: + income_tax: [2_805.73, 0] + pension_credit_earnings_disregard: 0 + pension_credit_income: 25_194.27 + +- name: Caring hours without entitlement to carer's allowance do not qualify for the 20 pound disregard (Sch VI para 3 needs Sch I para 4). + period: 2025 + input: + people: + claimant: + age: 70 + state_pension: 9_000 + employment_income: 2_000 + care_hours: 40 + is_entitled_to_carer_benefit: false + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 5 * 52 + +- name: Entitlement to carer's allowance qualifies for the 20 pound disregard. + period: 2025 + input: + people: + claimant: + age: 70 + state_pension: 9_000 + employment_income: 2_000 + care_hours: 40 + is_entitled_to_carer_benefit: true + benunits: + benunit: + members: [claimant] + households: + household: + members: [claimant] + output: + pension_credit_earnings_disregard: 20 * 52 diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_income.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_income.yaml index b6cf5c949..b33aeac54 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_income.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_income.yaml @@ -20,7 +20,11 @@ savings: 11_000 output: pension_credit_deemed_income: 104 - pension_credit_income: 343 + # 1 + 2 + 4 + 8 + 32 + 64 + 128 + 104 = 343, less the Sch VI disregard: + # the 20 pound para 4(1)(a)(vii) amount (contributory ESA), capped at the + # 129 of net earnings (no tax or NI on them). + pension_credit_earnings_disregard: 129 + pension_credit_income: 214 - name: Interest and dividends are not counted directly in Pension Credit income. period: 2021 diff --git a/policyengine_uk/tests/test_pension_credit_earnings_disregard_properties.py b/policyengine_uk/tests/test_pension_credit_earnings_disregard_properties.py new file mode 100644 index 000000000..c60d3de0f --- /dev/null +++ b/policyengine_uk/tests/test_pension_credit_earnings_disregard_properties.py @@ -0,0 +1,211 @@ +"""Properties of the Pension Credit earnings disregards (SPC Regs 2002 Sch VI). + +Invariants, over generated benefit units in England and Scotland: + +1. Statute: the disregard equals min(net earnings, 52 x w). Net earnings are + the claimant's and partner's gross earnings less earnings NI, half of + pension contributions and income tax on the earnings. The tax on a + person's earnings is measured independently, as the fall in their income + tax when the simulation is rerun without their earnings (the earnings as + the top slice, on their own Scottish or rest-of-UK schedule). w is 20 if + the unit is a lone-parent family, or a claimant or partner is entitled to + carer's allowance (an input here), receives a listed + disability benefit or is blind; otherwise 5 single, 10 couple. A dependent + child's DLA or caring never qualifies. +2. Bounds: 0 <= disregard <= min(gross earnings, 20 x 52). +3. Differential: Pension Credit income is the pre-change income (sources less + tax, NI and half of pension contributions, floored at 0) less the + disregard, floored at 0. +4. Monotonicity: the guarantee credit is never below its value without the + disregard. +5. Earning more never raises Pension Credit entitlement (reg 17(9) applies the + disregard to net earnings). +6. The dated benefit lists follow the amending instruments: ESA from 27 + October 2008, PIP and AFIP from 8 April 2013. +""" + +import numpy as np +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_uk import Simulation +from policyengine_uk.model_api import WEEKS_IN_YEAR + +YEAR = 2024 +SETTINGS = settings( + max_examples=25, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) +DISABILITY = [ + "attendance_allowance", + "dla_sc", + "pip_dl", + "incapacity_benefit", + "esa_contrib", +] + + +@st.composite +def units(draw): + country = draw(st.sampled_from(["ENGLAND", "SCOTLAND"])) + couple = draw(st.booleans()) + child = draw(st.booleans()) + people = {} + names = ["claimant"] + (["partner"] if couple else []) + for n in names: + person = { + "age": draw(st.sampled_from([67, 72, 85])), + "employment_income": draw(st.sampled_from([0, 50, 400, 1_040, 3_000])), + "self_employment_income": draw(st.sampled_from([0, 0, 1_500])), + "state_pension": draw(st.integers(min_value=0, max_value=12_000)), + "private_pension_income": draw(st.sampled_from([0, 2_000, 6_000])), + "is_blind": draw(st.sampled_from([False, False, False, True])), + "is_entitled_to_carer_benefit": draw( + st.sampled_from([False, False, False, True]) + ), + "care_hours": draw(st.sampled_from([0, 0, 40])), + "personal_pension_contributions": draw(st.sampled_from([0, 0, 300])), + } + benefit = draw(st.sampled_from([None, None] + DISABILITY)) + if benefit: + person[benefit] = 2_000 + people[n] = person + if child: + # A dependent child's DLA or caring never qualifies the unit. + people["child"] = { + "age": 10, + "dla_sc": draw(st.sampled_from([0, 2_000])), + "is_entitled_to_carer_benefit": draw(st.booleans()), + } + return {"people": people, "country": country} + + +def simulate(case): + people = case["people"] + members = list(people) + dated = { + name: {k: {str(YEAR): v} for k, v in person.items()} + for name, person in people.items() + } + return Simulation( + situation={ + "people": dated, + "benunits": {"b": {"members": members}}, + "households": { + "h": {"members": members, "country": {str(YEAR): case["country"]}} + }, + } + ) + + +def without_earnings(case, name): + people = {n: dict(p) for n, p in case["people"].items()} + people[name]["employment_income"] = 0 + people[name]["self_employment_income"] = 0 + return {"people": people, "country": case["country"]} + + +def unit_value(sim, variable): + return float(sim.calculate(variable, YEAR)[0]) + + +def person_values(sim, variable): + return np.asarray(sim.calculate(variable, YEAR, map_to="person"), dtype=float) + + +@SETTINGS +@given(units()) +def test_statute_bounds_differential_and_monotonicity(case): + people = case["people"] + sim = simulate(case) + names = list(people) + adults = [n != "child" for n in names] + gross = np.array( + [ + people[n]["employment_income"] + people[n].get("self_employment_income", 0) + if n != "child" + else 0 + for n in names + ], + dtype=float, + ) + ni = sum( + person_values(sim, v) + for v in ["ni_class_1_employee", "ni_class_2", "ni_class_4"] + ) + income_tax = person_values(sim, "income_tax") + tax_on_earnings = np.zeros(len(names)) + for i, name in enumerate(names): + if gross[i] > 0: + rerun = person_values(simulate(without_earnings(case, name)), "income_tax") + tax_on_earnings[i] = max(0.0, income_tax[i] - rerun[i]) + contributions = 0.5 * person_values(sim, "pension_contributions") + net = np.maximum(0, gross - ni - tax_on_earnings - contributions) + net_earnings = float(net[adults].sum()) + + adult_people = [people[n] for n in names if n != "child"] + couple = len(adult_people) == 2 + disabled = any( + p.get("is_blind") or any(p.get(b, 0) > 0 for b in DISABILITY) + for p in adult_people + ) + carer = any(p.get("is_entitled_to_carer_benefit") for p in adult_people) + lone_parent = "child" in people and not couple + weekly = 20 if (disabled or carer or lone_parent) else (10 if couple else 5) + expected = min(net_earnings, weekly * WEEKS_IN_YEAR) + disregard = unit_value(sim, "pension_credit_earnings_disregard") + assert np.isclose(disregard, expected, atol=0.01) + assert 0 <= disregard <= min(gross.sum(), 20 * WEEKS_IN_YEAR) + 0.01 + + sources = sim.tax_benefit_system.parameters( + f"{YEAR}-06-01" + ).gov.dwp.pension_credit.guarantee_credit.income + total = sum(float(sim.calculate(s, YEAR, map_to="benunit")[0]) for s in sources) + deductions = ( + float(sim.calculate("income_tax", YEAR, map_to="benunit")[0]) + + float(sim.calculate("national_insurance", YEAR, map_to="benunit")[0]) + + 0.5 * float(sim.calculate("pension_contributions", YEAR, map_to="benunit")[0]) + ) + before = max(0.0, total - deductions) + assert np.isclose( + unit_value(sim, "pension_credit_income"), + max(0.0, before - disregard), + atol=0.01, + ) + gc_without = max(0.0, unit_value(sim, "minimum_guarantee") - before) + assert unit_value(sim, "guarantee_credit") >= gc_without - 0.01 + + +@SETTINGS +@given(units(), st.sampled_from([1, 50, 260, 1_040, 5_000])) +def test_earning_more_never_raises_pension_credit(case, extra): + more = {name: dict(person) for name, person in case["people"].items()} + more["claimant"]["employment_income"] += extra + before = unit_value(simulate(case), "pension_credit_entitlement") + after = unit_value( + simulate({"people": more, "country": case["country"]}), + "pension_credit_entitlement", + ) + assert after <= before + 0.01 + + +def test_benefit_lists_follow_amending_instruments(): + from policyengine_uk.system import system + + def lists(date): + p = system.parameters(date).gov.dwp.pension_credit.earnings_disregard.higher + return set(p.disability_benefits), set(p.disability_benefit_unit_benefits) + + person, unit = lists("2008-10-26") + assert "esa_contrib" not in person and "esa_income" not in unit + person, unit = lists("2008-10-27") + assert "esa_contrib" in person and "esa_income" in unit + person, _ = lists("2013-04-07") + assert "pip" not in person and "armed_forces_independence_payment" not in person + person, _ = lists("2013-04-08") + assert {"pip", "armed_forces_independence_payment"} <= person + for date in ["2008-10-26", "2013-04-08", "2026-04-06"]: + person, _ = lists(date) + assert {"incapacity_benefit", "sda", "attendance_allowance", "dla"} <= person diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_earnings_disregard.py b/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_earnings_disregard.py new file mode 100644 index 000000000..2e39753ac --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_earnings_disregard.py @@ -0,0 +1,97 @@ +from policyengine_uk.model_api import * + + +class pension_credit_earnings_disregard(Variable): + label = "Pension Credit earnings disregard" + documentation = ( + "Earnings disregarded from Pension Credit income under Schedule VI to " + "the State Pension Credit Regulations 2002: 20 pounds a week for a " + "lone parent (para. 1), where the claimant or partner is a carer " + "satisfying Sch. I para. 4 (para. 3), or where the claimant or partner " + "receives a listed disability benefit or is certified blind " + "(para. 4(1)); otherwise 5 pounds a week for a single claimant and 10 " + "pounds for a couple (para. 5). 20 pounds is the most disregarded " + "however many conditions are met (para. 4A). Reg. 17(9) disregards the " + "sums 'in calculating the claimant's earnings', which are net of income " + "tax and National Insurance (reg. 17(10)) and of half of pension " + "contributions (reg. 17A(4A)), so the disregard never exceeds the " + "claimant's and partner's net earnings. Income tax on earnings is the " + "tax on them as the top slice of the person's taxable non-savings " + "income, on the person's own rate schedule (Scottish or rest of UK), " + "capped at their income tax: the tax deducted from the earnings where " + "the personal allowance goes against pension income first (DMG " + "86038-86039), so earning more never raises Pension Credit. Not " + "modelled: the employment-specific 20 pound " + "disregards of paras. 2 to 2B (part-time firefighters, auxiliary " + "coastguards, lifeboat crew, reserve forces) and the transitional " + "protections of para. 4(2) to (4)." + ) + entity = BenUnit + definition_period = YEAR + value_type = float + unit = GBP + reference = ( + "https://www.legislation.gov.uk/uksi/2002/1792/schedule/VI", + "https://www.legislation.gov.uk/uksi/2002/1792/regulation/17", + "https://www.legislation.gov.uk/uksi/2002/1792/regulation/17A", + ) + + def formula(benunit, period, parameters): + pc = parameters(period).gov.dwp.pension_credit + p = pc.earnings_disregard + person = benunit.members + claimant_or_partner = person("is_claimant_or_partner", period) + + on_disability_benefit = ( + add(person, period, p.higher.disability_benefits) > 0 + ) | person("is_blind", period) + unit_disability_benefits = p.higher.disability_benefit_unit_benefits + unit_on_disability_benefit = ( + add(benunit, period, unit_disability_benefits) > 0 + if len(unit_disability_benefits) > 0 + else False + ) + disabled = ( + benunit.any(claimant_or_partner & on_disability_benefit) + | unit_on_disability_benefit + ) + # Sch. I para. 4: a claimant or partner entitled to carer's allowance + # (the carer addition's own test), not caring hours alone. + carer = benunit.any( + claimant_or_partner & person("is_entitled_to_carer_benefit", period) + ) + lone_parent = benunit("is_lone_parent", period) + relation_type = benunit("relation_type", period) + weekly = where( + lone_parent | carer | disabled, + p.higher.amount, + p.standard[relation_type], + ) + + # Net earnings of the claimant and partner (regs. 17(10), 17A(4A)). + gross = max_(0, add(person, period, pc.guarantee_credit.earnings_sources)) + national_insurance = add( + person, period, ["ni_class_1_employee", "ni_class_2", "ni_class_4"] + ) + # Tax on the earnings as the top slice of taxable non-savings income. + rates = parameters(period).gov.hmrc.income_tax.rates + taxable = person("earned_taxable_income", period) + below_earnings = max_(0, taxable - min_(gross, taxable)) + scottish = person("pays_scottish_income_tax", period) + top_slice_tax = where( + scottish, + rates.scotland.rates.calc(taxable) + - rates.scotland.rates.calc(below_earnings), + rates.uk.calc(taxable) - rates.uk.calc(below_earnings), + ) + income_tax_on_earnings = min_(person("income_tax", period), top_slice_tax) + pension_contributions = ( + person("pension_contributions", period) + * pc.income.pension_contributions_deduction + ) + net = max_( + 0, + gross - national_insurance - income_tax_on_earnings - pension_contributions, + ) + net_earnings = benunit.sum(net * claimant_or_partner) + return min_(weekly * WEEKS_IN_YEAR, net_earnings) diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_income.py b/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_income.py index 1160800f3..7a9ec4419 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_income.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_income.py @@ -46,4 +46,6 @@ def formula(benunit, period, parameters): ) pen_con_deduction_rate = pc.income.pension_contributions_deduction deductions = tax + pension_contributions * pen_con_deduction_rate - return max_(0, total - deductions) + # Schedule VI earnings disregards (reg. 17(9)). + earnings_disregard = benunit("pension_credit_earnings_disregard", period) + return max_(0, total - deductions - earnings_disregard)