From 83de1ef1d604b98324c94681263821ec4d67e317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Fri, 16 Oct 2026 20:19:57 +0100 Subject: [PATCH] Correct historical dividend income tax band thresholds --- changelog.d/1822.fixed.md | 1 + .../parameters/gov/hmrc/income_tax/README.md | 43 ++++++++ .../gov/hmrc/income_tax/rates/dividends.yaml | 36 +++++++ .../hmrc/income_tax/dividend_band_dates.yaml | 101 ++++++++++++++++++ .../tests/test_dividend_band_dates.py | 73 +++++++++++++ 5 files changed, 254 insertions(+) create mode 100644 changelog.d/1822.fixed.md create mode 100644 policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/dividend_band_dates.yaml create mode 100644 policyengine_uk/tests/test_dividend_band_dates.py diff --git a/changelog.d/1822.fixed.md b/changelog.d/1822.fixed.md new file mode 100644 index 0000000000..4a057f7079 --- /dev/null +++ b/changelog.d/1822.fixed.md @@ -0,0 +1 @@ +- Corrected dividend income-tax band thresholds from 2016 to 2025 to use their statutory tax-year dates. diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/README.md b/policyengine_uk/parameters/gov/hmrc/income_tax/README.md index 3a6da4412d..c21b449d2c 100644 --- a/policyengine_uk/parameters/gov/hmrc/income_tax/README.md +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/README.md @@ -1 +1,44 @@ # Income Tax + +## Dividend bands + +[Income Tax Act 2007 s. 13](https://www.legislation.gov.uk/ukpga/2007/3/section/13) +ties the dividend rates to the corresponding UK taxable-income bands, including +when determining the dividend bands for a Scottish taxpayer. +[Section 16](https://www.legislation.gov.uk/ukpga/2007/3/section/16) places +dividends above other income. The dividend nil-rate amount uses band capacity; +it does not reduce income when determining the remaining capacity in each band. + +The dated dividend scale records these basic-rate limits: + +| Tax year beginning 6 April | Basic-rate limit | Authority | +| --- | ---: | --- | +| 2016 | £32,000 | [Finance (No. 2) Act 2015 s. 6](https://www.legislation.gov.uk/ukpga/2015/33/section/6/enacted) | +| 2017 | £33,500 | [Finance Act 2016 s. 2](https://www.legislation.gov.uk/ukpga/2016/24/section/2/enacted) | +| 2018 | £34,500 | [SI 2017/1184 art 2](https://www.legislation.gov.uk/uksi/2017/1184/article/2/made) | +| 2019 and 2020 | £37,500 | [Finance Act 2019 s. 5](https://www.legislation.gov.uk/ukpga/2019/1/section/5/enacted) | +| From 2021 | £37,700 | [SI 2021/111 art 2](https://www.legislation.gov.uk/uksi/2021/111/article/2/made) | + +The additional-rate threshold falls from £150,000 to £125,140 from 6 April 2023 +under [Finance Act 2023 s. 6](https://www.legislation.gov.uk/ukpga/2023/1/section/6/enacted). +These limits apply after allowances. For example, in 2025, £49,000 of pay uses +£36,430 of taxable band capacity after the £12,570 Personal Allowance. Of a +further £2,000 of dividends, £1,270 fits in the basic band, including the £500 +dividend nil-rate amount. The charge is £770 × 8.75% + £730 × 33.75% = £313.75. + +The threshold history does not certify the pre-2016 dividend-tax-credit regime +or all historical allowance calculations. The inherited 2016 Personal Allowance +is a separate issue tracked in [#2359](https://github.com/PolicyEngine/policyengine-uk/issues/2359): +the inherited amount was £10,600 while the statutory amount is £11,000. The 2016 regression +uses £160,000 of dividends, which naturally withdraws the full allowance under +either amount. It exercises the dividend bands without selecting an allowance +through an intermediate input. Dividend rates, allowance allocation, Gift Aid +extensions and the optional extra dividend bracket retain their existing +interfaces. + +The existing fixed-order allowance allocation does not always implement the +most-beneficial allocation required by ITA 2007 s. 25(2) for mixed wages and +dividends. The 2017, 2021 and 2026 threshold regressions also use dividend-only +income with a naturally zero Personal Allowance. The selected 2018, 2019 and +2025 mixed-income cases have independently checked allowance allocations; +they do not certify the allocation formula for other situations. diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/dividends.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/dividends.yaml index 74fba94512..3cb13cd423 100644 --- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/dividends.yaml +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/dividends.yaml @@ -55,6 +55,36 @@ brackets: label: Dividends higher rate threshold values: 2015-04-01: 37_500 + 2016-04-06: + value: 32_000 + metadata: + reference: + - title: Finance (No. 2) Act 2015 s. 6(a) + href: https://www.legislation.gov.uk/ukpga/2015/33/section/6/enacted + 2017-04-06: + value: 33_500 + metadata: + reference: + - title: Finance Act 2016 s. 2 + href: https://www.legislation.gov.uk/ukpga/2016/24/section/2/enacted + 2018-04-06: + value: 34_500 + metadata: + reference: + - title: The Income Tax (Indexation) Order 2017 art 2 + href: https://www.legislation.gov.uk/uksi/2017/1184/article/2/made + 2019-04-06: + value: 37_500 + metadata: + reference: + - title: Finance Act 2019 s. 5(1) + href: https://www.legislation.gov.uk/ukpga/2019/1/section/5/enacted + 2021-04-06: + value: 37_700 + metadata: + reference: + - title: The Income Tax (Indexation) Order 2021 art 2 + href: https://www.legislation.gov.uk/uksi/2021/111/article/2/made 2026-04-06: value: 37_700 metadata: @@ -79,6 +109,12 @@ brackets: threshold: values: 2015-04-01: 150_000 + 2023-04-06: + value: 125_140 + metadata: + reference: + - title: Finance Act 2023 s. 6(3)-(4) + href: https://www.legislation.gov.uk/ukpga/2023/1/section/6/enacted 2026-04-06: value: 125_140 metadata: diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/dividend_band_dates.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/dividend_band_dates.yaml new file mode 100644 index 0000000000..519e44f94e --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/dividend_band_dates.yaml @@ -0,0 +1,101 @@ +# Literal official-source band arithmetic; the dividend nil rate occupies band capacity. +# PA0 cases isolate2016/2017/2021/2026 bands from separate allowance limitations. +- name: 2016 dividends with wages 0 and dividends 160000 + period: 2016 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 0 + dividend_income: 160000 + output: + dividend_income_tax: 44185.0 + income_tax: 44185.0 +- name: 2017 dividends with wages 0 and dividends 160000 + period: 2017 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 0 + dividend_income: 160000 + output: + dividend_income_tax: 43810.0 + income_tax: 43810.0 +- name: 2018 dividends with wages 40000 and dividends 10000 + period: 2018 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 40000 + dividend_income: 10000 + output: + dividend_income_tax: 1512.5 + income_tax: 7142.5 +- name: 2019 dividends with wages 40000 and dividends 10000 + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 40000 + dividend_income: 10000 + output: + dividend_income_tax: 600.0 + income_tax: 6100.0 +- name: 2021 dividends with wages 0 and dividends 160000 + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 0 + dividend_income: 160000 + output: + dividend_income_tax: 42985.0 + income_tax: 42985.0 +- name: 2023 dividends with wages 130000 and dividends 10000 + period: 2023 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 130000 + dividend_income: 10000 + output: + dividend_income_tax: 3541.5 + income_tax: 48244.5 +- name: 2025 dividends with wages 49000 and dividends 2000 + period: 2025 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 49000 + dividend_income: 2000 + output: + dividend_income_tax: 313.75 + income_tax: 7599.75 +- name: 2025 dividends with wages 130000 and dividends 10000 + period: 2025 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 130000 + dividend_income: 10000 + output: + dividend_income_tax: 3738.25 + income_tax: 48441.25 +- name: 2026 dividends with wages 0 and dividends 160000 + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + region: LONDON + employment_income: 0 + dividend_income: 160000 + output: + dividend_income_tax: 48976.21 + income_tax: 48976.21 diff --git a/policyengine_uk/tests/test_dividend_band_dates.py b/policyengine_uk/tests/test_dividend_band_dates.py new file mode 100644 index 0000000000..969b759580 --- /dev/null +++ b/policyengine_uk/tests/test_dividend_band_dates.py @@ -0,0 +1,73 @@ +"""Dated dividend limits and preserved rate/reform interfaces. + +ITA 2007 s.13 uses the corresponding UK taxable-income bands. Earlier +unchanged values below are regression controls, not a pre-2016 law audit. +""" + +from pathlib import Path + +import pytest +import yaml +from policyengine_core.parameters import Parameter + +import policyengine_uk +from policyengine_uk import CountryTaxBenefitSystem + +PATH = "gov.hmrc.income_tax.rates.dividends" +FILE = ( + Path(policyengine_uk.__file__).parent + / "parameters/gov/hmrc/income_tax/rates/dividends.yaml" +) + + +@pytest.mark.parametrize( + "bracket,before,after,old,new", + [ + (1, "2016-04-05", "2016-04-06", 37_500, 32_000), + (1, "2017-04-05", "2017-04-06", 32_000, 33_500), + (1, "2018-04-05", "2018-04-06", 33_500, 34_500), + (1, "2019-04-05", "2019-04-06", 34_500, 37_500), + (1, "2021-04-05", "2021-04-06", 37_500, 37_700), + (2, "2023-04-05", "2023-04-06", 150_000, 125_140), + ], +) +def test_raw_dividend_limits_change_on_the_statutory_tax_year_date( + bracket, before, after, old, new +): + data = yaml.safe_load(FILE.read_text())["brackets"][bracket]["threshold"] + data["values"] = {str(date): value for date, value in data["values"].items()} + raw = Parameter(f"{PATH}[{bracket}].threshold", data=data, file_path=str(FILE)) + assert raw(before) == old + assert raw(after) == new + + +@pytest.fixture(scope="module") +def system(): + return CountryTaxBenefitSystem() + + +@pytest.mark.parametrize( + "year,basic_limit,additional_limit", + [ + (2016, 32_000, 150_000), + (2017, 33_500, 150_000), + (2018, 34_500, 150_000), + (2019, 37_500, 150_000), + (2020, 37_500, 150_000), + (2021, 37_700, 150_000), + (2023, 37_700, 125_140), + (2025, 37_700, 125_140), + (2026, 37_700, 125_140), + ], +) +def test_annual_dividend_limits_include_restoration_and_current_years( + system, year, basic_limit, additional_limit +): + scale = system.parameters.get_child(PATH)(f"{year}-01-01") + assert scale.thresholds == [0, basic_limit, additional_limit, 10_000_000] + + +def test_2026_dividend_rates_and_optional_extra_bracket_are_unchanged(system): + scale = system.parameters.get_child(PATH)("2026-01-01") + assert scale.rates == [0.1075, 0.3575, 0.3935, 0.3935] + assert scale.thresholds == [0, 37_700, 125_140, 10_000_000]