Skip to content

Commit cb59c62

Browse files
authored
Merge pull request #1568 from PolicyEngine/codex/fix-1392
Add the high value council tax surcharge
2 parents d2c7b7a + 264a957 commit cb59c62

6 files changed

Lines changed: 141 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added the England-only High Value Council Tax Surcharge from April 2028, including its 2026-price valuation bands and CPI uprating from 2029-30 onward.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
description: High Value Council Tax Surcharge on owners of residential property in England worth £2 million or more in 2026 prices.
2+
3+
brackets:
4+
- threshold:
5+
2028-01-01: 0
6+
amount:
7+
2028-01-01: 0
8+
- threshold:
9+
2028-01-01: 2_000_000
10+
amount:
11+
2028-01-01: 2_500
12+
- threshold:
13+
2028-01-01: 2_500_000
14+
amount:
15+
2028-01-01: 3_500
16+
- threshold:
17+
2028-01-01: 3_500_000
18+
amount:
19+
2028-01-01: 5_000
20+
- threshold:
21+
2028-01-01: 5_000_000
22+
amount:
23+
2028-01-01: 7_500
24+
25+
metadata:
26+
type: single_amount
27+
threshold_unit: currency-GBP
28+
amount_unit: currency-GBP
29+
uprating: gov.benefit_uprating_cpi
30+
label: High Value Council Tax Surcharge
31+
reference:
32+
- title: High Value Council Tax Surcharge
33+
href: https://www.gov.uk/government/publications/high-value-council-tax-surcharge/high-value-council-tax-surcharge
34+
- title: Budget 2025
35+
href: https://www.gov.uk/government/publications/budget-2025-document/budget-2025-html
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import pytest
2+
3+
from policyengine_uk import Simulation
4+
from policyengine_uk.variables.gov.gov_tax import gov_tax
5+
from policyengine_uk.variables.gov.hmrc.household_tax import household_tax
6+
7+
8+
def _homeowner(main_residence_value: float, region: str = "LONDON") -> dict:
9+
return {
10+
"people": {
11+
"person": {
12+
"age": {2026: 45, 2028: 47, 2029: 48},
13+
"employment_income": {2028: 0, 2029: 0},
14+
}
15+
},
16+
"benunits": {"benunit": {"members": ["person"]}},
17+
"households": {
18+
"household": {
19+
"members": ["person"],
20+
"region": {2028: region, 2029: region},
21+
"main_residence_value": {2026: main_residence_value},
22+
}
23+
},
24+
}
25+
26+
27+
def test_high_value_council_tax_surcharge_starts_in_2028():
28+
sim = Simulation(situation=_homeowner(2_400_000))
29+
30+
assert sim.calculate("high_value_council_tax_surcharge", 2027)[0] == 0
31+
assert sim.calculate("high_value_council_tax_surcharge", 2028)[0] == 2_500
32+
33+
34+
def test_high_value_council_tax_surcharge_is_uprated_from_2029():
35+
sim = Simulation(situation=_homeowner(2_400_000))
36+
current = sim.tax_benefit_system.parameters("2029")
37+
previous = sim.tax_benefit_system.parameters("2028")
38+
expected_2029 = (
39+
2_500
40+
* float(current.gov.benefit_uprating_cpi)
41+
/ float(previous.gov.benefit_uprating_cpi)
42+
)
43+
44+
assert sim.calculate("high_value_council_tax_surcharge", 2029)[0] == pytest.approx(
45+
expected_2029
46+
)
47+
48+
49+
def test_high_value_council_tax_surcharge_flows_into_tax_aggregates():
50+
sim = Simulation(situation=_homeowner(2_400_000))
51+
52+
other_household_taxes = sum(
53+
sim.calculate(variable, 2028)[0]
54+
for variable in household_tax.adds
55+
if variable != "high_value_council_tax_surcharge"
56+
)
57+
other_government_taxes = sum(
58+
sim.calculate(variable, 2028)[0]
59+
for variable in gov_tax.adds
60+
if variable != "high_value_council_tax_surcharge"
61+
)
62+
63+
assert sim.calculate("household_tax", 2028)[0] - other_household_taxes == 2_500
64+
assert sim.calculate("gov_tax", 2028)[0] - other_government_taxes == 2_500
65+
66+
67+
def test_high_value_council_tax_surcharge_only_applies_in_england():
68+
sim = Simulation(situation=_homeowner(6_000_000, region="SCOTLAND"))
69+
70+
assert sim.calculate("high_value_council_tax_surcharge", 2028)[0] == 0

policyengine_uk/variables/gov/gov_tax.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class gov_tax(Variable):
1515
"corporate_sdlt",
1616
"business_rates",
1717
"council_tax",
18+
"high_value_council_tax_surcharge",
1819
"domestic_rates",
1920
"fuel_duty",
2021
"tv_licence",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from policyengine_uk.model_api import *
2+
3+
4+
class high_value_council_tax_surcharge(Variable):
5+
value_type = float
6+
entity = Household
7+
label = "High Value Council Tax Surcharge"
8+
documentation = (
9+
"Additional annual surcharge on owners of residential property in England "
10+
"worth at least £2 million in 2026 prices."
11+
)
12+
definition_period = YEAR
13+
unit = GBP
14+
15+
def formula(household, period, parameters):
16+
if period.start.year < 2028:
17+
return 0
18+
19+
country = household("country", period)
20+
in_england = country == country.possible_values.ENGLAND
21+
22+
p = parameters(period)
23+
property_value = household("main_residence_value", period)
24+
current_index = p.gov.economic_assumptions.indices.obr.per_capita.gdp
25+
baseline_index = parameters(
26+
"2026"
27+
).gov.economic_assumptions.indices.obr.per_capita.gdp
28+
value_2026_prices = property_value / (current_index / baseline_index)
29+
30+
surcharge = p.gov.hmrc.council_tax.high_value_surcharge.amount.calc(
31+
value_2026_prices
32+
)
33+
return where(in_england, surcharge, 0)

policyengine_uk/variables/gov/hmrc/household_tax.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class household_tax(Variable):
1515
"corporate_sdlt",
1616
"business_rates",
1717
"council_tax",
18+
"high_value_council_tax_surcharge",
1819
"domestic_rates",
1920
"fuel_duty",
2021
"tv_licence",

0 commit comments

Comments
 (0)