From be25a517545de62fd172d4b68e2d9adf8948c5de Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 29 Jan 2025 13:44:44 +0100 Subject: [PATCH 1/4] Refactor the Iowa state tax model starting in 2023 Fixes #5460 --- changelog_entry.yaml | 4 +++ .../alternate_tax/deduction/nonelderly.yaml | 1 + .../ia/tax/income/alternate_tax/rate.yaml | 1 + .../tax/income/modified_income/sources.yaml | 5 +++ .../tax/income/taxable_income/additions.yaml | 18 +++++++++++ .../income/taxable_income/subtractions.yaml | 26 +++++++++++++++ .../ia_alternate_tax_consolidated.yaml | 19 +++++++++++ .../ia_income_tax_consolidated.yaml | 32 +++++++++++++++++++ .../ia_regular_tax_consolidated.yaml | 19 +++++++++++ .../ia_taxable_income_consolidated.yaml | 19 +++++++++++ .../states/ia/tax/income/ia_integration.yaml | 28 ++++++++++++++++ .../ia_alternate_tax_consolidated.py | 26 +++++++++++++++ .../ia_income_tax_consolidated.py | 21 ++++++++++++ .../ia_regular_tax_consolidated.py | 25 +++++++++++++++ .../ia_additions_consolidated.py | 13 ++++++++ .../ia_subtractions_consolidated.py | 13 ++++++++ .../ia_taxable_income_consolidated.py | 22 +++++++++++++ ...xable_income_modifications_consolidated.py | 17 ++++++++++ .../ia_alternate_tax_eligible.py | 0 .../income/ia_income_tax_before_credits.py | 16 +++++++--- .../alternate_tax/ia_alternate_tax_indiv.py | 0 .../alternate_tax/ia_alternate_tax_joint.py | 0 .../alternate_tax/ia_alternate_tax_unit.py | 0 .../deductions/ia_basic_deduction_indiv.py | 0 .../deductions/ia_basic_deduction_joint.py | 0 .../deductions/ia_fedtax_deduction.py | 0 .../ia_itemized_deductions_indiv.py | 0 .../ia_itemized_deductions_joint.py | 0 .../deductions/ia_itemized_deductions_unit.py | 0 .../deductions/ia_qbi_deduction.py | 0 .../deductions/ia_standard_deduction_indiv.py | 0 .../deductions/ia_standard_deduction_joint.py | 0 .../ia_amt_indiv.py | 0 .../ia_amt_joint.py | 0 .../ia_base_tax_indiv.py | 0 .../ia_base_tax_joint.py | 0 .../ia_income_tax_indiv.py | 0 .../ia_income_tax_joint.py | 0 .../ia_regular_tax_indiv.py | 0 .../ia_regular_tax_joint.py | 0 .../ia_taxable_income_indiv.py | 0 .../ia_taxable_income_joint.py | 0 .../ia_pension_exclusion_eligible.py | 1 - 43 files changed, 320 insertions(+), 6 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/additions.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_alternate_tax_consolidated.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_income_tax_consolidated.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_consolidated.yaml create mode 100644 policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_alternate_tax_consolidated.py create mode 100644 policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_income_tax_consolidated.py create mode 100644 policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.py create mode 100644 policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_additions_consolidated.py create mode 100644 policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_subtractions_consolidated.py create mode 100644 policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_consolidated.py create mode 100644 policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_modifications_consolidated.py rename policyengine_us/variables/gov/states/ia/tax/income/{alternate_tax => }/ia_alternate_tax_eligible.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/alternate_tax/ia_alternate_tax_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/alternate_tax/ia_alternate_tax_joint.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/alternate_tax/ia_alternate_tax_unit.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_basic_deduction_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_basic_deduction_joint.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_fedtax_deduction.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_itemized_deductions_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_itemized_deductions_joint.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_itemized_deductions_unit.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_qbi_deduction.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_standard_deduction_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/deductions/ia_standard_deduction_joint.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_amt_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_amt_joint.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_base_tax_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_base_tax_joint.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_income_tax_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_income_tax_joint.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_regular_tax_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_regular_tax_joint.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_taxable_income_indiv.py (100%) rename policyengine_us/variables/gov/states/ia/tax/income/{ => including_married_filing_separately}/ia_taxable_income_joint.py (100%) diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..b808ccaf1e1 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: patch + changes: + fixed: + - Iowa income tax structure on and after 2023. diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/deduction/nonelderly.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/deduction/nonelderly.yaml index 7fc0e0f199e..96f046db832 100644 --- a/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/deduction/nonelderly.yaml +++ b/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/deduction/nonelderly.yaml @@ -1,6 +1,7 @@ description: Iowa has a alternate tax with this deduction against modified income for tax units without an elderly head or spouse. values: 2021-01-01: 13_500 + metadata: label: Iowa deduction used in tax alternate tax calculations for nonelderly diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/rate.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/rate.yaml index fb91ce22049..99df1a0677c 100644 --- a/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/rate.yaml +++ b/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/rate.yaml @@ -1,6 +1,7 @@ description: Iowa allows an alternate tax for non-single filing units that has this flat tax rate. values: 2021-01-01: 0.0853 + 2023-01-01: 0.06 metadata: label: Iowa alternate tax rate diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/modified_income/sources.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/modified_income/sources.yaml index ce8ec0fbca7..ff0dac2ece9 100644 --- a/policyengine_us/parameters/gov/states/ia/tax/income/modified_income/sources.yaml +++ b/policyengine_us/parameters/gov/states/ia/tax/income/modified_income/sources.yaml @@ -4,6 +4,11 @@ values: - ia_net_income - ia_pension_exclusion - ia_reportable_social_security + 2023-01-01: + - ia_taxable_income_consolidated + - taxable_income_deductions + - qualified_business_income_deduction + metadata: unit: list diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/additions.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/additions.yaml new file mode 100644 index 00000000000..a443c0931ed --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/additions.yaml @@ -0,0 +1,18 @@ +description: Iowa adds these sources to taxable income on and after 2023. +values: + 2021-01-01: [] + # Interest from state and municipal securities + # Dividends from state and municipal bonds + # Bonus Depreciation + # Net operating loss + + +metadata: + unit: list + period: year + label: Iowa taxable income additions + reference: + - title: 2023 IA1040 Iowa Income Tax Return + href: https://revenue.iowa.gov/media/2746/download?inline + - title: Iowa income tax law, 422.7 + href: https://www.legis.iowa.gov/docs/code/422.7.pdf diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml new file mode 100644 index 00000000000..f1f060c815c --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml @@ -0,0 +1,26 @@ +description: Iowa subtracts these sources from taxable income on and after 2023. +values: + 2021-01-01: + # Line 1B + - us_govt_interest + # Dividends from federal securitites + # Line 5B + - taxable_social_security + # Line 6B + - military_service_income + # Line 7B + - ia_pension_exclusion + # Railroad unemployment income + # Bonus Depreciation + # Iowa Health Insurance Deduction + # Iowa capital gains deduction + +metadata: + unit: list + period: year + label: Iowa taxable income subtractions + reference: + - title: 2023 IA1040 Iowa Income Tax Return + href: https://revenue.iowa.gov/media/2746/download?inline + - title: Iowa income tax law, 422.7 + href: https://www.legis.iowa.gov/docs/code/422.7.pdf diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_alternate_tax_consolidated.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_alternate_tax_consolidated.yaml new file mode 100644 index 00000000000..2cbc87ce8e9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_alternate_tax_consolidated.yaml @@ -0,0 +1,19 @@ +- name: Elderly present + absolute_error_margin: 0.01 + period: 2023 + input: + ia_modified_income: 100_000 + greater_age_head_spouse: 65 + state_code: IA + output: # from hand calculation following IA 6251 form + ia_alternate_tax_consolidated: 4_080 + +- name: Elderly not present + absolute_error_margin: 0.01 + period: 2023 + input: + ia_modified_income: 100_000 + greater_age_head_spouse: 64 + state_code: IA + output: # from hand calculation following IA 6251 form + ia_alternate_tax_consolidated: 5_190 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_income_tax_consolidated.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_income_tax_consolidated.yaml new file mode 100644 index 00000000000..0831a0e7d3a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_income_tax_consolidated.yaml @@ -0,0 +1,32 @@ +- name: Eligible, regular tax is lower than alternate tax + absolute_error_margin: 0.01 + period: 2023 + input: + ia_regular_tax_consolidated: 10_000 + ia_alternate_tax_eligible: true + ia_alternate_tax_consolidated: 12_000 + state_code: IA + output: # from hand calculation following IA 6251 form + ia_income_tax_consolidated: 10_000 + +- name: Eligible, alternate tax is lower than regular tax + absolute_error_margin: 0.01 + period: 2023 + input: + ia_regular_tax_consolidated: 12_000 + ia_alternate_tax_eligible: true + ia_alternate_tax_consolidated: 10_000 + state_code: IA + output: # from hand calculation following IA 6251 form + ia_income_tax_consolidated: 10_000 + +- name: Ineligible, regular tax is lower than alternate tax + absolute_error_margin: 0.01 + period: 2023 + input: + ia_regular_tax_consolidated: 12_000 + ia_alternate_tax_eligible: false + ia_alternate_tax_consolidated: 10_000 + state_code: IA + output: # from hand calculation following IA 6251 form + ia_income_tax_consolidated: 12_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.yaml new file mode 100644 index 00000000000..c057962fcfc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.yaml @@ -0,0 +1,19 @@ +- name: Single person with $40,000 of employment income + absolute_error_margin: 0.01 + period: 2023 + input: + ia_taxable_income_consolidated: 40_000 + filing_status: SINGLE + state_code: IA + output: # from hand calculation following IA 6251 form + ia_regular_tax_consolidated: 1_990.8 + +- name: Joint person with $40,000 of employment income + absolute_error_margin: 0.01 + period: 2023 + input: + ia_taxable_income_consolidated: 40_000 + filing_status: JOINT + state_code: IA + output: # from hand calculation following IA 6251 form + ia_regular_tax_consolidated: 1_877.6 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_consolidated.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_consolidated.yaml new file mode 100644 index 00000000000..23d514104aa --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_consolidated.yaml @@ -0,0 +1,19 @@ +- name: Taxable income with subtractions + absolute_error_margin: 0.01 + period: 2023 + input: + taxable_income: 1_000 + ia_taxable_income_modifications_consolidated: -3_000 + state_code: IA + output: # from hand calculation following IA 6251 form + ia_taxable_income_consolidated: 0 + +- name: Taxable income with additions + absolute_error_margin: 0.01 + period: 2023 + input: + taxable_income: 1_000 + ia_taxable_income_modifications_consolidated: 100 + state_code: IA + output: # from hand calculation following IA 6251 form + ia_taxable_income_consolidated: 1_100 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_integration.yaml index 563dfe49971..4f8d557f628 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_integration.yaml @@ -342,3 +342,31 @@ state_code: IA output: # expected ia_income_tax from patched TAXSIM35 2023-06-23 version ia_income_tax: 14_590.43 + +- name: Single person with $40,000 of employment income + absolute_error_margin: 1 + period: 2023 + input: + people: + person1: + employment_income: 40_000 + households: + household: + members: [person1] + state_code: IA + output: + ia_income_tax: 1_195 + +- name: Single person with $40,000 of employment income + absolute_error_margin: 1 + period: 2024 + input: + people: + person1: + taxable_interest_income: 100_000 + households: + household: + members: [person1] + state_code: IA + output: + ia_taxable_income_consolidated: 85_400 diff --git a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_alternate_tax_consolidated.py b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_alternate_tax_consolidated.py new file mode 100644 index 00000000000..ac76f30533d --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_alternate_tax_consolidated.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class ia_alternate_tax_consolidated(Variable): + value_type = float + entity = TaxUnit + label = "Iowa alternate tax for years on or after 2023" + unit = USD + definition_period = YEAR + reference = "https://revenue.iowa.gov/media/2754/download?inline" + defined_for = StateCode.IA + + def formula(tax_unit, period, parameters): + modified_income = tax_unit("ia_modified_income", period) + # compute alternate tax following worksheet in the instructions + p = parameters(period).gov.states.ia.tax.income.alternate_tax + # ... determine alternate tax deduction + elderly_head_or_spouse = ( + tax_unit("greater_age_head_spouse", period) >= p.elderly_age + ) + alt_ded = where( + elderly_head_or_spouse, p.deduction.elderly, p.deduction.nonelderly + ) + # ... determine alternate tax amount + alt_taxinc = max_(0, modified_income - alt_ded) + return alt_taxinc * p.rate diff --git a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_income_tax_consolidated.py b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_income_tax_consolidated.py new file mode 100644 index 00000000000..434b19908ba --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_income_tax_consolidated.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ia_income_tax_consolidated(Variable): + value_type = float + entity = TaxUnit + label = "Iowa income tax for years on or after 2023" + unit = USD + definition_period = YEAR + reference = ( + "https://revenue.iowa.gov/media/2746/download?inline", + "https://www.legis.iowa.gov/docs/code/422.7.pdf", + ) + defined_for = StateCode.IA + + def formula(tax_unit, period, parameters): + reg_tax = tax_unit("ia_regular_tax_consolidated", period) + alt_tax_eligible = tax_unit("ia_alternate_tax_eligible", period) + alt_tax = tax_unit("ia_alternate_tax_consolidated", period) + smaller_tax = min_(reg_tax, alt_tax) + return where(alt_tax_eligible, smaller_tax, reg_tax) diff --git a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.py b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.py new file mode 100644 index 00000000000..fa93d2668e8 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ia_regular_tax_consolidated(Variable): + value_type = float + entity = TaxUnit + label = "Iowa regular tax for years on or after 2023" + unit = USD + definition_period = YEAR + reference = "https://revenue.iowa.gov/media/2748/download?inline" + defined_for = StateCode.IA + + def formula(tax_unit, period, parameters): + taxable_income = tax_unit("ia_taxable_income_consolidated", period) + p = parameters(period).gov.states.ia.tax.income.rates + filing_status = tax_unit( + "filing_status", + period, + ) + joint = filing_status == filing_status.possible_values.JOINT + return where( + joint, + p.by_filing_status.joint.calc(taxable_income), + p.by_filing_status.other.calc(taxable_income), + ) diff --git a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_additions_consolidated.py b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_additions_consolidated.py new file mode 100644 index 00000000000..07d04ce5434 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_additions_consolidated.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ia_additions_consolidated(Variable): + value_type = float + entity = TaxUnit + label = "Iowa additions to taxable income for years on or after 2023" + unit = USD + definition_period = YEAR + reference = "https://www.legis.iowa.gov/docs/code/422.7.pdf" + defined_for = StateCode.IA + + adds = "gov.states.ia.tax.income.taxable_income.additions" diff --git a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_subtractions_consolidated.py b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_subtractions_consolidated.py new file mode 100644 index 00000000000..7909423d581 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_subtractions_consolidated.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ia_subtractions_consolidated(Variable): + value_type = float + entity = TaxUnit + label = "Iowa subtractions from taxable income for years on or after 2023" + unit = USD + definition_period = YEAR + reference = "https://www.legis.iowa.gov/docs/code/422.7.pdf" + defined_for = StateCode.IA + + adds = "gov.states.ia.tax.income.taxable_income.subtractions" diff --git a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_consolidated.py b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_consolidated.py new file mode 100644 index 00000000000..e67d7cf5c8e --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_consolidated.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ia_taxable_income_consolidated(Variable): + value_type = float + entity = TaxUnit + label = "Iowa taxable income for years on or after 2023" + unit = USD + definition_period = YEAR + reference = ( + "https://revenue.iowa.gov/media/2746/download?inline", + "https://www.legis.iowa.gov/docs/code/422.7.pdf", + ) + defined_for = StateCode.IA + + def formula(tax_unit, period, parameters): + fed_taxable_income = tax_unit("taxable_income", period) + modifications = tax_unit( + "ia_taxable_income_modifications_consolidated", period + ) + # Modifications include additions and subtractions + return max_(0, fed_taxable_income + modifications) diff --git a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_modifications_consolidated.py b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_modifications_consolidated.py new file mode 100644 index 00000000000..b0dd9c3ce3a --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/taxable_income/ia_taxable_income_modifications_consolidated.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ia_taxable_income_modifications_consolidated(Variable): + value_type = float + entity = TaxUnit + label = "Iowa modifications to taxable income for years on or after 2023" + unit = USD + definition_period = YEAR + reference = ( + "https://revenue.iowa.gov/media/2746/download?inline", + "https://www.legis.iowa.gov/docs/code/422.7.pdf", + ) + defined_for = StateCode.IA + + adds = ["ia_additions_consolidated"] + subtracts = ["ia_subtractions_consolidated"] diff --git a/policyengine_us/variables/gov/states/ia/tax/income/alternate_tax/ia_alternate_tax_eligible.py b/policyengine_us/variables/gov/states/ia/tax/income/ia_alternate_tax_eligible.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/alternate_tax/ia_alternate_tax_eligible.py rename to policyengine_us/variables/gov/states/ia/tax/income/ia_alternate_tax_eligible.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_income_tax_before_credits.py b/policyengine_us/variables/gov/states/ia/tax/income/ia_income_tax_before_credits.py index aed67f628a4..901c67130fa 100644 --- a/policyengine_us/variables/gov/states/ia/tax/income/ia_income_tax_before_credits.py +++ b/policyengine_us/variables/gov/states/ia/tax/income/ia_income_tax_before_credits.py @@ -16,8 +16,14 @@ class ia_income_tax_before_credits(Variable): defined_for = StateCode.IA def formula(tax_unit, period, parameters): - return where( - tax_unit("ia_files_separately", period), - tax_unit("ia_income_tax_indiv", period), - tax_unit("ia_income_tax_joint", period), - ) + p = parameters( + period + ).gov.states.ia.tax.income.married_filing_separately_on_same_return + if p.availability: + return where( + tax_unit("ia_files_separately", period), + tax_unit("ia_income_tax_indiv", period), + tax_unit("ia_income_tax_joint", period), + ) + else: + return tax_unit("ia_income_tax_consolidated", period) diff --git a/policyengine_us/variables/gov/states/ia/tax/income/alternate_tax/ia_alternate_tax_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/alternate_tax/ia_alternate_tax_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/alternate_tax/ia_alternate_tax_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/alternate_tax/ia_alternate_tax_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/alternate_tax/ia_alternate_tax_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/alternate_tax/ia_alternate_tax_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/alternate_tax/ia_alternate_tax_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/alternate_tax/ia_alternate_tax_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/alternate_tax/ia_alternate_tax_unit.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/alternate_tax/ia_alternate_tax_unit.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/alternate_tax/ia_alternate_tax_unit.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/alternate_tax/ia_alternate_tax_unit.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_basic_deduction_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_basic_deduction_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_basic_deduction_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_basic_deduction_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_basic_deduction_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_basic_deduction_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_basic_deduction_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_basic_deduction_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_fedtax_deduction.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_fedtax_deduction.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_fedtax_deduction.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_fedtax_deduction.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_itemized_deductions_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_itemized_deductions_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_itemized_deductions_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_itemized_deductions_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_itemized_deductions_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_itemized_deductions_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_itemized_deductions_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_itemized_deductions_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_itemized_deductions_unit.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_itemized_deductions_unit.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_itemized_deductions_unit.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_itemized_deductions_unit.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_qbi_deduction.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_qbi_deduction.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_qbi_deduction.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_qbi_deduction.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_standard_deduction_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_standard_deduction_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_standard_deduction_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_standard_deduction_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_standard_deduction_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_standard_deduction_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/deductions/ia_standard_deduction_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/deductions/ia_standard_deduction_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_amt_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_amt_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_amt_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_amt_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_amt_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_amt_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_amt_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_amt_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_base_tax_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_base_tax_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_base_tax_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_base_tax_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_base_tax_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_base_tax_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_base_tax_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_base_tax_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_income_tax_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_income_tax_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_income_tax_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_income_tax_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_income_tax_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_income_tax_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_income_tax_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_income_tax_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_regular_tax_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_regular_tax_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_regular_tax_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_regular_tax_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_regular_tax_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_regular_tax_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_regular_tax_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_regular_tax_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_taxable_income_indiv.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_taxable_income_indiv.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_taxable_income_indiv.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_taxable_income_indiv.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/ia_taxable_income_joint.py b/policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_taxable_income_joint.py similarity index 100% rename from policyengine_us/variables/gov/states/ia/tax/income/ia_taxable_income_joint.py rename to policyengine_us/variables/gov/states/ia/tax/income/including_married_filing_separately/ia_taxable_income_joint.py diff --git a/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py b/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py index 77963379664..803429fa11d 100644 --- a/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py +++ b/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py @@ -19,7 +19,6 @@ def formula(person, period, parameters): # ... determine age eligibility age = person("age", period) age_eligible = age >= p.minimum_age - head_or_spouse_age_eligible = is_head_or_spouse & age_eligible # ... determine disability eligiblity is_disabled = person("is_permanently_and_totally_disabled", period) is_disabled_head_or_spouse = is_head_or_spouse & is_disabled From 16f3f33da2e1558bd94cb372d800b47b3725da17 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 29 Jan 2025 13:48:32 +0100 Subject: [PATCH 2/4] reference and test --- .../ia/tax/income/alternate_tax/rate.yaml | 2 ++ .../tax/income/modified_income/sources.yaml | 3 ++- .../income/ia_income_tax_before_credits.yaml | 27 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/rate.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/rate.yaml index 99df1a0677c..89ed528fc18 100644 --- a/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/rate.yaml +++ b/policyengine_us/parameters/gov/states/ia/tax/income/alternate_tax/rate.yaml @@ -16,3 +16,5 @@ metadata: href: https://tax.iowa.gov/sites/default/files/2023-01/2022IA1040%2841001%29.pdf#page=1 - title: 2022 IA1040 Income Tax Return instructions href: https://tax.iowa.gov/sites/default/files/2023-03/2022%20Expanded%20Instructions_022023.pdf#page=54 + - title: 2023 Iowa Alternate Tax Worksheet + href: https://revenue.iowa.gov/media/2754/download?inline diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/modified_income/sources.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/modified_income/sources.yaml index ff0dac2ece9..79ddc79ceb7 100644 --- a/policyengine_us/parameters/gov/states/ia/tax/income/modified_income/sources.yaml +++ b/policyengine_us/parameters/gov/states/ia/tax/income/modified_income/sources.yaml @@ -22,4 +22,5 @@ metadata: href: https://tax.iowa.gov/sites/default/files/2023-01/2022IA1040%2841001%29.pdf#page=1 - title: 2022 IA1040 Income Tax Return instructions href: https://tax.iowa.gov/sites/default/files/2023-03/2022%20Expanded%20Instructions_022023.pdf#page=37 - + - title: 2023 Iowa Alternate Tax Worksheet + href: https://revenue.iowa.gov/media/2754/download?inline diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_income_tax_before_credits.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_income_tax_before_credits.yaml index 65ab4788301..29dcbb68318 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_income_tax_before_credits.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_income_tax_before_credits.yaml @@ -49,3 +49,30 @@ state_code: IA output: ia_income_tax_before_credits: 1_500 + +- name: Post 2023, only the consolidated structure applies + period: 2023 + input: + people: + person1: + is_tax_unit_head: true + ia_base_tax_indiv: 700 + ia_amt_indiv: 100 + ia_base_tax_joint: 1_500 + ia_amt_joint: 50 + person2: + is_tax_unit_spouse: true + ia_base_tax_indiv: 600 + ia_amt_indiv: 100 + ia_base_tax_joint: 0 + ia_amt_joint: 0 + tax_units: + tax_unit: + members: [person1, person2] + ia_income_tax_consolidated: 4_000 + households: + household: + members: [person1, person2] + state_code: IA + output: + ia_income_tax_before_credits: 4_000 From 92306bb3eaaaa8916a2f0abbf9ab1a27f00ebd7d Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 29 Jan 2025 14:44:34 +0100 Subject: [PATCH 3/4] pension exclusion fix --- .../income/ia_pension_exclusion_eligible.yaml | 18 ++++++++++++++++++ .../ia_regular_tax_consolidated.py | 5 +---- .../ia_pension_exclusion_eligible.py | 3 ++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_pension_exclusion_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_pension_exclusion_eligible.yaml index d41f7682fa1..96cd09382a0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_pension_exclusion_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/ia_pension_exclusion_eligible.yaml @@ -116,3 +116,21 @@ state_code: IA output: ia_pension_exclusion_eligible: [true, true] + +- name: Only person who meets the age requirement is not a head or spouse + period: 2023 + input: + people: + person1: + age: 54 + person2: + age: 54 + person3: + age: 70 + is_tax_unit_head_or_spouse: false + households: + household: + members: [person1, person2, person3] + state_code: IA + output: + ia_pension_exclusion_eligible: [false, false, false] diff --git a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.py b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.py index fa93d2668e8..7e894c0eefa 100644 --- a/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.py +++ b/policyengine_us/variables/gov/states/ia/tax/income/consolidated/ia_regular_tax_consolidated.py @@ -13,10 +13,7 @@ class ia_regular_tax_consolidated(Variable): def formula(tax_unit, period, parameters): taxable_income = tax_unit("ia_taxable_income_consolidated", period) p = parameters(period).gov.states.ia.tax.income.rates - filing_status = tax_unit( - "filing_status", - period, - ) + filing_status = tax_unit("filing_status", period) joint = filing_status == filing_status.possible_values.JOINT return where( joint, diff --git a/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py b/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py index 803429fa11d..e3c19c6be5b 100644 --- a/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py +++ b/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py @@ -19,7 +19,8 @@ def formula(person, period, parameters): # ... determine age eligibility age = person("age", period) age_eligible = age >= p.minimum_age + head_or_spouse_age_eligible = is_head_or_spouse & age_eligible # ... determine disability eligiblity is_disabled = person("is_permanently_and_totally_disabled", period) is_disabled_head_or_spouse = is_head_or_spouse & is_disabled - return age_eligible | is_disabled_head_or_spouse + return head_or_spouse_age_eligible | is_disabled_head_or_spouse From eb7ccc4113972b3e8120d5a01251b72e8adef0fc Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 29 Jan 2025 15:39:53 +0100 Subject: [PATCH 4/4] minor --- .../tax/income/net_income/ia_pension_exclusion_eligible.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py b/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py index e3c19c6be5b..1743ba445c5 100644 --- a/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py +++ b/policyengine_us/variables/gov/states/ia/tax/income/net_income/ia_pension_exclusion_eligible.py @@ -14,13 +14,8 @@ class ia_pension_exclusion_eligible(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.ia.tax.income.pension_exclusion - # determine eligibility for pension exclusion is_head_or_spouse = person("is_tax_unit_head_or_spouse", period) - # ... determine age eligibility age = person("age", period) age_eligible = age >= p.minimum_age - head_or_spouse_age_eligible = is_head_or_spouse & age_eligible - # ... determine disability eligiblity is_disabled = person("is_permanently_and_totally_disabled", period) - is_disabled_head_or_spouse = is_head_or_spouse & is_disabled - return head_or_spouse_age_eligible | is_disabled_head_or_spouse + return is_head_or_spouse & (age_eligible | is_disabled)