diff --git a/changelog.d/2226.fixed.md b/changelog.d/2226.fixed.md new file mode 100644 index 0000000000..cc439fbe14 --- /dev/null +++ b/changelog.d/2226.fixed.md @@ -0,0 +1 @@ +- Add the 15.05% employer Class 1 rate for 2022-23 (Health and Social Care Levy Act 2021 s.5(2)(b)) and its end on 6 November 2022 (Health and Social Care Levy (Repeal) Act 2022 s.2(1)). Model year 2022 now reads 15.05%, as the employee main rate reads 13.25%. diff --git a/docs/book/policy/model-baseline.md b/docs/book/policy/model-baseline.md index eb0afdde4c..0bbfc62b5a 100644 --- a/docs/book/policy/model-baseline.md +++ b/docs/book/policy/model-baseline.md @@ -14,7 +14,7 @@ Budget 2025 keeps the income tax personal allowance and basic rate limit, and th ### Autumn Budget 2024 -The government increased the [employer National Insurance rate from 13.8% to 15%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employer.yaml#L13-L17) and reduced the [employer secondary threshold from £9,100 to £5,000 annually](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/thresholds/secondary_threshold.yaml#L26-L30), both taking effect in fiscal year 2025-26. +The government increased the [employer National Insurance rate from 13.8% to 15%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employer.yaml#L30-L35) and reduced the [employer secondary threshold from £9,100 to £5,000 annually](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/thresholds/secondary_threshold.yaml#L26-L30), both taking effect in fiscal year 2025-26. ### Universal Credit rebalancing @@ -28,7 +28,7 @@ Annual benefit uprating applied 4.1% increases to state pensions and 1.7% to wor ### Autumn Statement 2023 -The government announced further National Insurance cuts, reducing the [employee main rate from 10% to 8%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml#L22-L27) and the [self-employed Class 4 rate from 9% to 6%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_4/rates/main.yaml#L16-L21) in fiscal year 2024-25. [Class 2 National Insurance contributions were abolished](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_2/flat_rate.yaml#L14-L19) for self-employed people, with the flat rate set to £0 in fiscal year 2024-25. +The government announced further National Insurance cuts, reducing the [employee main rate from 10% to 8%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml#L24-L29) and the [self-employed Class 4 rate from 9% to 6%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_4/rates/main.yaml#L16-L21) in fiscal year 2024-25. [Class 2 National Insurance contributions were abolished](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_2/flat_rate.yaml#L14-L19) for self-employed people, with the flat rate set to £0 in fiscal year 2024-25. ### Capital gains tax changes (Autumn Budget 2024) @@ -40,7 +40,7 @@ The government increased the [child benefit high income tax charge threshold fro ### Autumn Statement 2023 (Employee NI cut) -An initial National Insurance cut reduced the [employee main rate from 12% to 10%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml#L16-L21) in fiscal year 2024-25. +An initial National Insurance cut reduced the [employee main rate from 12% to 10%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml#L18-L23) in fiscal year 2024-25. ## 2023 reforms @@ -56,7 +56,7 @@ The government announced an increase in the [National Insurance primary threshol ### Autumn Budget 2021 (Health and Social Care Levy) -The government temporarily increased [National Insurance rates by 1.25 percentage points](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml#L4-L10) in fiscal year 2022-23, later reversed the same fiscal year. +The Health and Social Care Levy Act 2021 raised the [employee main rate from 12% to 13.25%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml#L4-L17) and the [employer rate from 13.8% to 15.05%](https://github.com/PolicyEngine/policyengine-uk/blob/master/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employer.yaml#L18-L29) for fiscal year 2022-23. The Health and Social Care Levy (Repeal) Act 2022 restored 12% and 13.8% for earnings paid from 6 November 2022. The model reads each fiscal year's rates at 30 April, so 2022-23 carries the levy rates for the whole year ([#1807](https://github.com/PolicyEngine/policyengine-uk/issues/1807)). ### Mini-Budget 2022 (September) diff --git a/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml b/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml index 4a2474d2d7..f7e10bfa97 100644 --- a/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml +++ b/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employee/main.yaml @@ -1,10 +1,12 @@ description: The Class 1 National Insurance main rate is paid on employment earnings between the Primary Threshold and the Upper Earnings Limit. values: 2015-04-01: 0.12 - 2022-04-01: + 2022-04-06: value: 0.1325 metadata: reference: + - title: Health and Social Care Levy Act 2021 s.5(2)(a)(i) + href: https://www.legislation.gov.uk/ukpga/2021/28/section/5/enacted - title: Autumn Budget and Spending Review 2022 href: https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/1043689/Budget_AB2021_Web_Accessible.pdf 2022-11-06: diff --git a/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employer.yaml b/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employer.yaml index b5b8f95aa8..55ca38508c 100644 --- a/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employer.yaml +++ b/policyengine_uk/parameters/gov/hmrc/national_insurance/class_1/rates/employer.yaml @@ -4,14 +4,32 @@ metadata: label: NI employer rate propagate_metadata_to_children: true unit: /1 + # Annual values are the rate at 30 April of each tax year, as for the + # employee main rate (no fiscal_year_blend). For 2022-23 that is the levy + # rate of 15.05%, although earnings paid from 6 November 2022 were charged + # at 13.8%; see #1807 for the choice between sampling and averaging. values: - 2015-04-01: + 2015-04-01: value: 0.138 - reference: - - title: National Insurance rates and thresholds - href: https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/882271/Table-a4.pdf - 2025-01-01: + metadata: + reference: + - title: National Insurance rates and thresholds + href: https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/882271/Table-a4.pdf + 2022-04-06: + value: 0.1505 + metadata: + reference: + - title: Health and Social Care Levy Act 2021 s.5(2)(b) + href: https://www.legislation.gov.uk/ukpga/2021/28/section/5/enacted + 2022-11-06: + value: 0.138 + metadata: + reference: + - title: Health and Social Care Levy (Repeal) Act 2022 s.2(1) + href: https://www.legislation.gov.uk/ukpga/2022/43/section/2/enacted + 2025-01-01: value: 0.15 - reference: - - title: National Insurance Contributions (Secondary Class 1 Contributions) Act 2025(1) - href: https://www.legislation.gov.uk/ukpga/2025/11/section/1 + metadata: + reference: + - title: National Insurance Contributions (Secondary Class 1 Contributions) Act 2025 s.1 + href: https://www.legislation.gov.uk/ukpga/2025/11/section/1 diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_1/ni_class_1_employer.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_1/ni_class_1_employer.yaml index dd9da72b43..f164638623 100644 --- a/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_1/ni_class_1_employer.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_1/ni_class_1_employer.yaml @@ -171,3 +171,49 @@ ni_class_1_income: 8_100 # 52 x £155 = £8,060 would charge £5.52 output: ni_class_1_employer: 0 + +# 2022-23: the Health and Social Care Levy Act 2021 s.5(2)(b) made the +# secondary percentage 15.05%, until the Health and Social Care Levy (Repeal) +# Act 2022 s.2(1) restored 13.8% for earnings paid from 6 November 2022. Model +# year 2022 takes the rate at 30 April, 15.05%, as the employee main rate takes +# 13.25%. The annual secondary threshold is £175 x 52 = £9,100. HMRC, "Rates and +# thresholds for employers 2022 to 2023": 15.05% from 6 April to 5 November +# 2022, 13.8% from 6 November 2022 to 5 April 2023, £9,100 a year. + +- name: Employer NI on £30,000 in 2022-23 is at the 15.05% levy rate + period: 2022 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 30_000 + output: + ni_class_1_employer: 3_145.45 # 0.1505 x (30,000 - 9,100) + ni_employer: 3_145.45 + +- name: Employer NI on £30,000 in 2023-24 is back at 13.8% + period: 2023 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 30_000 + output: + ni_class_1_employer: 2_884.20 # 0.138 x (30,000 - 9,100) + ni_employer: 2_884.20 + +- name: Employer NI on £30,000 in 2021-22 is at 13.8% + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 30_000 + output: + ni_class_1_employer: 2_920.08 # 0.138 x (30,000 - 170 x 52) + +- name: The 2022-23 levy rate applies above the upper earnings limit + period: 2022 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 100_000 + output: + ni_class_1_employer: 13_680.45 # 0.1505 x (100,000 - 9,100) diff --git a/policyengine_uk/tests/test_ni_health_and_social_care_levy.py b/policyengine_uk/tests/test_ni_health_and_social_care_levy.py new file mode 100644 index 0000000000..d0cbd4d53f --- /dev/null +++ b/policyengine_uk/tests/test_ni_health_and_social_care_levy.py @@ -0,0 +1,208 @@ +"""Class 1 rates under the Health and Social Care Levy in 2022-23. + +The Health and Social Care Levy Act 2021 s.5(2) raised two Class 1 +percentages for the tax year 2022-23 by 1.25 points: the main primary +percentage from 12% to 13.25% (s.5(2)(a)(i)) and the secondary percentage +from 13.8% to 15.05% (s.5(2)(b)). The Health and Social Care Levy (Repeal) Act +2022 s.2(1) kept both only for payments of earnings made before 6 November +2022. Para 5(3) of its Schedule gives the annual rates for directors' annual +earnings periods: 12.73% main primary and 14.53% secondary. + +The rate parameters store these as dated values. The model reads each tax +year at 30 April (convert_to_fiscal_year_parameters), so model year 2022 +takes the levy rate on both sides. Whether to average across the year instead +is open in #1807. + +Invariants, checked on the parameter files as stored: + +1. Statutory window: for any date d, the employer rate is 15.05% if and only + if 6 April 2022 <= d < 6 November 2022, and the employee main rate is + 13.25% on exactly the same dates. +2. Same dates: in the 2022-23 tax year the two rates change on the same + dates, 6 April and 6 November 2022. +3. Same uplift: inside the window each rate is 1.25 points above its value on + 5 April 2022. +4. Annual equivalent: the day-weighted average of each rate over 2022-23, + computed exactly, rounds to the Repeal Act's directors' rate. + fiscal_year_average gives the same figure (differential). + +And on the model: + +5. Same convention: neither rate is blended, so in every model year from 2015 + to 2030 each annual rate is the stored rate at 30 April. Model year 2022 is + 15.05% and 13.25%; 2021 and 2023 are 13.8% and 12%. +""" + +import datetime +from fractions import Fraction +from pathlib import Path + +import pytest +from hypothesis import example, given, settings +from hypothesis import strategies as st +from policyengine_core.parameters import load_parameter_file + +import policyengine_uk +from policyengine_uk import CountryTaxBenefitSystem +from policyengine_uk.utils.parameters import fiscal_year_average + +RATES = ( + Path(policyengine_uk.__file__).parent + / "parameters" + / "gov" + / "hmrc" + / "national_insurance" + / "class_1" + / "rates" +) +EMPLOYER_FILE = RATES / "employer.yaml" +EMPLOYEE_MAIN_FILE = RATES / "employee" / "main.yaml" + +LEVY_START = datetime.date(2022, 4, 6) # HSCL Act 2021 s.5(1): tax year 2022-23 +LEVY_END = datetime.date(2022, 11, 6) # Repeal Act 2022 s.2(1) +TAX_YEAR_END = datetime.date(2023, 4, 6) + +EMPLOYER_LEVY_RATE = Fraction("0.1505") # s.5(2)(b) +EMPLOYEE_LEVY_RATE = Fraction("0.1325") # s.5(2)(a)(i) +UPLIFT = Fraction("0.0125") +# Repeal Act 2022 Sch para 5(3), as percentages. +EMPLOYER_DIRECTORS_RATE = Fraction("14.53") +EMPLOYEE_DIRECTORS_RATE = Fraction("12.73") + + +@pytest.fixture(scope="module") +def employer(): + return load_parameter_file(str(EMPLOYER_FILE), "employer") + + +@pytest.fixture(scope="module") +def employee_main(): + return load_parameter_file(str(EMPLOYEE_MAIN_FILE), "main") + + +@pytest.fixture(scope="module") +def system(): + return CountryTaxBenefitSystem() + + +def rate_on(param, date): + """The stored rate in force on a date, as an exact fraction.""" + return Fraction(str(param(date.isoformat()))) + + +def change_dates(param, start, end): + """Dates in [start, end) on which the stored rate takes a new value.""" + dates = [] + for value_at_instant in param.values_list: + date = datetime.date.fromisoformat(value_at_instant.instant_str) + if not start <= date < end: + continue + if rate_on(param, date) != rate_on(param, date - datetime.timedelta(days=1)): + dates.append(date) + return sorted(dates) + + +def exact_annual_percentage(param, start, end): + """Day-weighted average of the stored rate over [start, end), in percent.""" + total = Fraction(0) + day = start + while day < end: + total += rate_on(param, day) + day += datetime.timedelta(days=1) + return 100 * total / (end - start).days + + +# Invariant 1: statutory window. +@settings(max_examples=200, deadline=None, derandomize=True) +@given( + date=st.dates( + min_value=datetime.date(2015, 4, 6), + max_value=datetime.date(2031, 4, 5), + ) +) +@example(date=datetime.date(2022, 4, 1)) +@example(date=datetime.date(2022, 4, 5)) +@example(date=datetime.date(2022, 4, 6)) +@example(date=datetime.date(2022, 4, 30)) +@example(date=datetime.date(2022, 11, 5)) +@example(date=datetime.date(2022, 11, 6)) +@example(date=datetime.date(2023, 4, 5)) +def test_levy_rates_apply_only_in_the_statutory_window(employer, employee_main, date): + in_window = LEVY_START <= date < LEVY_END + assert (rate_on(employer, date) == EMPLOYER_LEVY_RATE) == in_window + assert (rate_on(employee_main, date) == EMPLOYEE_LEVY_RATE) == in_window + + +# Invariant 2: same dates. +def test_employer_and_employee_rates_change_on_the_levy_dates(employer, employee_main): + employer_dates = change_dates(employer, LEVY_START, TAX_YEAR_END) + employee_dates = change_dates(employee_main, LEVY_START, TAX_YEAR_END) + assert employer_dates == employee_dates == [LEVY_START, LEVY_END] + + +# Invariant 3: same uplift. +@pytest.mark.parametrize( + "date", + [LEVY_START, datetime.date(2022, 7, 6), LEVY_END - datetime.timedelta(days=1)], +) +def test_levy_adds_one_and_a_quarter_points_to_both_rates( + employer, employee_main, date +): + day_before = LEVY_START - datetime.timedelta(days=1) + for param in (employer, employee_main): + assert rate_on(param, date) - rate_on(param, day_before) == UPLIFT + + +# Invariant 4: annual equivalent, exact and via fiscal_year_average. +@pytest.mark.parametrize( + "param_name, directors_rate", + [ + ("employer", EMPLOYER_DIRECTORS_RATE), + ("employee_main", EMPLOYEE_DIRECTORS_RATE), + ], +) +def test_annual_average_matches_the_directors_rate(request, param_name, directors_rate): + param = request.getfixturevalue(param_name) + exact = exact_annual_percentage(param, LEVY_START, TAX_YEAR_END) + assert round(exact, 2) == directors_rate + assert 100 * fiscal_year_average(param, 2022) == pytest.approx( + float(exact), abs=1e-9 + ) + + +# Invariant 5: same convention. +def model_rates(system, year): + class_1 = system.get_parameters_at_instant( + str(year) + ).gov.hmrc.national_insurance.class_1 + return class_1.rates.employer, class_1.rates.employee.main + + +def test_neither_rate_is_blended(system): + rates = system.parameters.gov.hmrc.national_insurance.class_1.rates + for param in (rates.employer, rates.employee.main): + assert not (param.metadata or {}).get("fiscal_year_blend", False) + + +@pytest.mark.parametrize("year", range(2015, 2031)) +def test_model_year_rate_is_the_rate_at_30_april(system, employer, employee_main, year): + model_employer, model_employee = model_rates(system, year) + sample = datetime.date(year, 4, 30) + assert Fraction(str(model_employer)) == rate_on(employer, sample) + assert Fraction(str(model_employee)) == rate_on(employee_main, sample) + + +@pytest.mark.parametrize( + "year, employer_rate, employee_rate", + [ + (2021, "0.138", "0.12"), + (2022, "0.1505", "0.1325"), + (2023, "0.138", "0.12"), + ], +) +def test_model_year_2022_carries_the_levy_on_both_sides( + system, year, employer_rate, employee_rate +): + model_employer, model_employee = model_rates(system, year) + assert Fraction(str(model_employer)) == Fraction(employer_rate) + assert Fraction(str(model_employee)) == Fraction(employee_rate) diff --git a/policyengine_uk/tests/test_ni_secondary_threshold.py b/policyengine_uk/tests/test_ni_secondary_threshold.py index 9bedc954e6..91cf33c903 100644 --- a/policyengine_uk/tests/test_ni_secondary_threshold.py +++ b/policyengine_uk/tests/test_ni_secondary_threshold.py @@ -24,12 +24,13 @@ From 2025-26 the stored value is the annual figure / 52 (5,000 / 52), the convention reg 11(3A)(c) uses for multiples of a week. The rounded reg 10(d) £96 would give £4,992 (#1967). -3. Differential: in every year except 2022-23, for any Class 1 earnings - e >= 0 of an earner aged 21 or over who is not an apprentice, - ni_class_1_employer equals rate x max(e - annual ST, 0), computed in exact - arithmetic from STATUTORY. 2022-23 is left out: the Health and Social Care - Levy raised the secondary percentage to 15.05% from 6 April to 5 November - 2022, and the rate parameter does not carry it. +3. Differential: in every year, for any Class 1 earnings e >= 0 of an + earner aged 21 or over who is not an apprentice, ni_class_1_employer + equals rate x max(e - annual ST, 0), computed in exact arithmetic from + STATUTORY. For 2022-23 the s.9(2) percentage at 6 April is 15.05% (Health + and Social Care Levy Act 2021 s.5(2)(b)). It applied to earnings paid + before 6 November 2022 (Repeal Act 2022 s.2(1)), and the model reads the + tax year at 30 April, as for the employee main rate (#1807). 4. Threshold edge: employer NI is zero just below the annual ST, less than half a penny at it, and positive a penny above it. At the ST itself the stored 5,000 / 52 (96.153846) annualises to £4,999.999992, so exact @@ -58,8 +59,8 @@ 2019: (Fraction(166), Fraction(8_632), Fraction(138, 1_000)), 2020: (Fraction(169), Fraction(8_788), Fraction(138, 1_000)), 2021: (Fraction(170), Fraction(8_840), Fraction(138, 1_000)), - # 15.05% from 6 April to 5 November 2022, then 13.8%. - 2022: (Fraction(175), Fraction(9_100), None), + # 15.05% for earnings paid from 6 April to 5 November 2022, then 13.8%. + 2022: (Fraction(175), Fraction(9_100), Fraction(1_505, 10_000)), 2023: (Fraction(175), Fraction(9_100), Fraction(138, 1_000)), 2024: (Fraction(175), Fraction(9_100), Fraction(138, 1_000)), 2025: (Fraction(96), Fraction(5_000), Fraction(15, 100)), @@ -199,5 +200,7 @@ def test_employer_ni_at_the_threshold_edge(year): # between £8,060 and £8,112 in 2016-17 were charged. @example(year=2025, earnings=[40_000.0, 4_996.0, 5_000.0]) @example(year=2016, earnings=[8_100.0, 8_112.0, 20_000.0]) +# 2022-23 was charged at 13.8%, not the 15.05% levy rate. +@example(year=2022, earnings=[30_000.0, 9_100.0, 100_000.0]) def test_employer_ni_follows_the_statutory_threshold(year, earnings): check_employer_ni(year, earnings)