diff --git a/changelog.d/fix-state-head-fallbacks.fixed.md b/changelog.d/fix-state-head-fallbacks.fixed.md new file mode 100644 index 00000000000..061b1b2b93b --- /dev/null +++ b/changelog.d/fix-state-head-fallbacks.fixed.md @@ -0,0 +1 @@ +Montana itemized deductions count only federally deductible mortgage interest, so interest on acquisition debt above the IRC 163(h)(3) caps is no longer deducted. The Virginia EITC reports the credit the tax applies for spouses filing separately, not only the share of the spouse listed as head. Maryland's two-income subtraction gives each spouse their own losses and deductions when the couple has no gross income, instead of giving all of them to the head. diff --git a/changelog.d/fix-state-head-fallbacks.removed.md b/changelog.d/fix-state-head-fallbacks.removed.md new file mode 100644 index 00000000000..8e41282ac40 --- /dev/null +++ b/changelog.d/fix-state-head-fallbacks.removed.md @@ -0,0 +1 @@ +Removed `va_eitc_person` and `va_agi_share`, which fed only the head-share branch of `va_eitc`; `va_eitc` now reports the tax unit's applied Virginia EITC for every filing status. diff --git a/policyengine_us/tests/code_health/test_non_refundable_credit_downstream_consumers.py b/policyengine_us/tests/code_health/test_non_refundable_credit_downstream_consumers.py index 6b769d9b02e..d4f8dce8cd5 100644 --- a/policyengine_us/tests/code_health/test_non_refundable_credit_downstream_consumers.py +++ b/policyengine_us/tests/code_health/test_non_refundable_credit_downstream_consumers.py @@ -78,7 +78,6 @@ "va_non_refundable_eitc": { "variables/gov/states/va/tax/income/credits/eitc/refundability_calculation/va_income_tax_if_claiming_non_refundable_eitc.py", "variables/gov/states/va/tax/income/credits/eitc/va_eitc.py", - "variables/gov/states/va/tax/income/credits/eitc/va_eitc_person.py", }, } diff --git a/policyengine_us/tests/core/test_mt_mortgage_interest_federal_limit_properties.py b/policyengine_us/tests/core/test_mt_mortgage_interest_federal_limit_properties.py new file mode 100644 index 00000000000..17700756dd7 --- /dev/null +++ b/policyengine_us/tests/core/test_mt_mortgage_interest_federal_limit_properties.py @@ -0,0 +1,157 @@ +"""Montana's itemized mortgage interest is the amount federal law allows. + +Former MCA 15-30-2131(1)(a) allowed the items in 26 U.S.C. 161 (which +includes section 163 interest), and MCA 15-30-2101 reads "Internal Revenue +Code" as the Code as amended. The Form 2 instructions for itemized deductions +line 9 (2018-2023) say to enter the home mortgage interest "allowed by federal +law" and that interest on acquisition debt incurred after Dec. 15, 2017 "is +limited to the first $750,000". From 2024 Montana starts from the federal +itemized deductions. So interest on acquisition debt above the 26 U.S.C. +163(h)(3) caps is never a Montana deduction. + +A grid of couples with one acquisition mortgage (balance, origination year, +interest) shares one simulation per year. The other Montana itemized +components are set to zero so each variable is its mortgage interest line, +and the federal limit is restated here independently of the parameter files: +$1,000,000 of debt incurred before the TCJA date ($750,000 after), with +interest prorated by the share of the balance under the cap. PolicyEngine +approximates the Dec. 15, 2017 date by origination year 2017, and treats a +mortgage with no reported balance as fully deductible; the restatement uses +the same input conventions. + +1. Joint returns (every year): the Montana joint itemized deductions, and the + variant used for the federal itemization choice, equal the allowed amount. +2. Spouses filing separately on the same form (through 2023): each spouse's + deduction is the allowed amount times the share of the interest that + spouse reported, and the two sum to the allowed amount. + +The YAML cases check single points of this rule. The grid checks it for every +combination of balance, origination year, interest, the spouse's share, year +and filing path against the restatement above, so a change in the caps, the +grandfathering year, the proration or the spouse split is caught wherever it +binds. +""" + +from itertools import product + +import numpy as np +import pytest + +from policyengine_us import Simulation + +YEARS = range(2021, 2027) +# Montana ended filing separately on the same form from tax year 2024 (SB 399 +# of 2021; see the references in +# married_filing_separately_on_same_return_allowed.yaml). +LAST_SEPARATE_ON_SAME_FORM_YEAR = 2023 +BALANCES = (0, 300_000, 750_000, 1_000_000, 2_500_000) +ORIGINATION_YEARS = (2005, 2017, 2018, 2024) +INTERESTS = (0, 15_000, 40_000) +SPOUSE_SHARES = (0.0, 0.25) # share of the interest the spouse reported +UNITS = tuple(product(BALANCES, ORIGINATION_YEARS, INTERESTS, SPOUSE_SHARES)) + +ZERO_PERSON_COMPONENTS = ( + "mt_misc_deductions", + "mt_medical_expense_deduction_joint", + "mt_medical_expense_deduction_indiv", + "mt_salt_deduction", + "mt_federal_income_tax_deduction_indiv", + "mt_federal_income_tax_deduction_for_federal_itemization_indiv", +) +ZERO_TAX_UNIT_COMPONENTS = ( + "charitable_deduction", + "mt_federal_income_tax_deduction_unit", + "mt_federal_income_tax_deduction_for_federal_itemization", +) + + +def allowed_interest(interest, balance, origination_year): + """Home mortgage interest allowed under 26 U.S.C. 163(h)(3).""" + if balance == 0: + return interest + cap = 1_000_000 if origination_year <= 2017 else 750_000 + return interest * min(1, cap / balance) + + +def _situation(year): + period = str(year) + people, tax_units, households, marital_units = {}, {}, {}, {} + for i, (balance, origination, interest, spouse_share) in enumerate(UNITS): + head, spouse = f"u{i}_head", f"u{i}_spouse" + for name, role, share in ( + (head, "is_tax_unit_head", 1 - spouse_share), + (spouse, "is_tax_unit_spouse", spouse_share), + ): + people[name] = { + "age": {period: 50}, + role: {period: True}, + "home_mortgage_interest": {period: interest * share}, + **{v: {period: 0} for v in ZERO_PERSON_COMPONENTS}, + } + members = [head, spouse] + tax_units[f"u{i}"] = { + "members": members, + "first_home_mortgage_balance": {period: balance}, + "first_home_mortgage_origination_year": {period: origination}, + **{v: {period: 0} for v in ZERO_TAX_UNIT_COMPONENTS}, + } + households[f"u{i}"] = {"members": members, "state_code": {period: "MT"}} + marital_units[f"u{i}"] = {"members": members} + return { + "people": people, + "tax_units": tax_units, + "households": households, + "marital_units": marital_units, + } + + +@pytest.mark.parametrize("year", YEARS) +def test_montana_mortgage_interest_is_the_federally_allowed_amount(year): + sim = Simulation(situation=_situation(year)) + + def per_person(variable): + return np.asarray(sim.calculate(variable, year), dtype=float).reshape(-1, 2) + + allowed = np.array( + [ + allowed_interest(interest, balance, origination) + for balance, origination, interest, _ in UNITS + ] + ) + spouse_share = np.array([unit[3] for unit in UNITS]) + + # 1. Joint returns. The head-only units (spouse share 0) keep this check + # independent of how the joint formula splits interest between spouses. + head_only = spouse_share == 0 + for variable in ( + "mt_itemized_deductions_joint", + "mt_itemized_deductions_for_federal_itemization_joint", + ): + np.testing.assert_allclose( + per_person(variable).sum(axis=1)[head_only], + allowed[head_only], + atol=0.01, + err_msg=f"{variable} in {year}", + ) + + # 2. Spouses filing separately on the same form, through 2023. Check the + # model's switch against that boundary, so turning it off by mistake + # fails here rather than skipping these checks. + p = sim.tax_benefit_system.parameters(year).gov.states.mt.tax.income + separate_allowed = year <= LAST_SEPARATE_ON_SAME_FORM_YEAR + assert bool(p.married_filing_separately_on_same_return_allowed) == ( + separate_allowed + ) + if not separate_allowed: + return + expected = np.stack([allowed * (1 - spouse_share), allowed * spouse_share], 1) + for variable in ( + "mt_itemized_deductions_indiv", + "mt_itemized_deductions_for_federal_itemization_indiv", + ): + np.testing.assert_allclose( + per_person(variable), + expected, + atol=0.01, + err_msg=f"{variable} in {year}", + ) diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/tax/income/agi/subtractions/md_two_income_subtraction.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/tax/income/agi/subtractions/md_two_income_subtraction.yaml new file mode 100644 index 00000000000..0fdd8ccf8d0 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/tax/income/agi/subtractions/md_two_income_subtraction.yaml @@ -0,0 +1,291 @@ +# Worksheet 13D (2025 resident booklet, p. 18) adds each spouse's portion of +# federal AGI (line 1) and of the Maryland additions (line 2), subtracts each +# spouse's subtractions (line 4), and takes the smaller result, at least zero +# and at most $1,200. In these couples neither spouse has gross income, so +# their federal AGI is their own losses and deductions. md_total_additions is +# an input (it has no formula); the formula splits it equally, as in a couple +# who each own half of it. + +- name: Both spouses have losses, so each keeps their own + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 45 + is_tax_unit_head: true + self_employment_income: -20_000 + spouse: + age: 45 + is_tax_unit_spouse: true + self_employment_income: -20_000 + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 70_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + # Line 5 for each spouse: -20,000 + 35,000 = 15,000. Line 7: the + # smaller, 15,000, capped at 1,200. + adjusted_gross_income: -40_000 + md_two_income_subtraction: 1_200 + +- name: One spouse has the whole loss + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 45 + is_tax_unit_head: true + spouse: + age: 45 + is_tax_unit_spouse: true + self_employment_income: -10_000 + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 12_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + # Line 5: head 0 + 6,000 = 6,000; spouse -10,000 + 6,000 = -4,000. + # Line 6: the smaller, not less than zero, is 0. + md_two_income_subtraction: 0 + +- name: The same couple with the head and spouse labels exchanged + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 45 + is_tax_unit_head: true + self_employment_income: -10_000 + spouse: + age: 45 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 12_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + md_two_income_subtraction: 0 + +- name: One spouse paid all the student loan interest + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 30 + is_tax_unit_head: true + student_loan_interest: 2_000 + spouse: + age: 30 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 6_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + # Line 5: head -2,000 + 3,000 = 1,000; spouse 0 + 3,000 = 3,000. + adjusted_gross_income: -2_000 + md_two_income_subtraction: 1_000 + +- name: Each spouse keeps their own allowed loss when a capital loss exceeds the limit + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 45 + is_tax_unit_head: true + long_term_capital_gains: -100_000 + spouse: + age: 45 + is_tax_unit_spouse: true + self_employment_income: -20_000 + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 40_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + # Federal AGI is -23,000: the $20,000 business loss and $3,000 of the + # capital loss (26 U.S.C. 1211(b)). Line 5: head -3,000 + 20,000 = + # 17,000; spouse -20,000 + 20,000 = 0. Line 6: 0. + adjusted_gross_income: -23_000 + md_two_income_subtraction: 0 + +- name: The same couple with the head and spouse labels exchanged + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 45 + is_tax_unit_head: true + self_employment_income: -20_000 + spouse: + age: 45 + is_tax_unit_spouse: true + long_term_capital_gains: -100_000 + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 40_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + md_two_income_subtraction: 0 + +- name: A deduction recorded only for the tax unit is split equally + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 30 + is_tax_unit_head: true + student_loan_interest: 2_000 + spouse: + age: 30 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + health_savings_account_ald: 2_000 + md_total_additions: 7_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + # Federal AGI is -4,000. The head's own student loan interest is the + # head's; the HSA deduction is recorded only for the tax unit, so each + # spouse takes half. Line 5: head -2,000 - 1,000 + 3,500 = 500; spouse + # -1,000 + 3,500 = 2,500. Line 6: 500. + adjusted_gross_income: -4_000 + md_two_income_subtraction: 500 + +- name: Deductible alimony paid by one spouse is that spouse's + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 50 + is_tax_unit_head: true + alimony_expense: 2_000 + divorce_year: 2018 + spouse: + age: 50 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 6_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + # Line 5: head -2,000 + 3,000 = 1,000; spouse 3,000. An equal split of + # the alimony deduction would give 2,000 each and the $1,200 cap. + adjusted_gross_income: -2_000 + md_two_income_subtraction: 1_000 + +- name: The same alimony couple with the head and spouse labels exchanged + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 50 + is_tax_unit_head: true + spouse: + age: 50 + is_tax_unit_spouse: true + alimony_expense: 2_000 + divorce_year: 2018 + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 6_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + md_two_income_subtraction: 1_000 + +- name: Educator expenses are the educator's + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + is_tax_unit_head: true + spouse: + age: 40 + is_tax_unit_spouse: true + educator_expense: 300 + tax_units: + tax_unit: + members: [head, spouse] + md_total_additions: 1_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + # Line 5: head 500; spouse -300 + 500 = 200. + adjusted_gross_income: -300 + md_two_income_subtraction: 200 + +- name: An HSA deduction with a recorded owner is that spouse's + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 30 + is_tax_unit_head: true + spouse: + age: 30 + is_tax_unit_spouse: true + student_loan_interest: 2_000 + health_savings_account_ald_person: 2_000 + tax_units: + tax_unit: + members: [head, spouse] + health_savings_account_ald: 2_000 + md_total_additions: 7_000 + households: + household: + members: [head, spouse] + state_code: MD + output: + # Line 5: head 3,500; spouse -2,000 - 2,000 + 3,500 = -500. Line 6: 0. + adjusted_gross_income: -4_000 + md_two_income_subtraction: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_indiv.yaml index 4435e64a801..291bb803808 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_indiv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_indiv.yaml @@ -30,7 +30,7 @@ period: 2021 input: charitable_deduction: 1_000 - mortgage_interest: 34 + deductible_mortgage_interest: 34 mt_salt_deduction: 1_035 mt_medical_expense_deduction_indiv: 3_000 casualty_loss_deduction: 745 @@ -74,3 +74,44 @@ state_code: MT output: mt_itemized_deductions_for_federal_itemization_indiv: [1_000, 700, 0] + +- name: Spouses filing separately on the same form split the federally capped mortgage interest of their joint federal return + period: 2022 + absolute_error_margin: 0.01 + input: + people: + head: + is_tax_unit_head: true + home_mortgage_interest: 30_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_indiv: 0 + mt_salt_deduction: 0 + mt_federal_income_tax_deduction_for_federal_itemization_indiv: 0 + spouse: + is_tax_unit_spouse: true + home_mortgage_interest: 10_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_indiv: 0 + mt_salt_deduction: 0 + mt_federal_income_tax_deduction_for_federal_itemization_indiv: 0 + tax_units: + tax_unit: + members: [head, spouse] + first_home_mortgage_balance: 1_000_000 + first_home_mortgage_origination_year: 2019 + charitable_deduction: 0 + filing_status: JOINT + households: + household: + members: [head, spouse] + state_code: MT + output: + # $30,000 of the $40,000 interest is allowed by federal law on the joint + # federal return (the $750,000 cap on $1,000,000 of post-2017 debt). + # Each spouse reported a share of the interest and deducts that share + # of the allowed amount. No Montana source says whether spouses filing + # separately on the same form each get the $375,000 separate cap; the + # instructions let them split jointly paid expenses in any proportion + # (2023 Form 2 instructions, p. 13), so the joint federal amount is used. + deductible_mortgage_interest: [22_500, 7_500] + mt_itemized_deductions_for_federal_itemization_indiv: [22_500, 7_500] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_joint.yaml index 8a1114f4ef5..85519179428 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_joint.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_joint.yaml @@ -18,7 +18,7 @@ input: filing_status: HEAD_OF_HOUSEHOLD charitable_deduction: 0 - mortgage_interest: 1_234 + deductible_mortgage_interest: 1_234 mt_salt_deduction: 10_000 mt_medical_expense_deduction_joint: 3_000 casualty_loss_deduction: 0 @@ -33,7 +33,7 @@ input: filing_status: SINGLE charitable_deduction: 1_000 - mortgage_interest: 34 + deductible_mortgage_interest: 34 mt_salt_deduction: 1_035 mt_medical_expense_deduction_joint: 3_000 casualty_loss_deduction: 745 @@ -74,3 +74,99 @@ mt_federal_income_tax_deduction_for_federal_itemization: 600 output: mt_itemized_deductions_for_federal_itemization_joint: [2_212, 0, 0] + +- name: Mortgage interest on post-2017 debt above the federal cap is not deductible + period: 2022 + absolute_error_margin: 0.01 + input: + people: + head: + is_tax_unit_head: true + home_mortgage_interest: 40_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + spouse: + is_tax_unit_spouse: true + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [head, spouse] + first_home_mortgage_balance: 1_000_000 + first_home_mortgage_origination_year: 2019 + charitable_deduction: 0 + mt_federal_income_tax_deduction_for_federal_itemization: 0 + households: + household: + members: [head, spouse] + state_code: MT + output: + # $750,000 of the $1,000,000 acquisition debt incurred after Dec. 15, + # 2017 qualifies, so $30,000 of the $40,000 interest is allowed by + # federal law and in Montana (2022 Form 2 instructions, line 9). + deductible_mortgage_interest: [30_000, 0] + mt_itemized_deductions_for_federal_itemization_joint: [30_000, 0] + +- name: Mortgage interest on pre-2018 debt keeps the $1,000,000 cap + period: 2022 + absolute_error_margin: 0.01 + input: + people: + head: + is_tax_unit_head: true + home_mortgage_interest: 40_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + spouse: + is_tax_unit_spouse: true + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [head, spouse] + first_home_mortgage_balance: 1_000_000 + first_home_mortgage_origination_year: 2016 + charitable_deduction: 0 + mt_federal_income_tax_deduction_for_federal_itemization: 0 + households: + household: + members: [head, spouse] + state_code: MT + output: + # Debt incurred before Dec. 16, 2017 keeps the $1,000,000 cap, so all + # $40,000 is allowed. + deductible_mortgage_interest: [40_000, 0] + mt_itemized_deductions_for_federal_itemization_joint: [40_000, 0] + +- name: A federal separate return uses the $375,000 cap + period: 2022 + absolute_error_margin: 0.01 + input: + people: + filer: + is_tax_unit_head: true + home_mortgage_interest: 40_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [filer] + filing_status: SEPARATE + first_home_mortgage_balance: 1_000_000 + first_home_mortgage_origination_year: 2019 + charitable_deduction: 0 + mt_federal_income_tax_deduction_for_federal_itemization: 0 + households: + household: + members: [filer] + state_code: MT + output: + # 26 U.S.C. 163(h)(3)(F)(i)(II): $375,000 for a married individual + # filing a separate return, so $15,000 of the $40,000 is allowed. + deductible_mortgage_interest: 15_000 + mt_itemized_deductions_for_federal_itemization_joint: 15_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_itemized_deductions_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_itemized_deductions_indiv.yaml index 2bc390f8ad3..ac0685090a1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_itemized_deductions_indiv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_itemized_deductions_indiv.yaml @@ -30,7 +30,7 @@ period: 2021 input: charitable_deduction: 1_000 - mortgage_interest: 34 + deductible_mortgage_interest: 34 mt_salt_deduction: 1_035 mt_medical_expense_deduction_indiv: 3_000 casualty_loss_deduction: 745 @@ -74,3 +74,44 @@ state_code: MT output: mt_itemized_deductions_indiv: [1_000, 700, 0] + +- name: Spouses filing separately on the same form split the federally capped mortgage interest of their joint federal return + period: 2022 + absolute_error_margin: 0.01 + input: + people: + head: + is_tax_unit_head: true + home_mortgage_interest: 30_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_indiv: 0 + mt_salt_deduction: 0 + mt_federal_income_tax_deduction_indiv: 0 + spouse: + is_tax_unit_spouse: true + home_mortgage_interest: 10_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_indiv: 0 + mt_salt_deduction: 0 + mt_federal_income_tax_deduction_indiv: 0 + tax_units: + tax_unit: + members: [head, spouse] + first_home_mortgage_balance: 1_000_000 + first_home_mortgage_origination_year: 2019 + charitable_deduction: 0 + filing_status: JOINT + households: + household: + members: [head, spouse] + state_code: MT + output: + # $30,000 of the $40,000 interest is allowed by federal law on the joint + # federal return (the $750,000 cap on $1,000,000 of post-2017 debt). + # Each spouse reported a share of the interest and deducts that share + # of the allowed amount. No Montana source says whether spouses filing + # separately on the same form each get the $375,000 separate cap; the + # instructions let them split jointly paid expenses in any proportion + # (2023 Form 2 instructions, p. 13), so the joint federal amount is used. + deductible_mortgage_interest: [22_500, 7_500] + mt_itemized_deductions_indiv: [22_500, 7_500] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_itemized_deductions_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_itemized_deductions_joint.yaml index 6b25795e07a..8289ef0c24c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_itemized_deductions_joint.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_itemized_deductions_joint.yaml @@ -18,7 +18,7 @@ input: filing_status: HEAD_OF_HOUSEHOLD charitable_deduction: 0 - mortgage_interest: 1_234 + deductible_mortgage_interest: 1_234 mt_salt_deduction: 10_000 mt_medical_expense_deduction_joint: 3_000 casualty_loss_deduction: 0 @@ -33,7 +33,7 @@ input: filing_status: SINGLE charitable_deduction: 1_000 - mortgage_interest: 34 + deductible_mortgage_interest: 34 mt_salt_deduction: 1_035 mt_medical_expense_deduction_joint: 3_000 casualty_loss_deduction: 745 @@ -74,3 +74,99 @@ mt_federal_income_tax_deduction_unit: 600 output: mt_itemized_deductions_joint: [2_212, 0, 0] + +- name: Mortgage interest on post-2017 debt above the federal cap is not deductible + period: 2022 + absolute_error_margin: 0.01 + input: + people: + head: + is_tax_unit_head: true + home_mortgage_interest: 40_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + spouse: + is_tax_unit_spouse: true + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [head, spouse] + first_home_mortgage_balance: 1_000_000 + first_home_mortgage_origination_year: 2019 + charitable_deduction: 0 + mt_federal_income_tax_deduction_unit: 0 + households: + household: + members: [head, spouse] + state_code: MT + output: + # $750,000 of the $1,000,000 acquisition debt incurred after Dec. 15, + # 2017 qualifies, so $30,000 of the $40,000 interest is allowed by + # federal law and in Montana (2022 Form 2 instructions, line 9). + deductible_mortgage_interest: [30_000, 0] + mt_itemized_deductions_joint: [30_000, 0] + +- name: Mortgage interest on pre-2018 debt keeps the $1,000,000 cap + period: 2022 + absolute_error_margin: 0.01 + input: + people: + head: + is_tax_unit_head: true + home_mortgage_interest: 40_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + spouse: + is_tax_unit_spouse: true + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [head, spouse] + first_home_mortgage_balance: 1_000_000 + first_home_mortgage_origination_year: 2016 + charitable_deduction: 0 + mt_federal_income_tax_deduction_unit: 0 + households: + household: + members: [head, spouse] + state_code: MT + output: + # Debt incurred before Dec. 16, 2017 keeps the $1,000,000 cap, so all + # $40,000 is allowed. + deductible_mortgage_interest: [40_000, 0] + mt_itemized_deductions_joint: [40_000, 0] + +- name: A federal separate return uses the $375,000 cap + period: 2022 + absolute_error_margin: 0.01 + input: + people: + filer: + is_tax_unit_head: true + home_mortgage_interest: 40_000 + mt_misc_deductions: 0 + mt_medical_expense_deduction_joint: 0 + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [filer] + filing_status: SEPARATE + first_home_mortgage_balance: 1_000_000 + first_home_mortgage_origination_year: 2019 + charitable_deduction: 0 + mt_federal_income_tax_deduction_unit: 0 + households: + household: + members: [filer] + state_code: MT + output: + # 26 U.S.C. 163(h)(3)(F)(i)(II): $375,000 for a married individual + # filing a separate return, so $15,000 of the $40,000 is allowed. + deductible_mortgage_interest: 15_000 + mt_itemized_deductions_joint: 15_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/eitc/va_eitc.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/eitc/va_eitc.yaml index f058dd918c1..31a057b6f5c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/eitc/va_eitc.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/eitc/va_eitc.yaml @@ -39,16 +39,16 @@ output: va_eitc: 100 -- name: Prorated eitc for the head of the tax unit +- name: Spouses filing separately in one tax unit report the whole credit the tax applies period: 2021 input: people: person1: - va_eitc_person: 1_000 is_tax_unit_head: true + employment_income: 9_000 person2: - va_eitc_person: 500 - is_tax_unit_head: false + is_tax_unit_spouse: true + employment_income: 3_000 tax_units: tax_unit: members: [person1, person2] @@ -61,4 +61,61 @@ members: [person1, person2] state_code: VA output: - va_eitc: 1_000 + # The spouses split the Virginia EIC by their shares of the earned income + # used for the federal EITC and claim those shares on their two separate + # returns, and only one of them may claim the Credit for Low-Income + # Individuals (2021 Form 760 instructions, p. 32). The tax unit holds both + # returns, so va_eitc reports the credit its tax applies, the sum of the + # shares, whichever spouse is listed first. The credit amounts are inputs. + va_eitc: 100 + +- name: The same couple with the head and spouse labels exchanged + period: 2021 + input: + people: + person1: + is_tax_unit_spouse: true + employment_income: 9_000 + person2: + is_tax_unit_head: true + employment_income: 3_000 + tax_units: + tax_unit: + members: [person1, person2] + va_refundable_eitc: 0 + va_non_refundable_eitc: 100 + va_claims_refundable_eitc: false + filing_status: SEPARATE + households: + household: + members: [person1, person2] + state_code: VA + output: + va_eitc: 100 + +- name: A separate filer's credit does not depend on a dependent's Virginia subtractions + period: 2024 + input: + people: + parent: + is_tax_unit_head: true + age: 40 + employment_income: 12_000 + child: + is_tax_unit_dependent: true + age: 19 + is_full_time_student: true + unemployment_compensation: 4_000 + tax_units: + tax_unit: + members: [parent, child] + va_refundable_eitc: 600 + va_non_refundable_eitc: 15 + va_claims_refundable_eitc: true + filing_status: SEPARATE + households: + household: + members: [parent, child] + state_code: VA + output: + va_eitc: 600 diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/eitc/va_eitc_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/eitc/va_eitc_person.yaml deleted file mode 100644 index 60883139865..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/eitc/va_eitc_person.yaml +++ /dev/null @@ -1,63 +0,0 @@ -- name: Claims refundable eitc. - period: 2021 - input: - va_refundable_eitc: 800 - va_non_refundable_eitc: 400 - va_claims_refundable_eitc: true - va_agi_share: 0.8 - state_code: VA - output: - va_eitc_person: 640 - -- name: Claims refundable eitc. - period: 2021 - input: - people: - p1: - va_agi_share: 0.8 - p2: - va_agi_share: 0.2 - tax_units: - tax_unit: - members: [p1, p2] - va_refundable_eitc: 800 - va_non_refundable_eitc: 400 - va_claims_refundable_eitc: true - households: - household: - members: [p1, p2] - state_code: VA - output: - va_eitc_person: [640, 160] - -- name: Claims non-refundable eitc. - period: 2021 - input: - va_refundable_eitc: 50 - va_non_refundable_eitc: 100 - va_claims_refundable_eitc: false - va_agi_share: 0.8 - state_code: VA - output: - va_eitc_person: 80 - -- name: Claims refundable eitc. - period: 2021 - input: - people: - p1: - va_agi_share: 0.8 - p2: - va_agi_share: 0.2 - tax_units: - tax_unit: - members: [p1, p2] - va_refundable_eitc: 50 - va_non_refundable_eitc: 100 - va_claims_refundable_eitc: false - households: - household: - members: [p1, p2] - state_code: VA - output: - va_eitc_person: [80, 20] diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/va_agi_share.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/va_agi_share.yaml deleted file mode 100644 index e64b54f52e6..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/va_agi_share.yaml +++ /dev/null @@ -1,40 +0,0 @@ -- name: Positive income for both the head and the spouse in the household. - period: 2021 - input: - people: - person1: - is_tax_unit_head: true - age: 40 - va_agi_person: 200 - person2: - is_tax_unit_spouse: true - age: 40 - va_agi_person: 800 - households: - household: - members: [person1, person2] - state_code: VA - output: - va_agi_share: [0.2, 0.8] - -- name: If no adjusted gross income, assign to head. - period: 2021 - input: - people: - person1: - is_tax_unit_head: true - person2: - is_tax_unit_spouse: true - households: - household: - members: [person1, person2] - state_code: VA - output: - va_agi_share: [1, 0] - -- name: If no net income and single, assign entirely to them as head. - period: 2021 - input: - state_code: VA - output: - va_agi_share: 1 diff --git a/policyengine_us/variables/gov/states/md/tax/income/agi/subtractions/md_two_income_subtraction.py b/policyengine_us/variables/gov/states/md/tax/income/agi/subtractions/md_two_income_subtraction.py index 22b60ac4090..8db3537a2d3 100644 --- a/policyengine_us/variables/gov/states/md/tax/income/agi/subtractions/md_two_income_subtraction.py +++ b/policyengine_us/variables/gov/states/md/tax/income/agi/subtractions/md_two_income_subtraction.py @@ -1,6 +1,27 @@ from policyengine_us.model_api import * +# Person-level sources of the business losses in loss_ald. +BUSINESS_LOSS_SOURCES = [ + "total_self_employment_income", + "farm_operations_income", + "rental_income", + "farm_rent_income", + "estate_income", + "partnership_s_corp_income", +] + + +def _head_part(amount, head_own, spouse_own): + """The head's part of an amount split by the spouses' own amounts, or + equally when neither has any.""" + total = head_own + spouse_own + frac = np.full_like(total, 0.5) + mask = total > 0 + frac[mask] = head_own[mask] / total[mask] + return amount * frac + + class md_two_income_subtraction(Variable): value_type = float entity = TaxUnit @@ -10,6 +31,9 @@ class md_two_income_subtraction(Variable): reference = ( "https://interactive.marylandtaxes.gov/Individuals/iFile_ChooseForm/PriorYearForms/Resident_Booklet_2021.pdf#page=16", "https://mgaleg.maryland.gov/mgawebsite/Laws/StatuteText?article=gtg§ion=10-207&enactments=false", + "https://www.marylandcomptroller.gov/content/dam/mdcomp/tax/instructions/2025/resident-booklet.pdf#page=18", + # Worksheet 13D line 1: "the portion of federal adjusted gross income + # from Line 1 of Form 502 attributable to each spouse" ) defined_for = StateCode.MD @@ -24,13 +48,73 @@ def formula(tax_unit, period, parameters): is_spouse = person("is_tax_unit_spouse", period) head_gross_income = tax_unit.sum(where(is_head, gross_income, 0)) couple_gross_income = tax_unit.sum(where(is_head | is_spouse, gross_income, 0)) - # Compute the head's share of the couple's cross income. - # Use a mask rather than where to avoid a divide-by-zero warning. Default to one. + # Compute the head's share of the couple's gross income. + # Use a mask rather than where to avoid a divide-by-zero warning. head_frac = np.ones_like(couple_gross_income) mask = couple_gross_income > 0 head_frac[mask] = head_gross_income[mask] / couple_gross_income[mask] - head_us_agi = head_frac * us_agi - spouse_us_agi = (1 - head_frac) * us_agi + # Gross income is never below zero (losses are deducted in loss_ald), + # so without gross income the couple's AGI is their allowed losses and + # above-the-line deductions, and each spouse's portion is the part + # that is their own. The allowed business and capital losses in + # loss_ald are each split by the spouses' own losses of that kind, + # and deductions go to their owner where a person-level amount + # records one. Whatever has no owner is split equally. + filer = is_head | is_spouse + own_business = 0 + for source in BUSINESS_LOSS_SOURCES: + own_business = own_business + max_(0, -person(source, period)) + own_business = filer * own_business + unit_business = max_(0, -tax_unit("other_net_gain", period)) / 2 + own_capital = filer * person("capital_losses", period) + capital_part = add( + tax_unit, + period, + ["limited_capital_loss", "capital_losses_allowed_against_gains"], + ) + loss_ald = tax_unit("loss_ald", period) + business_part = max_(0, loss_ald - capital_part) + head_loss = _head_part( + business_part, + tax_unit.sum(is_head * own_business) + unit_business, + tax_unit.sum(is_spouse * own_business) + unit_business, + ) + _head_part( + capital_part, + tax_unit.sum(is_head * own_capital), + tax_unit.sum(is_spouse * own_capital), + ) + spouse_loss = loss_ald - head_loss + # A tax-unit deduction with a person-level counterpart is split by + # the spouses' own amounts, or equally when neither has one. + head_deductions = 0 + spouse_deductions = 0 + for deduction in sorted(parameters(period).gov.irs.ald.deductions): + variable = person.entity.get_variable(deduction, check_existence=True) + if variable.entity.is_person: + amount = filer * person(deduction, period) + head_deductions = head_deductions + tax_unit.sum(is_head * amount) + spouse_deductions = spouse_deductions + tax_unit.sum(is_spouse * amount) + continue + counterpart = f"{deduction}_person" + if person.entity.get_variable(counterpart) is None: + continue + own = filer * person(counterpart, period) + unit_amount = tax_unit(deduction, period) + head_part = _head_part( + unit_amount, tax_unit.sum(is_head * own), tax_unit.sum(is_spouse * own) + ) + head_deductions = head_deductions + head_part + spouse_deductions = spouse_deductions + unit_amount - head_part + head_own = -head_loss - head_deductions + spouse_own = -spouse_loss - spouse_deductions + unattributed = us_agi - head_own - spouse_own + no_gross_income = couple_gross_income <= 0 + head_us_agi = where( + no_gross_income, head_own + unattributed / 2, head_frac * us_agi + ) + spouse_us_agi = where( + no_gross_income, spouse_own + unattributed / 2, (1 - head_frac) * us_agi + ) # compute head and spouse MD AGI additions using ad hoc rule total_additions = tax_unit("md_total_additions", period) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_indiv.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_indiv.py index 5d1cb0c5153..1c1a1e3c8e4 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_indiv.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_indiv.py @@ -11,6 +11,12 @@ class mt_itemized_deductions_for_federal_itemization_indiv(Variable): "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2/2022_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=7", "https://law.justia.com/codes/montana/2022/title-15/chapter-30/part-21/section-15-30-2131/", # MT Code § 15-30-2131 (2022) (1) + "https://mca.legmt.gov/bills/2019/mca/title_0150/chapter_0300/part_0210/section_0010/0150-0300-0210-0010.html", + # MCA 15-30-2101: "Internal Revenue Code" means the IRC as amended + "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2023_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=38", + # 2023 Form 2 instructions, itemized deductions line 9: home mortgage + # interest "allowed by federal law", limited to the first $750,000 of + # acquisition debt incurred after Dec. 15, 2017 ) defined_for = "mt_married_filing_separately_on_same_return_eligible" @@ -22,7 +28,10 @@ def formula(person, period, parameters): head_or_spouse = person("is_tax_unit_head_or_spouse", period) # The interest deduction is the sum of mortagage and investment interest expenses investment_interest = person("investment_interest_expense", period) - mortgage_interest = person("mortgage_interest", period) + # Montana allows the mortgage interest federal law allows, so interest + # on acquisition debt above the IRC 163(h)(3) caps is not deductible + # (MCA 15-30-2131(1)(a); Form 2 instructions, itemized line 9). + mortgage_interest = person("deductible_mortgage_interest", period) interest_ded = investment_interest + mortgage_interest other_deductions = add( person, diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_joint.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_joint.py index 3469bb0b4b3..c56b1d7272e 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_joint.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_itemized_deductions_for_federal_itemization_joint.py @@ -11,13 +11,22 @@ class mt_itemized_deductions_for_federal_itemization_joint(Variable): "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2/2022_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=7", "https://law.justia.com/codes/montana/2022/title-15/chapter-30/part-21/section-15-30-2131/", # MT Code § 15-30-2131 (2022) (1) + "https://mca.legmt.gov/bills/2019/mca/title_0150/chapter_0300/part_0210/section_0010/0150-0300-0210-0010.html", + # MCA 15-30-2101: "Internal Revenue Code" means the IRC as amended + "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2023_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=38", + # 2023 Form 2 instructions, itemized deductions line 9: home mortgage + # interest "allowed by federal law", limited to the first $750,000 of + # acquisition debt incurred after Dec. 15, 2017 ) defined_for = StateCode.MT def formula(person, period, parameters): charitable_deduction = person.tax_unit("charitable_deduction", period) investment_interest = person("investment_interest_expense", period) - mortgage_interest = person("mortgage_interest", period) + # Montana allows the mortgage interest federal law allows, so interest + # on acquisition debt above the IRC 163(h)(3) caps is not deductible + # (MCA 15-30-2131(1)(a); Form 2 instructions, itemized line 9). + mortgage_interest = person("deductible_mortgage_interest", period) interest_ded = investment_interest + mortgage_interest other_deductions = add( person.tax_unit, diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_itemized_deductions_indiv.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_itemized_deductions_indiv.py index 7b31319e265..2ce15dcaaac 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_itemized_deductions_indiv.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_itemized_deductions_indiv.py @@ -11,6 +11,12 @@ class mt_itemized_deductions_indiv(Variable): "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2/2022_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=7", "https://law.justia.com/codes/montana/2022/title-15/chapter-30/part-21/section-15-30-2131/", # MT Code § 15-30-2131 (2022) (1) + "https://mca.legmt.gov/bills/2019/mca/title_0150/chapter_0300/part_0210/section_0010/0150-0300-0210-0010.html", + # MCA 15-30-2101: "Internal Revenue Code" means the IRC as amended + "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2023_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=38", + # 2023 Form 2 instructions, itemized deductions line 9: home mortgage + # interest "allowed by federal law", limited to the first $750,000 of + # acquisition debt incurred after Dec. 15, 2017 ) defined_for = "mt_married_filing_separately_on_same_return_eligible" @@ -24,7 +30,10 @@ def formula(person, period, parameters): head_or_spouse = person("is_tax_unit_head_or_spouse", period) # The interest deduction is the sum of mortagage and investment interest expenses investment_interest = person("investment_interest_expense", period) - mortgage_interest = person("mortgage_interest", period) + # Montana allows the mortgage interest federal law allows, so interest + # on acquisition debt above the IRC 163(h)(3) caps is not deductible + # (MCA 15-30-2131(1)(a); Form 2 instructions, itemized line 9). + mortgage_interest = person("deductible_mortgage_interest", period) interest_ded = investment_interest + mortgage_interest other_deductions = add( person, diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_itemized_deductions_joint.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_itemized_deductions_joint.py index a3328b0290d..c13d9dbd54e 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_itemized_deductions_joint.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_itemized_deductions_joint.py @@ -11,13 +11,22 @@ class mt_itemized_deductions_joint(Variable): "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2/2022_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=7", "https://law.justia.com/codes/montana/2022/title-15/chapter-30/part-21/section-15-30-2131/", # MT Code § 15-30-2131 (2022) (1) + "https://mca.legmt.gov/bills/2019/mca/title_0150/chapter_0300/part_0210/section_0010/0150-0300-0210-0010.html", + # MCA 15-30-2101: "Internal Revenue Code" means the IRC as amended + "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2023_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=38", + # 2023 Form 2 instructions, itemized deductions line 9: home mortgage + # interest "allowed by federal law", limited to the first $750,000 of + # acquisition debt incurred after Dec. 15, 2017 ) defined_for = StateCode.MT def formula(person, period, parameters): charitable_deduction = person.tax_unit("charitable_deduction", period) investment_interest = person("investment_interest_expense", period) - mortgage_interest = person("mortgage_interest", period) + # Montana allows the mortgage interest federal law allows, so interest + # on acquisition debt above the IRC 163(h)(3) caps is not deductible + # (MCA 15-30-2131(1)(a); Form 2 instructions, itemized line 9). + mortgage_interest = person("deductible_mortgage_interest", period) interest_ded = investment_interest + mortgage_interest other_deductions = add( person.tax_unit, diff --git a/policyengine_us/variables/gov/states/va/tax/income/credits/eitc/va_eitc.py b/policyengine_us/variables/gov/states/va/tax/income/credits/eitc/va_eitc.py index 0447a964de3..2dafb5b97ff 100644 --- a/policyengine_us/variables/gov/states/va/tax/income/credits/eitc/va_eitc.py +++ b/policyengine_us/variables/gov/states/va/tax/income/credits/eitc/va_eitc.py @@ -6,21 +6,25 @@ class va_eitc(Variable): entity = TaxUnit label = "Virginia Earned Income Tax Credit" unit = USD - documentation = "Refundable or non-refundable Virginia EITC" + documentation = ( + "The Virginia EITC the tax unit's income tax applies: the refundable " + "credit if it is claimed, otherwise the non-refundable credit after " + "its tax liability limit. Spouses filing separately split the " + "Virginia EIC by their shares of the earned income used for the " + "federal EITC, and only one of them may claim the Credit for " + "Low-Income Individuals, so the credit for a tax unit holding both " + "spouses is the sum of their shares." + ) definition_period = YEAR - reference = "https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2022-760-instructions.pdf#page=32" + reference = ( + "https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2022-760-instructions.pdf#page=32", + "https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2025-760-instructions.pdf#page=31", + "https://law.lis.virginia.gov/vacode/title58.1/chapter3/section58.1-339.8/", + ) defined_for = StateCode.VA def formula(tax_unit, period, parameters): refundable_eitc = tax_unit("va_refundable_eitc", period) non_refundable_eitc = tax_unit("va_non_refundable_eitc", period) claims_refundable = tax_unit("va_claims_refundable_eitc", period) - amount = where(claims_refundable, refundable_eitc, non_refundable_eitc) - filing_status = tax_unit("filing_status", period) - # In the case of separated individuals, the EITC amount is prorated - is_separate = filing_status == filing_status.possible_values.SEPARATE - person = tax_unit.members - eitc_person = person("va_eitc_person", period) - is_head = person("is_tax_unit_head", period) - head_eitc = tax_unit.sum(eitc_person * is_head) - return where(is_separate, head_eitc, amount) + return where(claims_refundable, refundable_eitc, non_refundable_eitc) diff --git a/policyengine_us/variables/gov/states/va/tax/income/credits/eitc/va_eitc_person.py b/policyengine_us/variables/gov/states/va/tax/income/credits/eitc/va_eitc_person.py deleted file mode 100644 index 703dc91f6e9..00000000000 --- a/policyengine_us/variables/gov/states/va/tax/income/credits/eitc/va_eitc_person.py +++ /dev/null @@ -1,19 +0,0 @@ -from policyengine_us.model_api import * - - -class va_eitc_person(Variable): - value_type = float - entity = Person - label = "Virginia Earned Income Tax Credit per individual when married filing seperately" - unit = USD - definition_period = YEAR - reference = "https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2022-760-instructions.pdf#page=32" - defined_for = StateCode.VA - - def formula(person, period, parameters): - refundable_eitc = person.tax_unit("va_refundable_eitc", period) - non_refundable_eitc = person.tax_unit("va_non_refundable_eitc", period) - claims_refundable = person.tax_unit("va_claims_refundable_eitc", period) - va_agi_share = person("va_agi_share", period) - eitc_claimed = where(claims_refundable, refundable_eitc, non_refundable_eitc) - return eitc_claimed * va_agi_share diff --git a/policyengine_us/variables/gov/states/va/tax/income/va_agi_share.py b/policyengine_us/variables/gov/states/va/tax/income/va_agi_share.py deleted file mode 100644 index aef97e3632e..00000000000 --- a/policyengine_us/variables/gov/states/va/tax/income/va_agi_share.py +++ /dev/null @@ -1,25 +0,0 @@ -from policyengine_us.model_api import * - - -class va_agi_share(Variable): - value_type = float - entity = Person - label = "Virginia share of state adjusted gross income of each person" - unit = USD - definition_period = YEAR - reference = "https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2021-760-instructions.pdf#page=20" - defined_for = StateCode.VA - - def formula(person, period, parameters): - agi = person("va_agi_person", period) - total_agi = person.tax_unit.sum(agi) - # avoid divide-by-zero warnings - fraction = np.zeros_like(total_agi) - mask = total_agi != 0 - fraction[mask] = agi[mask] / total_agi[mask] - # if no net income, then assign entirely to head. - return where( - total_agi == 0, - person("is_tax_unit_head", period), - fraction, - )