diff --git a/changelog.d/pc-child-amount-tax-credit-award.fixed.md b/changelog.d/pc-child-amount-tax-credit-award.fixed.md new file mode 100644 index 0000000000..445c489458 --- /dev/null +++ b/changelog.d/pc-child-amount-tax-credit-award.fixed.md @@ -0,0 +1,2 @@ +- Pay no Pension Credit child amount (SPC Regs 2002 Schedule IIA) to a family awarded child tax credit or working tax credit, including an award at a nil rate (reg 6(6)(d) and (11); TCA 2002 s.14(3)). The new variable `has_tax_credit_award` records the award. +- Pay no Schedule IIA amount before it began on 1 February 2019 (SI 2018/676 reg 2). The new parameter `gov.dwp.pension_credit.guarantee_credit.child.in_effect` dates it. diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/child/in_effect.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/child/in_effect.yaml new file mode 100644 index 0000000000..f8cca78047 --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/child/in_effect.yaml @@ -0,0 +1,15 @@ +description: Whether the Pension Credit minimum guarantee includes the Schedule IIA additional amount for a child or qualifying young person. +values: + 2003-10-06: false + # SI 2018/676 reg 2(2)(c) and (4) added reg 6(6)(d) and Schedule IIA from + # 1 February 2019. Before then, support for a pensioner's child came through + # Child Tax Credit. + 2019-02-01: true +metadata: + unit: bool + label: Pension Credit child amount in effect + reference: + - title: The State Pension Credit Regulations 2002 reg. 6(6)(d) + href: https://www.legislation.gov.uk/uksi/2002/1792/regulation/6 + - title: The State Pension Credit (Additional Amount for Child or Qualifying Young Person) (Amendment) Regulations 2018 reg. 2 + href: https://www.legislation.gov.uk/uksi/2018/676/regulation/2 diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/guarantee_credit/child_amount_tax_credit_award.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/guarantee_credit/child_amount_tax_credit_award.yaml new file mode 100644 index 0000000000..5c1ecc1457 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/guarantee_credit/child_amount_tax_credit_award.yaml @@ -0,0 +1,329 @@ +# No Schedule IIA child amount for a tax credit award. +# +# SPC Regs 2002 reg 6(6)(d) adds Schedule IIA's amount for a child or +# qualifying young person "except where paragraph (11) applies". Reg 6(11): +# "This paragraph applies in the case of a person who is awarded, or who is +# treated as having an award of, a tax credit under the Tax Credits Act." Reg +# 6(17): "a tax credit" includes a child tax credit and a working tax credit. +# Reg 6(6)(d), (11)-(17) and Schedule IIA came into force on 1 February 2019 +# (SI 2018/676 reg 2); the model takes a year's rules at the start of the +# fiscal year, so they apply from 2019-20. +# +# An award need not be positive: HMRC may award a tax credit at a nil rate +# (TCA 2002 s.14(3)). The model treats a family as awarded a tax credit when +# it claims one and meets its conditions other than the income test. Tax +# credits ended on 5 April 2025. +# +# Rates (DWP, Benefit and pension rates): +# - 2024-25: standard minimum guarantee £332.95 a week for a couple; Schedule +# IIA £76.79 for the eldest child born before 6 April 2017 (para 10). +# - 2025-26: £346.60 couple; £78.10 eldest child born before 6 April 2017. +# - 2019-20: £255.25 couple; £63.84 eldest child. 2018-19: £248.80 couple. +# - WTC 2024-25: basic element £2,435, couple element £2,500; threshold +# £7,955; withdrawal rate 41%. CTC child element £3,455; family element £545 +# (entered: the model CPI-uprates it past its frozen £545). +# WEEKS_IN_YEAR is 52. +# +# Each couple is aged 70, so both reached pensionable age after 6 April 2016 +# and there is no savings credit (SPCA 2002 s.3(1)(a)). The grandchild is 10, +# born before 6 April 2017. Pension Credit earnings are entered net of the SPC +# Regs Sch VI para 5 disregard (£10 a week for a couple), which the model does +# not apply. £10,000 of savings gives no Pension Credit tariff income, and +# £300 of interest uses up the £300 step-one disregard of tax credit income +# (SI 2002/2006 reg 3). No one pays income tax or National Insurance. + +- name: A Pension Credit couple awarded CTC and WTC gets no child amount + # Tax credit income: State Pension 8,000 + interest (300 - 300) + earnings + # 2,600 = £10,600. The older partner is over 60 and works 20 hours, which + # meets the WTC hours condition (WTC Regs 2002 reg 4(1), second condition). + # The family claims both credits, so it is awarded a tax credit and reg + # 6(11) removes the Schedule IIA amount. Minimum guarantee: 332.95 x 52 = + # £17,313.40. + # With the income test lifted (SI 2002/2008 reg 4(1)(d)): WTC 2,435 + 2,500 + # = £4,935, CTC 545 + 3,455 = £4,000. Pension Credit income: 8,000 + 2,080 + # + 4,935 = £15,015 (CTC is not Pension Credit income), so Guarantee Credit + # is 17,313.40 - 15,015 = £2,298.40 and the passport holds. + # (Paying the child amount as well would give 2,298.40 + 76.79 x 52 = + # £6,291.48.) + period: 2024 + absolute_error_margin: 0.01 + input: + people: + grandparent_1: + age: 70 + is_claimant_or_partner: true + employment_income: 2_600 + weekly_hours: 20 + state_pension: 4_000 + savings_interest_income: 300 + child_tax_credit_reported: 1 + working_tax_credit_reported: 1 + grandparent_2: + age: 70 + is_claimant_or_partner: true + state_pension: 4_000 + grandchild: + age: 10 + is_claimant_or_partner: false + benunits: + benunit: + members: [grandparent_1, grandparent_2, grandchild] + would_claim_uc: false + pension_credit_earnings: 2_080 # 2,600 - 10 x 52 + CTC_family_element: 545 + households: + household: + members: [grandparent_1, grandparent_2, grandchild] + savings: 10_000 + output: + has_tax_credit_award: true + child_minimum_guarantee_addition: 0 + minimum_guarantee: 17_313.40 + tax_credits_applicable_income: 0 + working_tax_credit: 4_935 + child_tax_credit: 4_000 + guarantee_credit: 2_298.40 + pension_credit: 2_298.40 + +- name: The same couple with no tax credit claim gets the child amount + # Schedule IIA para 10: 76.79 x 52 = £3,993.08. Minimum guarantee: + # 17,313.40 + 3,993.08 = £21,306.48. Pension Credit income: 8,000 + 2,080 = + # £10,080, so Guarantee Credit is £11,226.48. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + grandparent_1: + age: 70 + is_claimant_or_partner: true + employment_income: 2_600 + weekly_hours: 20 + state_pension: 4_000 + savings_interest_income: 300 + grandparent_2: + age: 70 + is_claimant_or_partner: true + state_pension: 4_000 + grandchild: + age: 10 + is_claimant_or_partner: false + benunits: + benunit: + members: [grandparent_1, grandparent_2, grandchild] + would_claim_uc: false + pension_credit_earnings: 2_080 + households: + household: + members: [grandparent_1, grandparent_2, grandchild] + savings: 10_000 + output: + has_tax_credit_award: false + child_minimum_guarantee_addition: 3_993.08 + minimum_guarantee: 21_306.48 + working_tax_credit: 0 + child_tax_credit: 0 + guarantee_credit: 11_226.48 + pension_credit: 11_226.48 + +- name: A WTC award alone also removes the child amount + # Reg 6(17): "a tax credit" includes a working tax credit. The first case's + # couple claiming WTC but not CTC: no Schedule IIA amount; the passported + # WTC of £4,935 leaves Guarantee Credit of £2,298.40, as before. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + grandparent_1: + age: 70 + is_claimant_or_partner: true + employment_income: 2_600 + weekly_hours: 20 + state_pension: 4_000 + savings_interest_income: 300 + working_tax_credit_reported: 1 + grandparent_2: + age: 70 + is_claimant_or_partner: true + state_pension: 4_000 + grandchild: + age: 10 + is_claimant_or_partner: false + benunits: + benunit: + members: [grandparent_1, grandparent_2, grandchild] + would_claim_uc: false + pension_credit_earnings: 2_080 + households: + household: + members: [grandparent_1, grandparent_2, grandchild] + savings: 10_000 + output: + has_tax_credit_award: true + child_minimum_guarantee_addition: 0 + tax_credits_applicable_income: 0 + working_tax_credit: 4_935 + child_tax_credit: 0 + pension_credit: 2_298.40 + +- name: An award at a nil rate is still an award + # Tax credit income: 9,000 + 8,000 + (300 - 300) + 3,500 = £20,500. WTC on + # the income test: 4,935 - 0.41 x (20,500 - 7,955) < 0, so nil. + # Pension Credit income: 17,000 + (3,500 - 520) = £19,980, above the + # £17,313.40 guarantee, so no Pension Credit, and with the passported WTC + # (£4,935) still none: the income test applies. + # The family has claimed WTC and meets its conditions, so it holds an award + # at a nil rate (TCA 2002 s.14(3)) and gets no Schedule IIA amount. Had the + # award followed a positive amount, the child amount would give Guarantee + # Credit of 21,306.48 - 19,980 = £1,326.48 with the income test still + # applied, though that Pension Credit would lift it. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + grandparent_1: + age: 70 + is_claimant_or_partner: true + employment_income: 3_500 + weekly_hours: 20 + state_pension: 9_000 + savings_interest_income: 300 + working_tax_credit_reported: 1 + grandparent_2: + age: 70 + is_claimant_or_partner: true + state_pension: 8_000 + grandchild: + age: 10 + is_claimant_or_partner: false + benunits: + benunit: + members: [grandparent_1, grandparent_2, grandchild] + would_claim_uc: false + pension_credit_earnings: 2_980 # 3,500 - 10 x 52 + households: + household: + members: [grandparent_1, grandparent_2, grandchild] + savings: 10_000 + output: + has_tax_credit_award: true + tax_credits_applicable_income: 20_500 + working_tax_credit: 0 + child_minimum_guarantee_addition: 0 + pension_credit: 0 + +- name: With tax credits ended, a reported award no longer removes the child amount + # Tax credits ended on 5 April 2025, so there is no award in 2025-26. + # Schedule IIA: 78.10 x 52 = £4,061.20. Minimum guarantee: 346.60 x 52 + + # 4,061.20 = 18,023.20 + 4,061.20 = £22,084.40. Guarantee Credit: + # 22,084.40 - 10,080 = £12,004.40. The standard minimum guarantee is entered + # at its statutory amount: the model projects 2025-26 by CPI (#1925). + period: 2025 + absolute_error_margin: 0.01 + input: + people: + grandparent_1: + age: 71 + is_claimant_or_partner: true + employment_income: 2_600 + weekly_hours: 20 + state_pension: 4_000 + savings_interest_income: 300 + child_tax_credit_reported: 1 + working_tax_credit_reported: 1 + grandparent_2: + age: 71 + is_claimant_or_partner: true + state_pension: 4_000 + grandchild: + age: 11 + is_claimant_or_partner: false + benunits: + benunit: + members: [grandparent_1, grandparent_2, grandchild] + would_claim_uc: false + pension_credit_earnings: 2_080 + standard_minimum_guarantee: 18_023.20 # 346.60 x 52 + households: + household: + members: [grandparent_1, grandparent_2, grandchild] + savings: 10_000 + output: + has_tax_credit_award: false + working_tax_credit: 0 + child_tax_credit: 0 + child_minimum_guarantee_addition: 4_061.20 + minimum_guarantee: 22_084.40 + guarantee_credit: 12_004.40 + +- name: In 2019-20 the child amount applies, except with a tax credit award + # Schedule IIA from 1 February 2019. 2019-20: 63.84 x 52 = £3,319.68; + # couple guarantee 255.25 x 52 = £13,273. The first couple has a CTC award, + # the second none. + period: 2019 + absolute_error_margin: 0.01 + input: + people: + awarded_1: + age: 70 + is_claimant_or_partner: true + child_tax_credit_reported: 1 + awarded_2: + age: 70 + is_claimant_or_partner: true + awarded_grandchild: + age: 10 + is_claimant_or_partner: false + not_awarded_1: + age: 70 + is_claimant_or_partner: true + not_awarded_2: + age: 70 + is_claimant_or_partner: true + not_awarded_grandchild: + age: 10 + is_claimant_or_partner: false + benunits: + awarded: + members: [awarded_1, awarded_2, awarded_grandchild] + would_claim_uc: false + not_awarded: + members: [not_awarded_1, not_awarded_2, not_awarded_grandchild] + would_claim_uc: false + households: + awarded: + members: [awarded_1, awarded_2, awarded_grandchild] + not_awarded: + members: [not_awarded_1, not_awarded_2, not_awarded_grandchild] + output: + has_tax_credit_award: [true, false] + child_minimum_guarantee_addition: [0, 3_319.68] + minimum_guarantee: [13_273, 16_592.68] + +- name: Before February 2019 there was no Schedule IIA amount + # 2018-19 starts on 6 April 2018, before SI 2018/676 added Schedule IIA. + # The couple guarantee is 248.80 x 52 = £12,937.60, with nothing for the + # grandchild, whom Child Tax Credit supported instead. + period: 2018 + absolute_error_margin: 0.01 + input: + people: + grandparent_1: + age: 70 + is_claimant_or_partner: true + grandparent_2: + age: 70 + is_claimant_or_partner: true + grandchild: + age: 10 + is_claimant_or_partner: false + benunits: + benunit: + members: [grandparent_1, grandparent_2, grandchild] + would_claim_uc: false + households: + household: + members: [grandparent_1, grandparent_2, grandchild] + output: + has_tax_credit_award: false + child_minimum_guarantee_addition: 0 + minimum_guarantee: 12_937.60 diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/tax_credits_pension_credit_passport.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/tax_credits_pension_credit_passport.yaml index d013059700..04a44902ad 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/tax_credits_pension_credit_passport.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/tax_credits_pension_credit_passport.yaml @@ -204,8 +204,8 @@ # = £866.64, so £123.34. # CTC: £545 + £3,455 = £4,000, not 4,000 - 0.41 x 205 = £3,915.95. # SPC Regs 2002 reg 6(6)(d) and (11) give no Schedule IIA child amount to - # a person awarded a tax credit, and the CTC family element has been £545 - # since 2011-12; both are entered because the model applies neither. + # a person awarded a tax credit. The CTC family element has been £545 since + # 2011-12; it is entered because the model CPI-uprates it. period: 2024 absolute_error_margin: 0.01 input: @@ -229,7 +229,6 @@ members: [grandparent_1, grandparent_2, grandchild] would_claim_uc: false pension_credit_earnings: 2_480 # 3,000 - 10 x 52 - child_minimum_guarantee_addition: 0 CTC_family_element: 545 households: household: @@ -276,7 +275,6 @@ members: [grandparent_1, grandparent_2, grandchild] would_claim_uc: false pension_credit_earnings: 2_480 - child_minimum_guarantee_addition: 0 CTC_family_element: 0 working_tax_credit_run_on: false extended_childcare_entitlement_eligible: false diff --git a/policyengine_uk/tests/test_pension_credit_child_amount_tax_credit_properties.py b/policyengine_uk/tests/test_pension_credit_child_amount_tax_credit_properties.py new file mode 100644 index 0000000000..b8b9962858 --- /dev/null +++ b/policyengine_uk/tests/test_pension_credit_child_amount_tax_credit_properties.py @@ -0,0 +1,301 @@ +"""No Pension Credit child amount for a tax credit award. + +SPC Regs 2002 reg 6(6)(d) adds the Schedule IIA amount for each child or +qualifying young person "except where paragraph (11) applies": where the +person "is awarded, or ... is treated as having an award of, a tax credit" +(reg 6(11)), child tax credit or working tax credit (reg 6(17)). Reg 6(6)(d) +and Schedule IIA apply from 1 February 2019 (SI 2018/676), so from 2019-20 in +the model. Tax credits ended on 5 April 2025. HMRC may award a tax credit at a +nil rate (TCA 2002 s.14(3)), so the award follows the claim and the +entitlement conditions other than the income test. + +Properties, for any family: + +1. The award is a claim plus the conditions of entitlement, recomputed + independently, in every year with tax credits (2019-20 to 2024-25). +2. Differential: the child amount is nil where there is an award, and + otherwise equals the amount in a simulation with the award entered as + absent. That amount equals an independent Schedule IIA calculation from + the parameters (para 9(1)(a) and para 10). +3. After tax credits ended (2025-26 on), no family has an award, and the + child amount is the Schedule IIA amount. +4. Before 2019-20 the child amount is nil. +5. Removing the child amount never raises Pension Credit plus tax credits, + and changes nothing for a family with no award. +6. The results do not depend on the order in which the child amount, the + award, Pension Credit, the tax credit income test and household income + are requested, and no request raises a dependency cycle. +""" + +import numpy as np +from hypothesis import HealthCheck, example, given, settings +from hypothesis import strategies as st + +from policyengine_uk import Simulation + +TAX_CREDIT_YEARS = [2019, 2021, 2024] +NO_AWARD_YEARS = [2025, 2026] +BEFORE_SCHEDULE_IIA_YEARS = [2015, 2018] +SUPPORT = ["pension_credit", "working_tax_credit", "child_tax_credit"] +OUTPUTS = [ + "child_minimum_guarantee_addition", + "has_tax_credit_award", + "tax_credits_applicable_income", + "pension_credit", + "working_tax_credit", + "child_tax_credit", +] + + +@st.composite +def adults(draw, partner): + age = draw(st.integers(40 if partner else 60, 90)) + earnings = draw(st.sampled_from([0, 0, 2_600, 6_000, 12_000])) + return { + "age": age, + "employment_income": earnings, + "weekly_hours": draw(st.sampled_from([16, 20, 30])) if earnings else 0, + "state_pension": ( + draw(st.sampled_from([0, 4_000, 6_000, 9_000, 11_500])) if age >= 66 else 0 + ), + "private_pension_income": draw(st.sampled_from([0, 0, 1_500, 5_000])), + "savings_interest_income": draw(st.sampled_from([0, 0, 300, 500])), + "working_tax_credit_reported": draw(st.sampled_from([0, 1])), + "child_tax_credit_reported": draw(st.sampled_from([0, 1, 1])), + } + + +@st.composite +def families(draw): + members = [draw(adults(partner=False))] + if draw(st.booleans()): + members.append(draw(adults(partner=True))) + children = [ + {"age": draw(st.integers(0, 15))} for _ in range(draw(st.integers(0, 3))) + ] + benunit = { + "would_claim_pc": draw(st.sampled_from([True, True, True, False])), + # A Universal Credit claim leaves a reported CTC award ineligible. + "would_claim_uc": draw(st.sampled_from([False, False, False, True])), + } + household = {"savings": draw(st.sampled_from([0, 5_000, 12_000, 20_000]))} + return members, children, benunit, household + + +def situation(families, year, benunit_inputs=None): + people, benunits, households = {}, {}, {} + for i, (members, children, benunit, household) in enumerate(families): + names = [] + for j, inputs in enumerate(members): + name = f"a{i}_{j}" + people[name] = {k: {year: v} for k, v in inputs.items()} + people[name]["is_claimant_or_partner"] = {year: True} + names.append(name) + for j, inputs in enumerate(children): + name = f"c{i}_{j}" + people[name] = {k: {year: v} for k, v in inputs.items()} + people[name]["is_claimant_or_partner"] = {year: False} + names.append(name) + benunits[f"b{i}"] = { + "members": names, + **{k: {year: v} for k, v in benunit.items()}, + **{k: {year: v} for k, v in (benunit_inputs or {}).items()}, + } + households[f"h{i}"] = { + "members": names, + **{k: {year: v} for k, v in household.items()}, + } + return {"people": people, "benunits": benunits, "households": households} + + +def calculate(drawn, year, order=OUTPUTS, benunit_inputs=None): + sim = Simulation(situation=situation(drawn, year, benunit_inputs)) + return {variable: sim.calculate(variable, year) for variable in order} + + +def schedule_iia_amount(drawn, year): + """Schedule IIA amounts from the parameters, for children who are not + disabled: para 9(1)(a) for each child, and para 10's higher amount for + the eldest if born before 6 April 2017 (by birth year, as the model).""" + from policyengine_uk import CountryTaxBenefitSystem + + child = ( + CountryTaxBenefitSystem() + .parameters(year) + .gov.dwp.pension_credit.guarantee_credit.child + ) + amounts = [] + for _, children, _, _ in drawn: + ages = [c["age"] for c in children] + if not ages: + amounts.append(0) + continue + eldest_first = year - max(ages) < 2017 + weekly = len(ages) * child.addition + if eldest_first: + weekly += child.first.addition - child.addition + amounts.append(weekly * 52) + return np.array(amounts) + + +SETTINGS = settings( + max_examples=20, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) +FAMILIES = st.lists(families(), min_size=1, max_size=6) + +# The YAML households (child_amount_tax_credit_award.yaml), run on every +# invocation. Pension Credit earnings are net of SPC Regs Sch VI para 5, and +# the CTC family element is entered at its statutory £545. +_GRANDPARENT = { + "age": 70, + "employment_income": 2_600, + "weekly_hours": 20, + "state_pension": 4_000, + "savings_interest_income": 300, +} +_INPUTS = {"would_claim_uc": False, "pension_credit_earnings": 2_080} +YAML_FAMILIES = [ + # CTC and WTC with Pension Credit: passported, no child amount. + ( + [ + { + **_GRANDPARENT, + "child_tax_credit_reported": 1, + "working_tax_credit_reported": 1, + }, + {"age": 70, "state_pension": 4_000}, + ], + [{"age": 10}], + {**_INPUTS, "CTC_family_element": 545}, + {"savings": 10_000}, + ), + # No tax credit claim: the child amount. + ( + [_GRANDPARENT, {"age": 70, "state_pension": 4_000}], + [{"age": 10}], + _INPUTS, + {"savings": 10_000}, + ), + # WTC alone. + ( + [ + {**_GRANDPARENT, "working_tax_credit_reported": 1}, + {"age": 70, "state_pension": 4_000}, + ], + [{"age": 10}], + _INPUTS, + {"savings": 10_000}, + ), + # A WTC award at a nil rate. + ( + [ + { + **_GRANDPARENT, + "employment_income": 3_500, + "state_pension": 9_000, + "working_tax_credit_reported": 1, + }, + {"age": 70, "state_pension": 8_000}, + ], + [{"age": 10}], + {**_INPUTS, "pension_credit_earnings": 2_980}, + {"savings": 10_000}, + ), +] + + +@SETTINGS +@given(FAMILIES, st.sampled_from(TAX_CREDIT_YEARS)) +@example(YAML_FAMILIES, 2024) +def test_award_removes_the_child_amount_and_nothing_else(drawn, year): + conditions = [ + "would_claim_CTC", + "is_CTC_eligible", + "would_claim_WTC", + "is_WTC_eligible", + ] + on = calculate(drawn, year, order=OUTPUTS + conditions) + # 1. The award is a claim plus the conditions of entitlement. + expected_award = (on["would_claim_CTC"] & on["is_CTC_eligible"]) | ( + on["would_claim_WTC"] & on["is_WTC_eligible"] + ) + assert (on["has_tax_credit_award"] == expected_award).all(), drawn + # 2. Differential, and the Schedule IIA amount from the parameters. + without = calculate(drawn, year, benunit_inputs={"has_tax_credit_award": False}) + expected = np.where( + on["has_tax_credit_award"], 0, without["child_minimum_guarantee_addition"] + ) + assert np.allclose(on["child_minimum_guarantee_addition"], expected), drawn + assert np.allclose( + without["child_minimum_guarantee_addition"], + schedule_iia_amount(drawn, year), + atol=0.01, + ), drawn + # 5. Removing the child amount never raises Pension Credit plus tax + # credits, and changes nothing without an award. + total_on = sum(on[v] for v in SUPPORT) + total_without = sum(without[v] for v in SUPPORT) + assert (total_on <= total_without + 0.01).all(), drawn + no_award = ~on["has_tax_credit_award"] + for variable in SUPPORT + ["tax_credits_applicable_income"]: + assert np.allclose(on[variable][no_award], without[variable][no_award]), ( + variable, + drawn, + ) + + +@SETTINGS +@given(FAMILIES, st.sampled_from(NO_AWARD_YEARS)) +def test_no_award_after_tax_credits_ended(drawn, year): + on = calculate(drawn, year) + assert not on["has_tax_credit_award"].any() + assert np.allclose( + on["child_minimum_guarantee_addition"], + schedule_iia_amount(drawn, year), + atol=0.01, + ), drawn + + +@SETTINGS +@given(FAMILIES, st.sampled_from(BEFORE_SCHEDULE_IIA_YEARS)) +def test_no_child_amount_before_schedule_iia(drawn, year): + on = calculate(drawn, year) + assert (on["child_minimum_guarantee_addition"] == 0).all(), drawn + + +@SETTINGS +@given(FAMILIES, st.sampled_from(TAX_CREDIT_YEARS + NO_AWARD_YEARS)) +@example(YAML_FAMILIES, 2024) +def test_results_do_not_depend_on_request_order(drawn, year): + forward = calculate(drawn, year) + backward = calculate(drawn, year, order=list(reversed(OUTPUTS))) + household_first = calculate(drawn, year, order=["household_net_income"] + OUTPUTS) + for variable in OUTPUTS: + assert np.allclose(forward[variable], backward[variable]), (variable, drawn) + assert np.allclose(forward[variable], household_first[variable]), ( + variable, + drawn, + ) + + +def test_yaml_families_reach_every_case(): + """The pinned examples are not vacuous: they hit each case of the rule.""" + year = 2024 + on = calculate(YAML_FAMILIES, year) + without = calculate( + YAML_FAMILIES, year, benunit_inputs={"has_tax_credit_award": False} + ) + assert on["has_tax_credit_award"].tolist() == [True, False, True, True] + # The rule removes the child amount from each awarded family. + assert (without["child_minimum_guarantee_addition"] > 0).all() + assert np.allclose(on["child_minimum_guarantee_addition"], [0, 3_993.08, 0, 0]) + # Pension Credit, CTC and WTC are all paid to the first family. + for variable in SUPPORT: + assert on[variable][0] > 0, variable + # The nil-rate award: no WTC, no Pension Credit, no child amount. + assert on["working_tax_credit"][3] == 0 + assert on["pension_credit"][3] == 0 + assert without["pension_credit"][3] > 0 diff --git a/policyengine_uk/tests/test_tax_credits_pension_credit_passport_properties.py b/policyengine_uk/tests/test_tax_credits_pension_credit_passport_properties.py index fa6d49c562..34d607b36f 100644 --- a/policyengine_uk/tests/test_tax_credits_pension_credit_passport_properties.py +++ b/policyengine_uk/tests/test_tax_credits_pension_credit_passport_properties.py @@ -142,8 +142,8 @@ def calculate(sim, year, order=OUTPUTS): # The YAML cases, run on every invocation: random draws seldom raise CTC or # hit the third row. Pension Credit earnings are net of SPC Regs Sch VI -# para 5; the CTC family element and the Sch IIA child amount are entered at -# their statutory values (see the YAML file). +# para 5; the CTC family element is entered at its statutory value (see the +# YAML file). _PENSIONER = { "age": 70, "employment_income": 2_600, @@ -181,7 +181,6 @@ def calculate(sim, year, order=OUTPUTS): [{"age": 10}], { "pension_credit_earnings": 2_480, - "child_minimum_guarantee_addition": 0, "CTC_family_element": 545, }, {"savings": 10_000}, diff --git a/policyengine_uk/variables/gov/dwp/has_tax_credit_award.py b/policyengine_uk/variables/gov/dwp/has_tax_credit_award.py new file mode 100644 index 0000000000..b4bd69d42f --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/has_tax_credit_award.py @@ -0,0 +1,35 @@ +from policyengine_uk.model_api import * + + +class has_tax_credit_award(Variable): + value_type = bool + entity = BenUnit + label = "has a tax credit award" + documentation = ( + "Whether the family is awarded child tax credit or working tax credit " + "for the year, at any rate. Entitlement depends on a claim (TCA 2002 " + "s.3(1)), which a couple makes jointly (s.3(3)(a)), so an award is " + "both members'. On a claim HMRC decide whether to make an award and " + "at what rate (s.14(1)), and may award a tax credit at a nil rate " + "(s.14(3)). So the award follows the claim and the conditions of " + "entitlement other than the income test, not a positive amount. Tax " + "credits ended on 5 April 2025, so there are no awards after that." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/ukpga/2002/21/section/3", + "https://www.legislation.gov.uk/ukpga/2002/21/section/14", + ) + + def formula(benunit, period, parameters): + if not parameters(period).gov.dwp.tax_credits.active: + return benunit.filled_array(False) + # Neither condition reads Pension Credit, which reads this award + # (child_minimum_guarantee_addition), so no cycle arises. + child_tax_credit = benunit("would_claim_CTC", period) & benunit( + "is_CTC_eligible", period + ) + working_tax_credit = benunit("would_claim_WTC", period) & benunit( + "is_WTC_eligible", period + ) + return child_tax_credit | working_tax_credit diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee/additional/child_minimum_guarantee_addition.py b/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee/additional/child_minimum_guarantee_addition.py index 8a6677bece..7bc48ae7ec 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee/additional/child_minimum_guarantee_addition.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee/additional/child_minimum_guarantee_addition.py @@ -7,9 +7,17 @@ class child_minimum_guarantee_addition(Variable): definition_period = YEAR value_type = float unit = GBP - reference = "https://www.legislation.gov.uk/uksi/2002/1792/schedule/IIA" + reference = ( + "https://www.legislation.gov.uk/uksi/2002/1792/regulation/6", + "https://www.legislation.gov.uk/uksi/2002/1792/schedule/IIA", + ) def formula(benunit, period, parameters): + gc = parameters(period).gov.dwp.pension_credit.guarantee_credit + # SPC Regs 2002 reg 6(6)(d) and Schedule IIA apply from 1 February + # 2019 (SI 2018/676 reg 2). + if not gc.child.in_effect: + return benunit.empty_array() person = benunit.members is_child_or_qualifying_young_person = person( "is_child_or_qualifying_young_person_for_pension_credit", period @@ -25,7 +33,6 @@ def formula(benunit, period, parameters): first_child_born_before_2017 = (child_index == 1) & ( person("birth_year", period) < 2017 ) - gc = parameters(period).gov.dwp.pension_credit.guarantee_credit standard_disability_benefits = gc.child.disability.eligibility severe_disability_benefits = gc.child.disability.severe.eligibility is_disabled = add(person, period, standard_disability_benefits) > 0 @@ -52,4 +59,14 @@ def formula(benunit, period, parameters): ) * WEEKS_IN_YEAR ) - return benunit.sum(per_child_amount) + # Reg 6(6)(d) applies Schedule IIA "except where paragraph (11) + # applies", which is "the case of a person who is awarded, or who is + # treated as having an award of, a tax credit" (reg 6(11)): child tax + # credit or working tax credit (reg 6(17)). The tax credit award then + # carries the support for the child. Reg 6(12) and (13) treat an + # award as continuing from the start of a tax year until it is + # renewed or finalised, and reg 6(14) to (16) end the amount when an + # award is made late; on the model's whole-year awards, both affect + # only part of a year, and are not modelled. + has_tax_credit_award = benunit("has_tax_credit_award", period) + return benunit.sum(per_child_amount) * ~has_tax_credit_award