From 6cb1a4b3649cf5de025f3f4c2aab015cd2f98170 Mon Sep 17 00:00:00 2001 From: Pavel Makarchuk <110687043+PavelMakarchuk@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:02:37 +0100 Subject: [PATCH] Remove the Montana CTC for the enacted policies (#5578) * Remove the Montana CTC for the enacted policies Fixes #5577 * minor * remove from state ctcs --- changelog_entry.yaml | 4 + .../states/mt}/ctc/README.md | 0 .../states/mt}/ctc/amount.yaml | 2 - .../gov/contrib/states/mt/ctc/in_effect.yaml | 13 ++ .../states/mt}/ctc/income_limit/agi.yaml | 0 .../mt}/ctc/income_limit/investment.yaml | 0 .../states/mt}/ctc/reduction/amount.yaml | 2 - .../states/mt}/ctc/reduction/increment.yaml | 0 .../states/mt}/ctc/reduction/threshold.yaml | 0 .../mt/tax/income/credits/refundable.yaml | 6 +- policyengine_us/reforms/reforms.py | 6 + .../reforms/states/mt/ctc/__init__.py | 3 + .../reforms/states/mt/ctc/mt_ctc.py | 93 ++++++++++++ .../mt/tax/income/credits/ctc/mt_ctc.yaml | 78 ---------- .../income/credits/ctc/mt_ctc_eligible.yaml | 39 ----- .../policy/contrib/states/mt/ctc/mt_ctc.yaml | 134 ++++++++++++++++++ .../mt/tax/income/credits/ctc/mt_ctc.py | 23 --- .../tax/income/credits/ctc/mt_ctc_eligible.py | 28 ---- 18 files changed, 254 insertions(+), 177 deletions(-) rename policyengine_us/parameters/gov/{states/mt/tax/income/credits => contrib/states/mt}/ctc/README.md (100%) rename policyengine_us/parameters/gov/{states/mt/tax/income/credits => contrib/states/mt}/ctc/amount.yaml (84%) create mode 100644 policyengine_us/parameters/gov/contrib/states/mt/ctc/in_effect.yaml rename policyengine_us/parameters/gov/{states/mt/tax/income/credits => contrib/states/mt}/ctc/income_limit/agi.yaml (100%) rename policyengine_us/parameters/gov/{states/mt/tax/income/credits => contrib/states/mt}/ctc/income_limit/investment.yaml (100%) rename policyengine_us/parameters/gov/{states/mt/tax/income/credits => contrib/states/mt}/ctc/reduction/amount.yaml (78%) rename policyengine_us/parameters/gov/{states/mt/tax/income/credits => contrib/states/mt}/ctc/reduction/increment.yaml (100%) rename policyengine_us/parameters/gov/{states/mt/tax/income/credits => contrib/states/mt}/ctc/reduction/threshold.yaml (100%) create mode 100644 policyengine_us/reforms/states/mt/ctc/__init__.py create mode 100644 policyengine_us/reforms/states/mt/ctc/mt_ctc.py delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/ctc/mt_ctc.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/ctc/mt_ctc_eligible.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/mt/ctc/mt_ctc.yaml delete mode 100644 policyengine_us/variables/gov/states/mt/tax/income/credits/ctc/mt_ctc.py delete mode 100644 policyengine_us/variables/gov/states/mt/tax/income/credits/ctc/mt_ctc_eligible.py diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..0a0a4bb41fc 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: patch + changes: + fixes: + - Convert the Montana Child Tax Credit to a reform. diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/README.md b/policyengine_us/parameters/gov/contrib/states/mt/ctc/README.md similarity index 100% rename from policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/README.md rename to policyengine_us/parameters/gov/contrib/states/mt/ctc/README.md diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/amount.yaml b/policyengine_us/parameters/gov/contrib/states/mt/ctc/amount.yaml similarity index 84% rename from policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/amount.yaml rename to policyengine_us/parameters/gov/contrib/states/mt/ctc/amount.yaml index bc964eee7db..6c408dda913 100644 --- a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/amount.yaml +++ b/policyengine_us/parameters/gov/contrib/states/mt/ctc/amount.yaml @@ -16,8 +16,6 @@ metadata: period: year label: Montana child tax credit base reference: - # The Montana Child Tax Credit established in the 2023 House Bill No. 268 - # not existent before - title: 2023 Montana Legislature, House Bill No. 268, Section 1.(2) & Section 1.(7)-(c) href: https://leg.mt.gov/bills/2023/billhtml/HB0268.htm diff --git a/policyengine_us/parameters/gov/contrib/states/mt/ctc/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/mt/ctc/in_effect.yaml new file mode 100644 index 00000000000..6a61157ac36 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/mt/ctc/in_effect.yaml @@ -0,0 +1,13 @@ +description: The Montana Child Tax Credit is in effect if this is true. + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Montana Child Tax Credit in effect + reference: + - title: 2023 Montana Legislature, House Bill No. 268, Section 1.(2) & Section 1.(7)-(c) + href: https://leg.mt.gov/bills/2023/billhtml/HB0268.htm + diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/income_limit/agi.yaml b/policyengine_us/parameters/gov/contrib/states/mt/ctc/income_limit/agi.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/income_limit/agi.yaml rename to policyengine_us/parameters/gov/contrib/states/mt/ctc/income_limit/agi.yaml diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/income_limit/investment.yaml b/policyengine_us/parameters/gov/contrib/states/mt/ctc/income_limit/investment.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/income_limit/investment.yaml rename to policyengine_us/parameters/gov/contrib/states/mt/ctc/income_limit/investment.yaml diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/reduction/amount.yaml b/policyengine_us/parameters/gov/contrib/states/mt/ctc/reduction/amount.yaml similarity index 78% rename from policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/reduction/amount.yaml rename to policyengine_us/parameters/gov/contrib/states/mt/ctc/reduction/amount.yaml index 19d4733fcef..ad8910e153e 100644 --- a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/reduction/amount.yaml +++ b/policyengine_us/parameters/gov/contrib/states/mt/ctc/reduction/amount.yaml @@ -6,7 +6,5 @@ metadata: period: year label: Montana child tax credit reduction amount reference: - # The Montana Child Tax Credit established in the 2023 House Bill No. 268 - # not existent before - title: 2023 Montana Legislature, House Bill No. 268, Section 1-(6) href: https://leg.mt.gov/bills/2023/billhtml/HB0268.htm diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/reduction/increment.yaml b/policyengine_us/parameters/gov/contrib/states/mt/ctc/reduction/increment.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/reduction/increment.yaml rename to policyengine_us/parameters/gov/contrib/states/mt/ctc/reduction/increment.yaml diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/reduction/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/mt/ctc/reduction/threshold.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/mt/tax/income/credits/ctc/reduction/threshold.yaml rename to policyengine_us/parameters/gov/contrib/states/mt/ctc/reduction/threshold.yaml diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/refundable.yaml b/policyengine_us/parameters/gov/states/mt/tax/income/credits/refundable.yaml index 04f5c38af14..5db8853c7fa 100644 --- a/policyengine_us/parameters/gov/states/mt/tax/income/credits/refundable.yaml +++ b/policyengine_us/parameters/gov/states/mt/tax/income/credits/refundable.yaml @@ -6,11 +6,7 @@ metadata: reference: - title: Montana 2022 Form2 Individual Income Tax Instructions href: https://mtrevenue.gov/wp-content/uploads/dlm_uploads/2022/12/Form-2-2022-Instructions.pdf#page=17 - - title: 2023 Montana Legislature, House Bill No. 268, Section 1 - href: https://leg.mt.gov/bills/2023/billhtml/HB0268.htm + values: 2021-01-01: - mt_eitc - 2023-01-01: - - mt_ctc - - mt_eitc diff --git a/policyengine_us/reforms/reforms.py b/policyengine_us/reforms/reforms.py index 774f943ae53..dc7a058cabf 100644 --- a/policyengine_us/reforms/reforms.py +++ b/policyengine_us/reforms/reforms.py @@ -86,6 +86,10 @@ create_nyc_school_tax_credit_with_phase_out_reform, ) +from .states.mt.ctc import ( + create_mt_ctc_reform, +) + from policyengine_core.reforms import Reform import warnings @@ -188,6 +192,7 @@ def create_structural_reforms_from_parameters(parameters, period): nyc_school_tax_credit_with_phase_out = ( create_nyc_school_tax_credit_with_phase_out_reform(parameters, period) ) + mt_ctc = create_mt_ctc_reform(parameters, period) reforms = [ afa_reform, @@ -226,6 +231,7 @@ def create_structural_reforms_from_parameters(parameters, period): ny_2025_inflation_rebates, limit_salt_deduction_to_property_taxes, nyc_school_tax_credit_with_phase_out, + mt_ctc, ] reforms = tuple(filter(lambda x: x is not None, reforms)) diff --git a/policyengine_us/reforms/states/mt/ctc/__init__.py b/policyengine_us/reforms/states/mt/ctc/__init__.py new file mode 100644 index 00000000000..05fa74f5f05 --- /dev/null +++ b/policyengine_us/reforms/states/mt/ctc/__init__.py @@ -0,0 +1,3 @@ +from .mt_ctc import ( + create_mt_ctc_reform, +) diff --git a/policyengine_us/reforms/states/mt/ctc/mt_ctc.py b/policyengine_us/reforms/states/mt/ctc/mt_ctc.py new file mode 100644 index 00000000000..e9d9a79f849 --- /dev/null +++ b/policyengine_us/reforms/states/mt/ctc/mt_ctc.py @@ -0,0 +1,93 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ +from policyengine_core.periods import instant + + +def create_mt_ctc() -> Reform: + class mt_ctc(Variable): + value_type = float + entity = TaxUnit + label = "Montana Child Tax Credit" + definition_period = YEAR + unit = USD + reference = "https://leg.mt.gov/bills/2023/billpdf/HB0268.pdf" + defined_for = "mt_ctc_eligible" + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.mt.ctc + person = tax_unit.members + age = person("age", period) + credit_amount = tax_unit.sum(p.amount.calc(age)) + # Credit gets reduced by an amount for each increment that AGI exceeds a certain threshold + agi = tax_unit("adjusted_gross_income", period) + excess = max_(agi - p.reduction.threshold, 0) + increments = excess // p.reduction.increment + reduction = p.reduction.amount * increments + return max_(credit_amount - reduction, 0) + + class mt_ctc_eligible(Variable): + value_type = bool + entity = TaxUnit + label = "Eligible for the Montana Child Tax Credit" + definition_period = YEAR + reference = "https://leg.mt.gov/bills/2023/billpdf/HB0268.pdf" + defined_for = StateCode.MT + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.mt.ctc.income_limit + agi = tax_unit("adjusted_gross_income", period) + agi_eligible = agi <= p.agi + # CTC limited to filers with investment income below a certain threshold + investment_income_eligible = ( + tax_unit("eitc_relevant_investment_income", period) + < p.investment + ) + + earned_income = tax_unit("tax_unit_earned_income", period) + receives_earned_income = earned_income > 0 + + return ( + agi_eligible + & investment_income_eligible + & receives_earned_income + ) + + def modify_parameters(parameters): + parameters.gov.states.mt.tax.income.credits.refundable.update( + start=instant("2023-01-01"), + stop=instant("2031-12-31"), + value=["mt_ctc", "mt_eitc"], + ) + return parameters + + class reform(Reform): + def apply(self): + self.update_variable(mt_ctc) + self.update_variable(mt_ctc_eligible) + self.modify_parameters(modify_parameters) + + return reform + + +def create_mt_ctc_reform(parameters, period, bypass: bool = False): + if bypass: + return create_mt_ctc() + + p = parameters.gov.contrib.states.mt.ctc + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_mt_ctc() + else: + return None + + +mt_ctc = create_mt_ctc_reform(None, None, bypass=True) diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/ctc/mt_ctc.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/ctc/mt_ctc.yaml deleted file mode 100644 index e57f3f6413f..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/ctc/mt_ctc.yaml +++ /dev/null @@ -1,78 +0,0 @@ -- name: One child with reduction - period: 2023 - input: - people: - head: - age: 40 - dep1: - age: 60 - dep2: - age: 4 - tax_units: - tax_unit: - members: [head, dep1, dep2] - mt_ctc_eligible: true - adjusted_gross_income: 55_000 - output: - mt_ctc: 750 - # 1200 - 5*90 = 750 - -- name: 2 children under 6 without reduction - period: 2023 - input: - people: - head: - age: 34 - dep1: - age: 3 - dep2: - age: 5 - tax_units: - tax_unit: - members: [head, dep1, dep2] - mt_ctc_eligible: true - adjusted_gross_income: 49_999 - output: - mt_ctc: 2_400 - # 1200 * 2 - -- name: One child over 6 - ineligible - period: 2023 - input: - people: - head: - age: 34 - dep1: - age: 3 - dep2: - age: 5 - dep3: - age: 6 - tax_units: - tax_unit: - members: [head, dep1, dep2, dep3] - mt_ctc_eligible: true - adjusted_gross_income: 49_999 - output: - mt_ctc: 2_400 - # 1200 * 2 - -- name: Ineligible - period: 2023 - input: - people: - head: - age: 34 - dep1: - age: 3 - dep2: - age: 5 - dep3: - age: 6 - tax_units: - tax_unit: - members: [head, dep1, dep2, dep3] - mt_ctc_eligible: false - adjusted_gross_income: 49_999 - output: - mt_ctc: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/ctc/mt_ctc_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/ctc/mt_ctc_eligible.yaml deleted file mode 100644 index 05a1380d13b..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/ctc/mt_ctc_eligible.yaml +++ /dev/null @@ -1,39 +0,0 @@ -- name: Eligible - period: 2023 - input: - tax_unit_earned_income: 66_298 - adjusted_gross_income: 55_999 - eitc_relevant_investment_income: 10_299 - state_code: MT - output: - mt_ctc_eligible: true - -- name: AGI ineligible - period: 2023 - input: - tax_unit_earned_income: 66_300 - adjusted_gross_income: 56_001 - eitc_relevant_investment_income: 10_299 - state_code: MT - output: - mt_ctc_eligible: false - -- name: Investment income ineligible - period: 2023 - input: - tax_unit_earned_income: 66_300 - adjusted_gross_income: 56_000 - eitc_relevant_investment_income: 10_300 - state_code: MT - output: - mt_ctc_eligible: false - -- name: Earned income ineligible - period: 2023 - input: - tax_unit_earned_income: 0 - adjusted_gross_income: 0 - eitc_relevant_investment_income: 0 - state_code: MT - output: - mt_ctc_eligible: false diff --git a/policyengine_us/tests/policy/contrib/states/mt/ctc/mt_ctc.yaml b/policyengine_us/tests/policy/contrib/states/mt/ctc/mt_ctc.yaml new file mode 100644 index 00000000000..e439c729a00 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/mt/ctc/mt_ctc.yaml @@ -0,0 +1,134 @@ +- name: One child with reduction + period: 2023 + reforms: policyengine_us.reforms.states.mt.ctc.mt_ctc.mt_ctc + input: + gov.contrib.states.mt.ctc.in_effect: true + people: + head: + age: 40 + dep1: + age: 60 + dep2: + age: 4 + tax_units: + tax_unit: + members: [head, dep1, dep2] + mt_ctc_eligible: true + adjusted_gross_income: 55_000 + output: + mt_ctc: 750 + # 1200 - 5*90 = 750 + +- name: 2 children under 6 without reduction + period: 2023 + reforms: policyengine_us.reforms.states.mt.ctc.mt_ctc.mt_ctc + input: + gov.contrib.states.mt.ctc.in_effect: true + people: + head: + age: 34 + dep1: + age: 3 + dep2: + age: 5 + tax_units: + tax_unit: + members: [head, dep1, dep2] + mt_ctc_eligible: true + adjusted_gross_income: 49_999 + output: + mt_ctc: 2_400 + # 1200 * 2 + +- name: One child over 6 - ineligible + period: 2023 + reforms: policyengine_us.reforms.states.mt.ctc.mt_ctc.mt_ctc + input: + gov.contrib.states.mt.ctc.in_effect: true + people: + head: + age: 34 + dep1: + age: 3 + dep2: + age: 5 + dep3: + age: 6 + tax_units: + tax_unit: + members: [head, dep1, dep2, dep3] + mt_ctc_eligible: true + adjusted_gross_income: 49_999 + output: + mt_ctc: 2_400 + # 1200 * 2 + +- name: Ineligible + period: 2023 + reforms: policyengine_us.reforms.states.mt.ctc.mt_ctc.mt_ctc + input: + gov.contrib.states.mt.ctc.in_effect: true + people: + head: + age: 34 + dep1: + age: 3 + dep2: + age: 5 + dep3: + age: 6 + tax_units: + tax_unit: + members: [head, dep1, dep2, dep3] + mt_ctc_eligible: false + adjusted_gross_income: 49_999 + output: + mt_ctc: 0 + +- name: Eligible + period: 2023 + reforms: policyengine_us.reforms.states.mt.ctc.mt_ctc.mt_ctc + input: + gov.contrib.states.mt.ctc.in_effect: true + tax_unit_earned_income: 66_298 + adjusted_gross_income: 55_999 + eitc_relevant_investment_income: 10_299 + state_code: MT + output: + mt_ctc_eligible: true + +- name: AGI ineligible + period: 2023 + reforms: policyengine_us.reforms.states.mt.ctc.mt_ctc.mt_ctc + input: + gov.contrib.states.mt.ctc.in_effect: true + tax_unit_earned_income: 66_300 + adjusted_gross_income: 56_001 + eitc_relevant_investment_income: 10_299 + state_code: MT + output: + mt_ctc_eligible: false + +- name: Investment income ineligible + period: 2023 + reforms: policyengine_us.reforms.states.mt.ctc.mt_ctc.mt_ctc + input: + gov.contrib.states.mt.ctc.in_effect: true + tax_unit_earned_income: 66_300 + adjusted_gross_income: 56_000 + eitc_relevant_investment_income: 10_300 + state_code: MT + output: + mt_ctc_eligible: false + +- name: Earned income ineligible + period: 2023 + reforms: policyengine_us.reforms.states.mt.ctc.mt_ctc.mt_ctc + input: + gov.contrib.states.mt.ctc.in_effect: true + tax_unit_earned_income: 0 + adjusted_gross_income: 0 + eitc_relevant_investment_income: 0 + state_code: MT + output: + mt_ctc_eligible: false diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/ctc/mt_ctc.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/ctc/mt_ctc.py deleted file mode 100644 index ecb9e8a640f..00000000000 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/ctc/mt_ctc.py +++ /dev/null @@ -1,23 +0,0 @@ -from policyengine_us.model_api import * - - -class mt_ctc(Variable): - value_type = float - entity = TaxUnit - label = "Montana Child Tax Credit" - definition_period = YEAR - unit = USD - reference = "https://leg.mt.gov/bills/2023/billpdf/HB0268.pdf" - defined_for = "mt_ctc_eligible" - - def formula(tax_unit, period, parameters): - p = parameters(period).gov.states.mt.tax.income.credits.ctc - person = tax_unit.members - age = person("age", period) - credit_amount = tax_unit.sum(p.amount.calc(age)) - # Credit gets reduced by an amount for each increment that AGI exceeds a certain threshold - agi = tax_unit("adjusted_gross_income", period) - excess = max_(agi - p.reduction.threshold, 0) - increments = excess // p.reduction.increment - reduction = p.reduction.amount * increments - return max_(credit_amount - reduction, 0) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/ctc/mt_ctc_eligible.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/ctc/mt_ctc_eligible.py deleted file mode 100644 index 6b919b26bf3..00000000000 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/ctc/mt_ctc_eligible.py +++ /dev/null @@ -1,28 +0,0 @@ -from policyengine_us.model_api import * - - -class mt_ctc_eligible(Variable): - value_type = bool - entity = TaxUnit - label = "Eligible for the Montana Child Tax Credit" - definition_period = YEAR - reference = "https://leg.mt.gov/bills/2023/billpdf/HB0268.pdf" - defined_for = StateCode.MT - - def formula(tax_unit, period, parameters): - p = parameters( - period - ).gov.states.mt.tax.income.credits.ctc.income_limit - agi = tax_unit("adjusted_gross_income", period) - agi_eligible = agi <= p.agi - # CTC limited to filers with investment income below a certain threshold - investment_income_eligible = ( - tax_unit("eitc_relevant_investment_income", period) < p.investment - ) - - earned_income = tax_unit("tax_unit_earned_income", period) - receives_earned_income = earned_income > 0 - - return ( - agi_eligible & investment_income_eligible & receives_earned_income - )