Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/ms-mo-misc-deduction-double-count.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Count the pre-2018 federal miscellaneous deduction once in Mississippi and Missouri itemized deductions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
description: Missouri lets filers itemize the following deductions.
values:
1993-01-01:
- itemized_taxable_income_deductions # includes casualty_loss_deduction, charitable_deduction, interest_deduction, salt_deduction ,and medical_expense_deduction
- misc_deduction
# Form MO-A Part 2 line 1: total federal itemized deductions, which include
# the miscellaneous deduction above the 2% floor before 2018.
- itemized_taxable_income_deductions
- employee_social_security_tax
- employee_medicare_tax
- additional_medicare_tax
Expand All @@ -22,3 +23,5 @@ metadata:
href: https://dor.mo.gov/forms/MO-1040%20Instructions_2021.pdf#page=16
- title: 2024 Form MO-A - Individual Income Tax Adjustments, Part 2 - Missouri Itemized Deductions
href: https://dor.mo.gov/forms/MO-A_2024.pdf#page=2
- title: "2017 Form MO-1040 instructions, Form MO-A Part 2 line 1 #page 22,42"
href: https://dor.mo.gov/forms/MO-1040%20Instructions_2017.pdf#page=22
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,32 @@
itemized_taxable_income_deductions: 0
employee_social_security_tax: 0
employee_medicare_tax: 0
misc_deduction: 0
mo_net_state_income_taxes: 0
state_code: MO
output:
mo_itemized_deductions: 0.0

- name: 60 in Federal itemizations, 10 in net_state_income_taxes
- name: 20 in Federal itemizations, 10 in net_state_income_taxes
period: 2021
absolute_error_margin: 0.01
input:
itemized_taxable_income_deductions: 10
# Form MO-A Part 2 line 1 is the federal total, which already includes
# any miscellaneous deduction.
itemized_taxable_income_deductions: 20
employee_social_security_tax: 0
employee_medicare_tax: 0
misc_deduction: 10
mo_net_state_income_taxes: 10
state_code: MO
output:
mo_itemized_deductions: 10.00

- name: 6000 in Federal itemizations, 1000 in net_state_income_taxes
- name: 2000 in Federal itemizations, 1000 in net_state_income_taxes
period: 2021
absolute_error_margin: 0.01
input:
itemized_taxable_income_deductions: 1000
itemized_taxable_income_deductions: 2000
employee_social_security_tax: 0
employee_medicare_tax: 0
misc_deduction: 1000
mo_net_state_income_taxes: 1000
state_code: MO
output:
Expand All @@ -51,3 +50,66 @@
households: {household: {members: [head, spouse], state_code: MO}}
output:
mo_itemized_deductions: 50_000

# 2017 Form MO-A Part 2 line 1 is total federal itemized deductions from Form
# 1040 line 40, which already includes the miscellaneous deduction above the
# 2% floor; Part 2 has no separate line for it.
- name: 2017 miscellaneous deduction counted once
period: 2017
absolute_error_margin: 0.01
input:
charitable_deduction: 9_000
misc_deduction: 1_000
employee_social_security_tax: 0
employee_medicare_tax: 0
mo_net_state_income_taxes: 0
state_code: MO
output:
itemized_taxable_income_deductions: 10_000
mo_itemized_deductions: 10_000

# RSMo 143.141 starts from the allowable federal itemized deductions, and the
# 2017 instructions (MO-A Part 2 line 1) take the federal total once.
- name: 2017 federal total that includes miscellaneous deductions counted once
period: 2017
input:
itemized_taxable_income_deductions: 10_000
misc_deduction: 1_000
employee_social_security_tax: 0
employee_medicare_tax: 0
additional_medicare_tax: 0
self_employment_tax: 0
mo_net_state_income_taxes: 0
state_code: MO
output:
# The 10,000 already includes the 1,000; before the fix 11,000.
mo_itemized_deductions: 10_000

- name: 2017 state income tax adjustment without duplicating miscellaneous deductions
period: 2017
input:
itemized_taxable_income_deductions: 10_000
misc_deduction: 1_000
employee_social_security_tax: 0
employee_medicare_tax: 0
additional_medicare_tax: 0
self_employment_tax: 0
mo_net_state_income_taxes: 2_000
state_code: MO
output:
# 10,000 - 2,000; before the fix 9,000.
mo_itemized_deductions: 8_000

