From ac1cb6d51e2564be376a6d123194e7f8a1457ef4 Mon Sep 17 00:00:00 2001 From: Anthony Volk Date: Tue, 29 Oct 2024 16:21:44 +0100 Subject: [PATCH 1/3] fix: Alter VA reduced itemized deductions based on changes to TCJA --- .../va_reduced_itemized_deductions.py | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/policyengine_us/variables/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.py b/policyengine_us/variables/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.py index d4e9afef3f8..195b157061d 100644 --- a/policyengine_us/variables/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.py +++ b/policyengine_us/variables/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.py @@ -32,15 +32,26 @@ def formula(tax_unit, period, parameters): excess_ded = max_(applicable_ded - reducible_ded, 0) # If 0 - no reduction # Line 4 - IRS deduction rate of excess + # The federal limitation on itemized deductions does not apply during the TCJA period # Virginia still applies the limitation - year = period.start.year - if year >= 2018 and year <= 2026: - instant_str = f"2017-01-01" - else: - instant_str = period - p_irs = parameters(instant_str).gov.irs.deductions.itemized.limitation - excess_ded_fraction = excess_ded * p_irs.itemized_deduction_rate + + # Here, we use a parameter that mostly keeps in line with the IRS's; + # Virginia follows the IRS, except for TCJA-related policies, hence we + # remove anything TCJA related, but keep everything else coupled to the IRS + + # Shortcut to the full parameter, not parameter at instant, for IRS itemized limitations + full_irs_param: Parameter = parameters.gov.irs.deductions.itemized.limitation + + va_itemized_deduction_rate = full_irs_param.itemized_deduction_rate.clone() + + # Eliminate infinite values created by the TCJA's elimination of this param + va_itemized_deduction_rate.values_list = [ + entry for entry in va_itemized_deduction_rate.values_list + if not (entry.value == np.inf or entry.value == -np.inf) + ] + + excess_ded_fraction = excess_ded * va_itemized_deduction_rate(period) # Line 5 Federal AGI federal_agi = tax_unit("adjusted_gross_income", period) # Line 6 - applicable amount @@ -49,7 +60,16 @@ def formula(tax_unit, period, parameters): # Line 7 - excess excess = max_(federal_agi - applicable_amount, 0) # Line 8 - excess times federal item. ded. AGI rate - agi_adjustment = p_irs.agi_rate * excess + + # Here again, Virginia follows the IRS, except for TCJA-related policies, + # and we'll need to eliminate infinite values created by TCJA abolishing param + va_agi_rate = full_irs_param.agi_rate.clone() + va_agi_rate.values_list = [ + entry for entry in va_agi_rate.values_list + if not (entry.value == np.inf or entry.value == -np.inf) + ] + + agi_adjustment = va_agi_rate(period) * excess # Line 9 - min of line 4 and line 8 va_itm_deds_adjustment = min_(agi_adjustment, excess_ded_fraction) # Output from Part A (Line 1 - Line 9) @@ -70,9 +90,7 @@ def formula(tax_unit, period, parameters): "va_capped_state_and_local_sales_or_income_tax", period ) - state_and_local_tax_adj = ( - capped_state_and_local_tax * adjustment_fraction - ) + state_and_local_tax_adj = capped_state_and_local_tax * adjustment_fraction # Line 15 - Subtract Line 14 from Line 13 reduced_state_and_local_tax = max_( capped_state_and_local_tax - state_and_local_tax_adj, 0 From 877c4236325971c41012d753f81845097e715d0e Mon Sep 17 00:00:00 2001 From: Anthony Volk Date: Tue, 29 Oct 2024 16:52:40 +0100 Subject: [PATCH 2/3] fix: Add test, update changelog --- changelog_entry.yaml | 4 ++++ .../deductions/va_reduced_itemized_deductions.yaml | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..4992b5ed490 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: patch + changes: + changed: + - Altered handling of federal params in VA reduced itemized deductions \ No newline at end of file diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.yaml index f25847088c0..f85b14efbdb 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.yaml @@ -19,6 +19,16 @@ output: va_reduced_itemized_deductions: 0 +- name: 2027 Virginia limited itemized deduction for a head of household filer + period: 2027 + input: + filing_status: HEAD_OF_HOUSEHOLD + adjusted_gross_income: 800_000 # > $306,300 + state_and_local_sales_or_income_tax: 60_000 + state_code: VA + output: + va_reduced_itemized_deductions: 0 + - name: Filer with State and local tax as well as mortgage interest period: 2021 absolute_error_margin: 2 From be0f5bdeff4a4694c899e5e81d781515cb731008 Mon Sep 17 00:00:00 2001 From: Anthony Volk Date: Tue, 29 Oct 2024 18:56:33 +0100 Subject: [PATCH 3/3] chore: Format --- changelog_entry.yaml | 2 +- .../va_reduced_itemized_deductions.py | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/changelog_entry.yaml b/changelog_entry.yaml index 4992b5ed490..887de8e84ec 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -1,4 +1,4 @@ - bump: patch changes: changed: - - Altered handling of federal params in VA reduced itemized deductions \ No newline at end of file + - Altered handling of federal params in VA reduced itemized deductions diff --git a/policyengine_us/variables/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.py b/policyengine_us/variables/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.py index 195b157061d..5251b97074d 100644 --- a/policyengine_us/variables/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.py +++ b/policyengine_us/variables/gov/states/va/tax/income/deductions/va_reduced_itemized_deductions.py @@ -41,13 +41,18 @@ def formula(tax_unit, period, parameters): # remove anything TCJA related, but keep everything else coupled to the IRS # Shortcut to the full parameter, not parameter at instant, for IRS itemized limitations - full_irs_param: Parameter = parameters.gov.irs.deductions.itemized.limitation + full_irs_param: Parameter = ( + parameters.gov.irs.deductions.itemized.limitation + ) - va_itemized_deduction_rate = full_irs_param.itemized_deduction_rate.clone() + va_itemized_deduction_rate = ( + full_irs_param.itemized_deduction_rate.clone() + ) # Eliminate infinite values created by the TCJA's elimination of this param va_itemized_deduction_rate.values_list = [ - entry for entry in va_itemized_deduction_rate.values_list + entry + for entry in va_itemized_deduction_rate.values_list if not (entry.value == np.inf or entry.value == -np.inf) ] @@ -65,7 +70,8 @@ def formula(tax_unit, period, parameters): # and we'll need to eliminate infinite values created by TCJA abolishing param va_agi_rate = full_irs_param.agi_rate.clone() va_agi_rate.values_list = [ - entry for entry in va_agi_rate.values_list + entry + for entry in va_agi_rate.values_list if not (entry.value == np.inf or entry.value == -np.inf) ] @@ -90,7 +96,9 @@ def formula(tax_unit, period, parameters): "va_capped_state_and_local_sales_or_income_tax", period ) - state_and_local_tax_adj = capped_state_and_local_tax * adjustment_fraction + state_and_local_tax_adj = ( + capped_state_and_local_tax * adjustment_fraction + ) # Line 15 - Subtract Line 14 from Line 13 reduced_state_and_local_tax = max_( capped_state_and_local_tax - state_and_local_tax_adj, 0