diff --git a/changelog.d/fix-abolish-council-tax.fixed.md b/changelog.d/fix-abolish-council-tax.fixed.md new file mode 100644 index 000000000..d0be109ce --- /dev/null +++ b/changelog.d/fix-abolish-council-tax.fixed.md @@ -0,0 +1 @@ +Fix abolishing council tax having no budget impact. diff --git a/policyengine_uk/tests/microsimulation/reforms_config.yaml b/policyengine_uk/tests/microsimulation/reforms_config.yaml index af9f1a57a..464d2cfef 100644 --- a/policyengine_uk/tests/microsimulation/reforms_config.yaml +++ b/policyengine_uk/tests/microsimulation/reforms_config.yaml @@ -16,7 +16,7 @@ reforms: parameters: gov.hmrc.child_benefit.amount.additional: 25 - name: Reduce Universal Credit taper rate to 20% - expected_impact: -43.2 + expected_impact: -42.0 parameters: gov.dwp.universal_credit.means_test.reduction_rate: 0.2 - name: Raise Class 1 main employee NICs rate to 10% diff --git a/policyengine_uk/tests/microsimulation/test_abolish_council_tax.py b/policyengine_uk/tests/microsimulation/test_abolish_council_tax.py new file mode 100644 index 000000000..53fd570fd --- /dev/null +++ b/policyengine_uk/tests/microsimulation/test_abolish_council_tax.py @@ -0,0 +1,55 @@ +"""Test that abolishing council tax has a budgetary impact (#1153).""" + +import pytest +from policyengine_uk import Microsimulation +from policyengine_uk.model_api import Scenario + +YEAR = 2025 +CT_AMOUNT = 2000 + +SITUATION = { + "people": { + "person": { + "age": {YEAR: 30}, + "employment_income": {YEAR: 30000}, + }, + }, + "benunits": {"benunit": {"members": ["person"]}}, + "households": { + "household": { + "members": ["person"], + "council_tax": {YEAR: CT_AMOUNT}, + }, + }, +} + + +@pytest.fixture(scope="module") +def baseline_net_income(): + sim = Microsimulation(situation=SITUATION) + return float(sim.calculate("household_net_income", YEAR).sum()) + + +@pytest.fixture(scope="module") +def reform_net_income(): + scenario = Scenario( + parameter_changes={ + "gov.contrib.abolish_council_tax": {str(YEAR): True} + } + ) + sim = Microsimulation(situation=SITUATION, scenario=scenario) + return float(sim.calculate("household_net_income", YEAR).sum()) + + +def test_abolish_council_tax_increases_net_income( + baseline_net_income, reform_net_income +): + diff = reform_net_income - baseline_net_income + assert diff > 0 + + +def test_abolish_council_tax_increases_by_council_tax_amount( + baseline_net_income, reform_net_income +): + diff = reform_net_income - baseline_net_income + assert abs(diff - CT_AMOUNT) < 100 diff --git a/policyengine_uk/variables/contrib/policyengine/pre_budget_change_household_benefits.py b/policyengine_uk/variables/contrib/policyengine/pre_budget_change_household_benefits.py index 56f03f58e..2b1b9d5d1 100644 --- a/policyengine_uk/variables/contrib/policyengine/pre_budget_change_household_benefits.py +++ b/policyengine_uk/variables/contrib/policyengine/pre_budget_change_household_benefits.py @@ -44,12 +44,6 @@ def formula(household, period, parameters): contrib = parameters(period).gov.contrib uprating = contrib.benefit_uprating benefits = pre_budget_change_household_benefits.adds - if contrib.abolish_council_tax: - benefits = [ - benefit - for benefit in benefits - if benefit != "council_tax_benefit" - ] general_benefits = add( household, period, diff --git a/policyengine_uk/variables/contrib/policyengine/pre_budget_change_household_tax.py b/policyengine_uk/variables/contrib/policyengine/pre_budget_change_household_tax.py index 76195ace1..af0021736 100644 --- a/policyengine_uk/variables/contrib/policyengine/pre_budget_change_household_tax.py +++ b/policyengine_uk/variables/contrib/policyengine/pre_budget_change_household_tax.py @@ -14,7 +14,7 @@ class pre_budget_change_household_tax(Variable): "expected_lbtt", "corporate_sdlt", "business_rates", - "council_tax", + "council_tax_applicable", "domestic_rates", "fuel_duty", "tv_licence", @@ -27,17 +27,3 @@ class pre_budget_change_household_tax(Variable): "vat_change", "capital_gains_tax", ] - - def formula(household, period, parameters): - if parameters(period).gov.contrib.abolish_council_tax: - return add( - household, - period, - [ - tax - for tax in pre_budget_change_household_tax.adds - if tax not in ["council_tax"] - ], - ) - else: - return add(household, period, pre_budget_change_household_tax.adds) diff --git a/policyengine_uk/variables/gov/gov_tax.py b/policyengine_uk/variables/gov/gov_tax.py index 131cf8ef7..e8f1b20f3 100644 --- a/policyengine_uk/variables/gov/gov_tax.py +++ b/policyengine_uk/variables/gov/gov_tax.py @@ -16,7 +16,7 @@ class gov_tax(Variable): "expected_lbtt", "corporate_sdlt", "business_rates", - "council_tax", + "council_tax_applicable", "domestic_rates", "fuel_duty", "tv_licence", @@ -34,12 +34,3 @@ class gov_tax(Variable): "student_loan_repayments", "vat", ] - - def formula(household, period, parameters): - variables = list(gov_tax.adds) - if parameters(period).gov.contrib.abolish_council_tax: - variables = [ - variable for variable in variables if variable != "council_tax" - ] - - return add(household, period, variables) diff --git a/policyengine_uk/variables/gov/hmrc/household_tax.py b/policyengine_uk/variables/gov/hmrc/household_tax.py index 5655b2477..4f62f7713 100644 --- a/policyengine_uk/variables/gov/hmrc/household_tax.py +++ b/policyengine_uk/variables/gov/hmrc/household_tax.py @@ -14,7 +14,7 @@ class household_tax(Variable): "expected_lbtt", "corporate_sdlt", "business_rates", - "council_tax", + "council_tax_applicable", "domestic_rates", "fuel_duty", "tv_licence", @@ -33,17 +33,3 @@ class household_tax(Variable): "employer_ni_response_consumer_incidence", "student_loan_repayments", ] - - def formula(household, period, parameters): - if parameters(period).gov.contrib.abolish_council_tax: - return add( - household, - period, - [ - tax - for tax in household_tax.adds - if tax not in ["council_tax"] - ], - ) - else: - return add(household, period, household_tax.adds) diff --git a/policyengine_uk/variables/gov/local/council_tax_applicable.py b/policyengine_uk/variables/gov/local/council_tax_applicable.py new file mode 100644 index 000000000..ffa95f577 --- /dev/null +++ b/policyengine_uk/variables/gov/local/council_tax_applicable.py @@ -0,0 +1,16 @@ +from policyengine_uk.model_api import * + + +class council_tax_applicable(Variable): + value_type = float + entity = Household + label = "Council Tax (after abolition check)" + documentation = "Council Tax amount, or zero if council tax is abolished" + definition_period = YEAR + unit = GBP + quantity_type = FLOW + + def formula(household, period, parameters): + council_tax = household("council_tax", period) + abolish = parameters(period).gov.contrib.abolish_council_tax + return where(abolish, 0, council_tax) diff --git a/policyengine_uk/variables/household/income/hbai_household_net_income.py b/policyengine_uk/variables/household/income/hbai_household_net_income.py index 78c890db0..4ad1cf657 100644 --- a/policyengine_uk/variables/household/income/hbai_household_net_income.py +++ b/policyengine_uk/variables/household/income/hbai_household_net_income.py @@ -58,7 +58,7 @@ class hbai_household_net_income(Variable): # Reference for tax-free-childcare: https://assets.publishing.service.gov.uk/media/5e7b191886650c744175d08b/households-below-average-income-1994-1995-2018-2019.pdf ] subtracts = [ - "council_tax", + "council_tax_applicable", "domestic_rates", "income_tax", "national_insurance", diff --git a/policyengine_uk/variables/household/income/household_benefits.py b/policyengine_uk/variables/household/income/household_benefits.py index 9d82a3437..c77578b5d 100644 --- a/policyengine_uk/variables/household/income/household_benefits.py +++ b/policyengine_uk/variables/household/income/household_benefits.py @@ -57,12 +57,6 @@ def formula(household, period, parameters): contrib = parameters(period).gov.contrib uprating = contrib.benefit_uprating benefits = household_benefits.adds - if contrib.abolish_council_tax: - benefits = [ - benefit - for benefit in benefits - if benefit != "council_tax_benefit" - ] general_benefits = add( household, period,