- name: 2016 miscellaneous deduction counted once
period: 2016
input:
charitable_deduction: 9_000
misc_deduction: 1_000
employee_social_security_tax: 0
employee_medicare_tax: 0
additional_medicare_tax: 0
self_employment_tax: 0
mo_net_state_income_taxes: 0
state_code: MO
output:
mo_itemized_deductions: 10_000
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# 2017 Form 80-108 lines 7a to 7d take miscellaneous expenses above 2% of
# federal AGI once; itemized_deductions_less_salt already includes them.
- name: 2017 miscellaneous deduction counted once
absolute_error_margin: 0.01
period: 2017
input:
charitable_deduction: 2_000
misc_deduction: 1_000
state_code: MS
output:
ms_itemized_deductions_unit: 3_000

- name: 2025 no miscellaneous deduction subject to the 2% floor
absolute_error_margin: 0.01
period: 2025
input:
charitable_deduction: 2_000
state_code: MS
output:
ms_itemized_deductions_unit: 2_000

# Miss. Code Ann. 27-7-17(4) bars deducting the same item more than once.
- name: 2017 non-SALT total that includes miscellaneous deductions counted once
period: 2017
input:
itemized_deductions_less_salt: 10_000
misc_deduction: 1_000
ms_real_estate_tax_deduction: 0
state_code: MS
output:
# The 10,000 already includes the 1,000; before the fix 11,000.
ms_itemized_deductions_unit: 10_000

- name: 2017 real estate taxes added without duplicating miscellaneous deductions
period: 2017
input:
itemized_deductions_less_salt: 10_000
misc_deduction: 1_000
ms_real_estate_tax_deduction: 2_000
state_code: MS
output:
# 10,000 + 2,000; before the fix 13,000.
ms_itemized_deductions_unit: 12_000
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"""Mississippi and Missouri count the federal miscellaneous deduction once.

Before 2018 the federal miscellaneous deduction above the 2% floor is part of
itemized_taxable_income_deductions and of itemized_deductions_less_salt.
RSMo 143.141 starts Missouri's itemized deduction from the allowable federal
itemized deductions, and Miss. Code Ann. 27-7-17(4) bars deducting the same
item more than once. So for every generated tax unit and year:

1. Holding the federal totals fixed, the miscellaneous deduction does not
change mo_itemized_deductions or ms_itemized_deductions_unit.
2. Mississippi's total is its non-SALT federal total plus its real estate
tax deduction.
3. Missouri's total is never negative and never exceeds the federal total
plus payroll taxes. The worked cases also show it falls with the state
income tax adjustment.

Property 1 fails whenever the miscellaneous deduction is positive if either
state adds misc_deduction on top of the federal total; the strategy draws it
from $1 to $20,000, never zero, and the years include 2016 and 2017, when
the federal deduction applies.
"""

import hypothesis
import hypothesis.strategies as st
import numpy as np
import pytest

from policyengine_us import Simulation

YEARS = (2016, 2017, 2025)
TOLERANCE = 0.01


def build_situation(cases, state):
people, tax_units, households = {}, {}, {}
for i, case in enumerate(cases):
for with_misc in (True, False):
key = f"{i}_{int(with_misc)}"
person = f"person_{key}"
people[person] = {
"age": {year: 40 for year in YEARS},
"employee_social_security_tax": {
year: case["payroll_tax"] for year in YEARS
},
"employee_medicare_tax": {year: 0 for year in YEARS},
"self_employment_tax": {year: 0 for year in YEARS},
}
misc = case["misc"] if with_misc else 0
tax_unit = {
"members": [person],
"misc_deduction": {year: misc for year in YEARS},
"additional_medicare_tax": {year: 0 for year in YEARS},
}
if state == "MO":
tax_unit["itemized_taxable_income_deductions"] = {
year: case["federal_total"] for year in YEARS
}
tax_unit["mo_net_state_income_taxes"] = {
year: case["state_tax"] for year in YEARS
}
else:
tax_unit["itemized_deductions_less_salt"] = {
year: case["federal_total"] for year in YEARS
}
tax_unit["ms_real_estate_tax_deduction"] = {
year: case["real_estate"] for year in YEARS
}
tax_units[f"tax_unit_{key}"] = tax_unit
households[f"household_{key}"] = {
"members": [person],
"state_code": {year: state for year in YEARS},
}
return {"people": people, "tax_units": tax_units, "households": households}


def calculate(cases, state, variable):
simulation = Simulation(situation=build_situation(cases, state))
return {
year: np.asarray(simulation.calculate(variable, year)).reshape(len(cases), 2)
for year in YEARS
}


def assert_properties(cases):
mo = calculate(cases, "MO", "mo_itemized_deductions")
ms = calculate(cases, "MS", "ms_itemized_deductions_unit")
for i, case in enumerate(cases):
for year in YEARS:
# Column 0 has the miscellaneous deduction, column 1 has none.
assert mo[year][i, 0] == pytest.approx(mo[year][i, 1], abs=TOLERANCE), (
case,
year,
)
assert ms[year][i, 0] == pytest.approx(ms[year][i, 1], abs=TOLERANCE), (
case,
year,
)
assert ms[year][i, 0] == pytest.approx(
case["federal_total"] + case["real_estate"], abs=TOLERANCE
), (case, year)
assert mo[year][i, 0] >= 0, (case, year)
assert (
mo[year][i, 0]
<= case["federal_total"] + case["payroll_tax"] + TOLERANCE
), (case, year)


def test_state_tax_adjustment_does_not_raise_missouri_deduction():
base = {
"federal_total": 10_000,
"misc": 1_000,
"payroll_tax": 0,
"real_estate": 2_000,
"state_tax": 0,
}
cases = [base, {**base, "state_tax": 2_000}, {**base, "state_tax": 50_000}]
mo = calculate(cases, "MO", "mo_itemized_deductions")
# 10,000 once, less the state income tax adjustment, floored at zero.
assert mo[2017][:, 0] == pytest.approx([10_000, 8_000, 0], abs=TOLERANCE)
ms = calculate(cases[:1], "MS", "ms_itemized_deductions_unit")
# 10,000 once, plus 2,000 real estate taxes.
assert ms[2017][0, 0] == pytest.approx(12_000, abs=TOLERANCE)
assert_properties(cases)


AMOUNTS = st.integers(min_value=0, max_value=50_000)


@hypothesis.settings(
max_examples=10,
deadline=None,
derandomize=True,
suppress_health_check=[hypothesis.HealthCheck.too_slow],
)
@hypothesis.given(
st.lists(
st.fixed_dictionaries(
{
"federal_total": AMOUNTS,
"misc": st.integers(min_value=1, max_value=20_000),
"payroll_tax": st.integers(min_value=0, max_value=10_000),
"real_estate": AMOUNTS,
"state_tax": AMOUNTS,
}
),
min_size=1,
max_size=8,
)
)
def test_ms_mo_misc_deduction_counted_once(cases):
assert_properties(cases)
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ class ms_itemized_deductions_unit(Variable):
"https://www.dor.ms.gov/sites/default/files/tax-forms/individual/80100221.pdf#page=15",
"https://www.dor.ms.gov/sites/default/files/tax-forms/individual/80108228.pdf", # Line 7
"https://law.justia.com/codes/mississippi/title-27/chapter-7/article-1/section-27-7-17/",
# Miss. Code Ann. 27-7-17(4), 2016 and 2020 editions.
"https://law.justia.com/codes/mississippi/2016/title-27/chapter-7/article-1/section-27-7-17/",
"https://law.justia.com/codes/mississippi/2020/title-27/chapter-7/article-1/section-27-7-17/",
# 2017 instructions, Form 80-108 lines 7a to 7d.
"https://taxsim.nber.org/historical_state_tax_forms/MS/2017/80100178.pdf#page=15",
)
defined_for = StateCode.MS

# itemized_deductions_less_salt already includes the federal miscellaneous
# deduction above the 2% floor (Form 80-108 lines 7a to 7d before 2018), so
# misc_deduction is not added again: Miss. Code Ann. 27-7-17(4) bars
# deducting the same item more than once.
adds = [
"itemized_deductions_less_salt",
"misc_deduction",
"ms_real_estate_tax_deduction",
]

Expand Down
Loading