diff --git a/changelog.d/fix-casualty-loss-165h-reduction.fixed.md b/changelog.d/fix-casualty-loss-165h-reduction.fixed.md new file mode 100644 index 00000000000..10d9637e1b5 --- /dev/null +++ b/changelog.d/fix-casualty-loss-165h-reduction.fixed.md @@ -0,0 +1 @@ +Apply the Form 4684 $100 per-casualty reduction (26 U.S.C. 165(h)(1)) before the 10% floor, and leave tax unit dependents' losses off the filer's return, in the federal, New York, Alabama and Hawaii casualty loss deductions. Limit Alabama's deduction to declared-disaster losses from 2018, as federal law does, and Hawaii's from 2026 (Act 35, SLH 2026). diff --git a/changelog.d/fix-mt-casualty-loss-misc-deduction.fixed.md b/changelog.d/fix-mt-casualty-loss-misc-deduction.fixed.md new file mode 100644 index 00000000000..c88a9dbce78 --- /dev/null +++ b/changelog.d/fix-mt-casualty-loss-misc-deduction.fixed.md @@ -0,0 +1 @@ +Count a Montana casualty and theft loss once on a joint return, and only in the column of the spouse who had it when spouses file separately, figured as on federal Form 4684 ($100 reduction, then the 10% floor on Montana AGI) per the 2021-2023 Form 2 Itemized Deductions Schedule, line 15. diff --git a/changelog.d/fix-mt-separate-filing-allocations.fixed.md b/changelog.d/fix-mt-separate-filing-allocations.fixed.md new file mode 100644 index 00000000000..c7d3be16f20 --- /dev/null +++ b/changelog.d/fix-mt-separate-filing-allocations.fixed.md @@ -0,0 +1 @@ +Montana's federal income tax deduction for spouses filing separately on the same form now attributes federal tax to the spouse who earned the income and caps each spouse at 5,000; the child and dependent care expense deduction phases out on the couple's combined Montana AGI and is halved only for spouses filing separately on the same form; and the elderly homeowner/renter credit counts income without regard to losses. diff --git a/policyengine_us/parameters/gov/irs/deductions/itemized/casualty/per_casualty_reduction.yaml b/policyengine_us/parameters/gov/irs/deductions/itemized/casualty/per_casualty_reduction.yaml new file mode 100644 index 00000000000..b56d5b69462 --- /dev/null +++ b/policyengine_us/parameters/gov/irs/deductions/itemized/casualty/per_casualty_reduction.yaml @@ -0,0 +1,20 @@ +description: The IRS reduces each casualty or theft loss of personal-use property by this amount before applying the income floor. +values: + 2008-01-01: 100 + 2009-01-01: 500 + 2010-01-01: 100 +metadata: + unit: currency-USD + period: year + label: Casualty loss reduction per casualty + reference: + - title: 26 U.S.C. § 165(h)(1) + href: https://www.law.cornell.edu/uscode/text/26/165#h_1 + - title: 2008 Form 4684, line 11 + href: https://www.irs.gov/pub/irs-prior/f4684--2008.pdf#page=1 + - title: 2009 Form 4684, line 11 + href: https://www.irs.gov/pub/irs-prior/f4684--2009.pdf#page=1 + - title: 2022 Form 4684, line 11 + href: https://www.irs.gov/pub/irs-prior/f4684--2022.pdf#page=1 + - title: IRS Publication 547 (2022), $100 Rule + href: https://www.irs.gov/pub/irs-prior/p547--2022.pdf#page=10 diff --git a/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/casualty_loss/non_disaster_losses_allowed.yaml b/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/casualty_loss/non_disaster_losses_allowed.yaml new file mode 100644 index 00000000000..30ba00f91da --- /dev/null +++ b/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/casualty_loss/non_disaster_losses_allowed.yaml @@ -0,0 +1,19 @@ +description: Hawaii allows personal casualty and theft losses that are not attributable to a declared disaster, if this is true. +values: + 2018-01-01: true + 2026-01-01: false +metadata: + unit: bool + period: year + label: Hawaii non-disaster casualty losses allowed + reference: + - title: HRS § 235-2.4(l)(3) (unofficial compilation as of December 31, 2025) + href: https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=12 + - title: Act 35, SLH 2026 (HB 2329 CD1), striking HRS § 235-2.4(l)(3) + href: https://data.capitol.hawaii.gov/sessions/session2026/bills/HB2329_CD1_.pdf#page=23 + - title: Act 35, SLH 2026 (HB 2329 CD1), effective date + href: https://data.capitol.hawaii.gov/sessions/session2026/bills/HB2329_CD1_.pdf#page=34 + - title: Hawaii Department of Taxation Announcement No. 2026-06 + href: https://files.hawaii.gov/tax/news/announce/ann26-06.pdf#page=2 + - title: 2025 Hawaii Form N-11 Instructions, Casualty and Theft Losses + href: https://files.hawaii.gov/tax/forms/2025/n11ins.pdf#page=18 diff --git a/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/casualty_loss/per_casualty_reduction.yaml b/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/casualty_loss/per_casualty_reduction.yaml new file mode 100644 index 00000000000..f7a5c2dc1f9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/casualty_loss/per_casualty_reduction.yaml @@ -0,0 +1,18 @@ +description: Hawaii reduces each casualty or theft loss of personal-use property by this amount before applying the income floor. +values: + 2018-01-01: 100 +metadata: + unit: currency-USD + period: year + label: Hawaii casualty loss reduction per casualty + reference: + - title: HRS § 235-2.4(l)(1) (unofficial compilation as of December 31, 2025) + href: https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=12 + - title: Act 35, SLH 2026 (HB 2329 CD1), HRS § 235-2.4(k)(1) + href: https://data.capitol.hawaii.gov/sessions/session2026/bills/HB2329_CD1_.pdf#page=22 + - title: 2022 Hawaii Form N-11 Instructions, Casualty and Theft Losses + href: https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=18 + - title: 2025 Hawaii Form N-11 Instructions, Casualty and Theft Losses + href: https://files.hawaii.gov/tax/forms/2025/n11ins.pdf#page=19 + - title: 2017 Form 4684, line 11 + href: https://www.irs.gov/pub/irs-prior/f4684--2017.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/deductions/itemized/casualty_loss/applies.yaml b/policyengine_us/parameters/gov/states/mt/tax/income/deductions/itemized/casualty_loss/applies.yaml new file mode 100644 index 00000000000..6c6d2c05de1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mt/tax/income/deductions/itemized/casualty_loss/applies.yaml @@ -0,0 +1,22 @@ +description: Montana allows a casualty and theft loss deduction on its Itemized Deductions Schedule, if this is true. +metadata: + label: Montana casualty and theft loss deduction applies + period: year + unit: bool + reference: + - title: MCA § 15-30-2131(1)(a) (2021), itemized deductions by reference to 26 U.S.C. 161 and 211 (repealed effective 2024) + href: https://mca.legmt.gov/bills/2022/mca/title_0150/chapter_0300/part_0210/section_0310/0150-0300-0210-0310.html + - title: 2021 Montana Form 2 Instructions, Itemized Deductions Schedule, line 15 + href: https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2021_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=34 + - title: 2022 Montana Form 2 Instructions, Itemized Deductions Schedule, line 15 + href: https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=35 + - title: 2023 Montana Form 2 Instructions, Itemized Deductions Schedule, line 15 + href: https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2023_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=39 + # From 2024, Montana taxable income starts from federal taxable income and + # the Itemized Deductions Schedule is discontinued (SB 399). + - title: 2024 Montana Form 2 Instructions, Discontinued Worksheets and Schedules + href: https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2024_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=8 + +values: + 2021-01-01: true + 2024-01-01: false diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/deductions/itemized/misc_deductions.yaml b/policyengine_us/parameters/gov/states/mt/tax/income/deductions/itemized/misc_deductions.yaml deleted file mode 100644 index 1eeb0351b1a..00000000000 --- a/policyengine_us/parameters/gov/states/mt/tax/income/deductions/itemized/misc_deductions.yaml +++ /dev/null @@ -1,22 +0,0 @@ -description: Montana counts these sources as miscellaneous deductions. -values: - 2021-01-01: - - mt_child_dependent_care_expense_deduction - - casualty_loss_deduction - 2024-01-01: [] - -metadata: - unit: list - label: Montana miscellaneous deductions - period: year - reference: - - title: Montana Individual Income Tax Return (Form 2) 2024 - href: https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2024_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=8 - - title: Montana Individual Income Tax Return (Form 2) 2022 - href: https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2/2022_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=7 - - title: Montana Individual Income Tax Return (Form 2) 2021 - href: https://revenue.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2/2021_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=7 - - title: Montana Tax From Instructions 2021 - href: https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=35 - - title: MT Code § 15-30-2131 (2022) (1)(a)&(c) - href: https://law.justia.com/codes/montana/2022/title-15/chapter-30/part-21/section-15-30-2131/ diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/casualty_loss_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/casualty_loss_deduction.yaml new file mode 100644 index 00000000000..472fc8349f5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/casualty_loss_deduction.yaml @@ -0,0 +1,171 @@ +# 26 U.S.C. 165(h)(1), as in effect for these years: a personal casualty loss is +# allowed "only to the extent that the amount of the loss to such individual +# arising from each casualty, or from each theft, exceeds $500 ($100 for taxable +# years beginning after December 31, 2009)". P.L. 119-108 (2026) keeps $100 for +# losses other than qualified disaster-related losses, which the model has no +# input for. 26 U.S.C. 165(h)(2)(A): the net loss is allowed only to the extent +# it exceeds 10 percent of adjusted gross income. 165(h)(4)(B): "a husband and +# wife making a joint return for the taxable year shall be treated as 1 +# individual." +# 2017 Form 4684: line 11 "Enter $100 ($500 if qualified disaster loss rules +# apply; see instructions)", line 12 "Subtract line 11 from line 10. If zero or +# less; enter -0-", line 17 "Enter 10% of your adjusted gross income", line 18 +# "Subtract line 17 from line 16. If zero or less, enter -0-". +# IRS Publication 547 (2017, PDF p. 10), $100 Rule: "If you and your spouse file +# a joint return, you are treated as one individual in applying the $100 rule." +# "If you and your spouse have a casualty or theft loss and you file separate +# returns, each of you must reduce your loss by $100." +# The model records one loss amount per person, not separate casualty events, +# so a return's losses are treated as one casualty. A dependent's loss belongs +# on the dependent's own return, as the dependent's income does. + +- name: Case 1, a loss of exactly $100 is fully absorbed by the $100 reduction. + period: 2017 + input: + casualty_loss: 100 + output: + # max(100 - 100, 0) - 10% x 0 + casualty_loss_deduction: 0 + +- name: Case 2, a loss of $101 leaves $1 after the $100 reduction. + period: 2017 + input: + casualty_loss: 101 + output: + # max(101 - 100, 0) - 10% x 0 + casualty_loss_deduction: 1 + +- name: Case 3, a loss under $100 is not deductible. + period: 2017 + input: + casualty_loss: 80 + output: + # max(80 - 100, 0) = 0 + casualty_loss_deduction: 0 + +- name: Case 4, the 10 percent floor applies after the $100 reduction. + period: 2017 + input: + employment_income: 50_000 + casualty_loss: 10_000 + output: + # (10,000 - 100) - 10% x 50,000 = 9,900 - 5,000 + casualty_loss_deduction: 4_900 + +- name: Case 5, a loss $100 above the floor nets to zero. + period: 2017 + input: + employment_income: 50_000 + casualty_loss: 5_100 + output: + # (5,100 - 100) - 10% x 50,000 = 5,000 - 5,000 + casualty_loss_deduction: 0 + +- name: Case 6, a loss $101 above the floor leaves $1. + period: 2017 + input: + employment_income: 50_000 + casualty_loss: 5_101 + output: + # (5,101 - 100) - 10% x 50,000 = 5,001 - 5,000 + casualty_loss_deduction: 1 + +- name: Case 7, a joint return reduces the spouses' pooled losses by $100 once. + period: 2017 + input: + people: + person1: + age: 40 + employment_income: 30_000 + casualty_loss: 6_000 + person2: + age: 40 + employment_income: 20_000 + casualty_loss: 4_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + output: + filing_status: JOINT + # (6,000 + 4,000 - 100) - 10% x 50,000 = 9,900 - 5,000 + casualty_loss_deduction: 4_900 + +- name: Case 8, a dependent's loss is left to the dependent's own return. + period: 2017 + input: + people: + person1: + age: 40 + employment_income: 50_000 + casualty_loss: 10_000 + person2: + age: 10 + casualty_loss: 3_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + output: + is_tax_unit_dependent: [false, true] + # The child's 3,000 is not the parent's loss. + # (10,000 - 100) - 10% x 50,000 = 9,900 - 5,000 + casualty_loss_deduction: 4_900 + +- name: Case 9, a working dependent's loss stays off the parent's return. + period: 2017 + input: + people: + person1: + age: 45 + employment_income: 60_000 + casualty_loss: 8_000 + person2: + age: 17 + employment_income: 4_000 + casualty_loss: 9_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + output: + is_tax_unit_dependent: [false, true] + # The parent's AGI leaves out the dependent's wages, and the parent's loss + # leaves out the dependent's loss. + # (8,000 - 100) - 10% x 60,000 = 7,900 - 6,000 + adjusted_gross_income: 60_000 + casualty_loss_deduction: 1_900 + +- name: Case 10, the deduction is suspended from 2018. + period: 2018 + input: + employment_income: 50_000 + casualty_loss: 10_000 + output: + casualty_loss_deduction: 0 + +- name: Case 11, a reform that restores the deduction applies the $100 reduction. + period: 2025 + input: + gov.irs.deductions.itemized.casualty.active: true + employment_income: 50_000 + casualty_loss: 10_000 + output: + # (10,000 - 100) - 10% x 50,000 = 9,900 - 5,000 + casualty_loss_deduction: 4_900 + +- name: Case 12, a separate return reduces its own loss by $100. + period: 2017 + input: + employment_income: 20_000 + casualty_loss: 5_000 + filing_status: SEPARATE + output: + # (5,000 - 100) - 10% x 20,000 = 4,900 - 2,000 + casualty_loss_deduction: 2_900 diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/tax/income/deductions/itemized/al_casualty_loss_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/tax/income/deductions/itemized/al_casualty_loss_deduction.yaml index da91a20db54..515a980aed1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/al/tax/income/deductions/itemized/al_casualty_loss_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/al/tax/income/deductions/itemized/al_casualty_loss_deduction.yaml @@ -1,17 +1,161 @@ +# Ala. Code 40-18-15(a)(6) allows casualty and theft losses "as determined in +# accordance with subsections (c)(3) and (h) of 26 U.S.C. § 165", and 40-18-1.1 +# defines "26 U.S.C." as the Internal Revenue Code "as in effect from time to +# time". The 2025 Form 40 instructions (PDF p. 20): "A casualty or theft loss +# is determined in the same manner as on your federal return" except that "The +# loss on personal property must be reduced by 10% of the Alabama adjusted +# gross income"; Schedule A line 19a takes the loss from federal Form 4684, after +# its $100 reduction (line 11) and, from 2018, its limit to losses attributable +# to declared disasters (26 U.S.C. 165(h)(5)). The Department of Revenue's +# OBBBA Executive Summary (PDF p. 8) lists 165(h)(5) as "Tied to Federal: Yes" +# through 40-18-15(a)(6). The model has no input that +# distinguishes disaster losses; like the federal deduction, it allows no +# personal casualty loss from 2018 unless +# gov.irs.deductions.itemized.casualty.active is switched on. +# A joint return is one individual for the $100 rule (26 U.S.C. 165(h)(4)(B)). +# The model records one loss amount per person, so a return's losses are +# treated as one casualty. + - name: Reduction of casualty loss - period: 2021 + period: 2017 input: state_code: AL casualty_loss: 2_000 al_agi: 1_000 output: - al_casualty_loss_deduction: 1_900 + # (2,000 - 100) - 10% x 1,000 = 1,900 - 100 + al_casualty_loss_deduction: 1_800 - name: Capped at 0 - period: 2021 + period: 2017 input: state_code: AL casualty_loss: 1_000 al_agi: 11_000 output: + # (1,000 - 100) - 10% x 11,000 = 900 - 1,100, below zero + al_casualty_loss_deduction: 0 + +- name: Case 3, a loss not attributable to a declared disaster is not deductible from 2018. + period: 2021 + input: + state_code: AL + casualty_loss: 2_000 + al_agi: 1_000 + output: + al_casualty_loss_deduction: 0 + +- name: Case 4, a loss of exactly $100 is fully absorbed by the $100 reduction. + period: 2017 + input: + state_code: AL + casualty_loss: 100 + al_agi: 0 + output: + # max(100 - 100, 0) - 10% x 0 + al_casualty_loss_deduction: 0 + +- name: Case 5, a loss of $101 leaves $1 after the $100 reduction. + period: 2017 + input: + state_code: AL + casualty_loss: 101 + al_agi: 0 + output: + al_casualty_loss_deduction: 1 + +- name: Case 6, a loss under $100 is not deductible. + period: 2017 + input: + state_code: AL + casualty_loss: 60 + al_agi: 0 + output: + al_casualty_loss_deduction: 0 + +- name: Case 7, the 10 percent floor on Alabama AGI applies after the $100 reduction. + period: 2017 + input: + state_code: AL + casualty_loss: 5_000 + al_agi: 20_000 + output: + # (5,000 - 100) - 10% x 20,000 = 4,900 - 2,000 + al_casualty_loss_deduction: 2_900 + +- name: Case 8, a joint return reduces the spouses' pooled losses by $100 once. + period: 2017 + input: + people: + person1: + age: 40 + casualty_loss: 1_500 + person2: + age: 40 + casualty_loss: 1_500 + tax_units: + tax_unit: + members: [person1, person2] + al_agi: 10_000 + households: + household: + members: [person1, person2] + state_code: AL + output: + # (1,500 + 1,500 - 100) - 10% x 10,000 = 2,900 - 1,000 + al_casualty_loss_deduction: 1_900 + +- name: Case 9, a dependent's loss is left to the dependent's own return. + period: 2017 + input: + people: + person1: + age: 40 + casualty_loss: 3_000 + person2: + age: 10 + casualty_loss: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + al_agi: 10_000 + households: + household: + members: [person1, person2] + state_code: AL + output: + is_tax_unit_dependent: [false, true] + # The child's 2,000 is not the parent's loss. + # (3,000 - 100) - 10% x 10,000 = 2,900 - 1,000 + al_casualty_loss_deduction: 1_900 + +- name: Case 10, a negative Alabama AGI gives no floor. + period: 2017 + input: + state_code: AL + casualty_loss: 300 + al_agi: -1_000 + output: + # The loss after the $100 reduction is the most that can be deducted. + al_casualty_loss_deduction: 200 + +- name: Case 11, a reform that restores the federal deduction flows to Alabama. + period: 2025 + input: + gov.irs.deductions.itemized.casualty.active: true + state_code: AL + casualty_loss: 5_000 + al_agi: 20_000 + output: + # (5,000 - 100) - 10% x 20,000 = 4,900 - 2,000 + al_casualty_loss_deduction: 2_900 + +- name: Case 12, a negative Alabama AGI with no loss gives no deduction. + period: 2017 + input: + state_code: AL + casualty_loss: 0 + al_agi: -10_000 + output: + # Nothing to deduct: max(0 - 100, 0) = 0, whatever the AGI. al_casualty_loss_deduction: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/itemized/hi_casualty_loss_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/itemized/hi_casualty_loss_deduction.yaml index 0d28ce06199..5d1c126b001 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/itemized/hi_casualty_loss_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/itemized/hi_casualty_loss_deduction.yaml @@ -1,3 +1,16 @@ +# 2022 Form N-11 instructions, Casualty and Theft Losses (PDF p. 18): a loss is +# deductible only to the extent "The amount of EACH separate casualty or theft +# loss is more than $100, and ... The total amount of ALL losses during the +# year (reduced by the $100 limit) is more than 10% of your adjusted gross +# income." Worksheet A-5 (PDF p. 32): line 19 is the 2017 federal Form 4684, +# line 16 (after the $100 on line 11); line 21 is 10% of Hawaii AGI, "If zero +# or less, enter zero"; line 22 is line 19 minus line 21, not below zero. +# HRS 235-2.4(l)(1): "a $100 limitation per casualty". A joint return is one +# individual for the $100 rule (26 U.S.C. 165(h)(4)(B)). The model records one +# loss amount per person, so a return's losses are treated as one casualty. +# Act 35, SLH 2026, limits personal casualty losses to declared disasters from +# 2026; the model has no input that distinguishes them. + - name: base test period: 2022 input: @@ -15,7 +28,9 @@ members: [person1, person2] state_code: HI output: - hi_casualty_loss_deduction: 100 + filing_status: JOINT + # (100 + 100 - 100) - 10% x 1,000 = 100 - 100 + hi_casualty_loss_deduction: 0 - name: larger AGI period: 2022 @@ -34,8 +49,10 @@ members: [person1, person2] state_code: HI output: + filing_status: JOINT + # (100 + 100 - 100) - 10% x 2,000 = 100 - 200, below zero hi_casualty_loss_deduction: 0 - + - name: larger loss period: 2022 input: @@ -53,7 +70,9 @@ members: [person1, person2] state_code: HI output: - hi_casualty_loss_deduction: 200 + filing_status: JOINT + # (200 + 100 - 100) - 10% x 1,000 = 200 - 100 + hi_casualty_loss_deduction: 100 - name: AGI exceed loss period: 2022 @@ -72,4 +91,129 @@ members: [person1, person2] state_code: HI output: + filing_status: JOINT + # (100 + 100 - 100) - 10% x 3,000 = 100 - 300, below zero + hi_casualty_loss_deduction: 0 + +- name: Case 5, a loss of exactly $100 is fully absorbed by the $100 reduction. + period: 2025 + input: + casualty_loss: 100 + hi_agi: 0 + state_code: HI + output: + # max(100 - 100, 0) - 10% x 0 + hi_casualty_loss_deduction: 0 + +- name: Case 6, a loss of $101 leaves $1 after the $100 reduction. + period: 2025 + input: + casualty_loss: 101 + hi_agi: 0 + state_code: HI + output: + # max(101 - 100, 0) - 10% x 0 + hi_casualty_loss_deduction: 1 + +- name: Case 7, a loss under $100 is not deductible. + period: 2025 + input: + casualty_loss: 60 + hi_agi: 0 + state_code: HI + output: + hi_casualty_loss_deduction: 0 + +- name: Case 8, the 10 percent floor applies after the $100 reduction. + period: 2025 + input: + casualty_loss: 5_000 + hi_agi: 20_000 + state_code: HI + output: + # Worksheet A-5: line 19 = 5,000 - 100 = 4,900; line 21 = 10% x 20,000 + # = 2,000; line 22 = 4,900 - 2,000. + hi_casualty_loss_deduction: 2_900 + # Hawaii allows the loss though the federal deduction is suspended. + casualty_loss_deduction: 0 + +- name: Case 9, a joint return reduces the spouses' pooled losses by $100 once. + period: 2025 + input: + people: + person1: + age: 40 + casualty_loss: 600 + person2: + age: 40 + casualty_loss: 400 + tax_units: + tax_unit: + members: [person1, person2] + hi_agi: 3_000 + households: + household: + members: [person1, person2] + state_code: HI + output: + # (600 + 400 - 100) - 10% x 3,000 = 900 - 300 + hi_casualty_loss_deduction: 600 + +- name: Case 10, a dependent's loss is left to the dependent's own return. + period: 2025 + input: + people: + person1: + age: 40 + casualty_loss: 1_000 + person2: + age: 10 + casualty_loss: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + hi_agi: 5_000 + households: + household: + members: [person1, person2] + state_code: HI + output: + is_tax_unit_dependent: [false, true] + # The child's 2,000 is not the parent's loss. + # (1,000 - 100) - 10% x 5,000 = 900 - 500 + hi_casualty_loss_deduction: 400 + +- name: Case 11, a negative Hawaii AGI gives no floor. + period: 2025 + input: + casualty_loss: 300 + hi_agi: -1_000 + state_code: HI + output: + # Line 21: 10% x -1,000 is less than zero, so zero. 300 - 100 - 0 + hi_casualty_loss_deduction: 200 + +- name: Case 12, from 2026 Hawaii allows only declared-disaster losses. + period: 2026 + input: + casualty_loss: 5_000 + hi_agi: 20_000 + state_code: HI + output: + # Act 35, SLH 2026, makes 26 U.S.C. 165(h)(5) operative for Hawaii. + hi_casualty_loss_deduction: 0 + +- name: Case 13, a reform that restores the federal deduction does not reach Hawaii. + period: 2026 + input: + gov.irs.deductions.itemized.casualty.active: true + casualty_loss: 5_000 + hi_agi: 20_000 + adjusted_gross_income: 20_000 + state_code: HI + output: + # Hawaii conforms to the Code as of December 31, 2025 and keeps the + # 165(h)(5) limit from 2026; the federal deduction follows the reform. + # (5,000 - 100) - 10% x 20,000 = 4,900 - 2,000 + casualty_loss_deduction: 2_900 hi_casualty_loss_deduction: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit.yaml index 9e4f2540b71..8cfb8bc8538 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit.yaml @@ -223,3 +223,34 @@ # Same household, larger exclusion ($12,600) leaves a smaller expected # contribution, so the credit is higher: $539.67. mt_elderly_homeowner_or_renter_credit: 539.67 + +- name: 2023 Elderly Homeowner/Renter Credit Schedule worked case, a capital loss does not reduce gross household income + period: 2023 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + taxable_pension_income: 20_000 + long_term_capital_gains: -3_000 + social_security_retirement: 10_000 + real_estate_taxes: 2_000 + mt_refundable_credits_before_renter_credit: 0 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_name: MT + output: + # Line 1 federal AGI 17_000 (Social Security untaxed: 17_000 + 5_000 is + # under the 25_000 base); line 5 untaxed Social Security 10_000; line 9 + # losses 3_000; line 10 gross household income 30_000. + mt_elderly_homeowner_or_renter_credit_gross_household_income: 30_000 + # Line 12 = 30_000 - 12_600 = 17_400; line 13 multiplier 0.05; + # line 14 = 870. + mt_elderly_homeowner_or_renter_credit_net_household_income: 870 + # Line 18 = 2_000; line 19 = 1_130; line 20 = min(1_130, 1_150); + # line 21 = 100% (under 35_000); line 22 = 1_130. + mt_elderly_homeowner_or_renter_credit: 1_130 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_household_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_household_income.yaml index cee870a82af..38e02773559 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_household_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_household_income.yaml @@ -37,3 +37,51 @@ # § 15-30-2337(9)(a)(viii) requires all SS to be counted, even the # portion excluded from federal AGI. mt_elderly_homeowner_or_renter_credit_gross_household_income: 30_000 + +- name: A capital loss deducted in federal AGI is added back + period: 2023 + input: + people: + person1: + age: 70 + taxable_pension_income: 20_000 + long_term_capital_gains: -3_000 + mt_refundable_credits_before_renter_credit: 0 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_name: MT + output: + # § 15-30-2337(9)(a): federal AGI "without regard to loss". 2023 Elderly + # Homeowner/Renter Credit Schedule: + # line 1 federal AGI 20_000 - 3_000 = 17_000; line 9 adds back the 3_000 + # capital loss; line 10 = 20_000. + mt_elderly_homeowner_or_renter_credit_gross_household_income: 20_000 + +- name: A business loss deducted in federal AGI is added back once for the return + period: 2024 + input: + people: + person1: + age: 70 + taxable_pension_income: 20_000 + mt_refundable_credits_before_renter_credit: 0 + person2: + age: 68 + self_employment_income: -5_000 + mt_refundable_credits_before_renter_credit: 0 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_name: MT + output: + # Federal AGI 20_000 - 5_000 = 15_000; the 5_000 loss is added back, so + # gross household income is 20_000 (2024 Schedule 2EC line 18). Net household + # income: (20_000 - 12_600) * 0.035 = 259, allocated to the head. + mt_elderly_homeowner_or_renter_credit_net_household_income: [259, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction.yaml index df49679c68b..4cdfcd2395d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction.yaml @@ -19,8 +19,8 @@ state_code: MT output: # One qualifying individual caps expenses at 2_400. - # Head receives half: 2_400 * 0.5 = 1_200. - mt_child_dependent_care_expense_deduction: [1_200, 0] + # A single filer enters the full line 7 amount: 2_400. + mt_child_dependent_care_expense_deduction: [2_400, 0] - name: Care expense greater than maximum amount with moderate AGI and 1 child period: 2021 @@ -43,8 +43,8 @@ state_code: MT output: # 2_400 - 0.5 * (20_000 - 18_000) = 1_400. - # Head receives half: 1_400 * 0.5 = 700. - mt_child_dependent_care_expense_deduction: [700, 0] + # A single filer enters the full line 7 amount: 1_400. + mt_child_dependent_care_expense_deduction: [1_400, 0] - name: Care expense greater than maximum amount with high AGI and 1 child period: 2021 @@ -92,8 +92,8 @@ state_code: MT output: # Two qualifying individuals cap expenses at 3_600. - # Head receives half: 3_600 * 0.5 = 1_800. - mt_child_dependent_care_expense_deduction: [1_800, 0, 0] + # A single filer enters the full line 7 amount: 3_600. + mt_child_dependent_care_expense_deduction: [3_600, 0, 0] - name: Care expense greater than maximum amount with moderate AGI and 2 children period: 2021 @@ -119,8 +119,8 @@ state_code: MT output: # 3_600 - 0.5 * (22_000 - 18_000) = 1_600. - # Head receives half: 1_600 * 0.5 = 800. - mt_child_dependent_care_expense_deduction: [800, 0, 0] + # A single filer enters the full line 7 amount: 1_600. + mt_child_dependent_care_expense_deduction: [1_600, 0, 0] - name: Care expense greater than maximum amount with high AGI and 2 children period: 2021 @@ -174,8 +174,8 @@ state_code: MT output: # Three qualifying individuals cap expenses at 4_800. - # Head receives half: 4_800 * 0.5 = 2_400. - mt_child_dependent_care_expense_deduction: [2_400, 0, 0, 0] + # A single filer enters the full line 7 amount: 4_800. + mt_child_dependent_care_expense_deduction: [4_800, 0, 0, 0] - name: Care expense greater than maximum amount with moderate AGI and 3 children period: 2021 @@ -204,8 +204,8 @@ state_code: MT output: # 4_800 - 0.5 * (24_000 - 18_000) = 1_800. - # Head receives half: 1_800 * 0.5 = 900. - mt_child_dependent_care_expense_deduction: [900, 0, 0, 0] + # A single filer enters the full line 7 amount: 1_800. + mt_child_dependent_care_expense_deduction: [1_800, 0, 0, 0] - name: Care expense greater than maximum amount with high AGI and 3 children period: 2021 @@ -255,8 +255,8 @@ members: [person1, person2] state_code: MT output: - # Head receives half: 2_000 * 0.5 = 1_000. - mt_child_dependent_care_expense_deduction: [1_000, 0] + # A single filer enters the full line 7 amount: 2_000. + mt_child_dependent_care_expense_deduction: [2_000, 0] - name: Care expense less than maximum amount with high AGI and 1 child period: 2021 @@ -303,8 +303,8 @@ members: [person1, person2, person3] state_code: MT output: - # Head receives half: 3_000 * 0.5 = 1_500. - mt_child_dependent_care_expense_deduction: [1_500, 0, 0] + # A single filer enters the full line 7 amount: 3_000. + mt_child_dependent_care_expense_deduction: [3_000, 0, 0] - name: Care expense less than maximum amount with high AGI and 2 children period: 2021 @@ -357,8 +357,8 @@ members: [person1, person2, person3, person4] state_code: MT output: - # Head receives half: 4_000 * 0.5 = 2_000. - mt_child_dependent_care_expense_deduction: [2_000, 0, 0, 0] + # A single filer enters the full line 7 amount: 4_000. + mt_child_dependent_care_expense_deduction: [4_000, 0, 0, 0] - name: Care expense less than maximum amount with high AGI and 3 children period: 2021 @@ -441,8 +441,8 @@ state_code: MT output: # One qualifying individual caps expenses at 2_400 (Form 2441-M line 2). - # Head receives half: 2_400 * 0.5 = 1_200. - mt_child_dependent_care_expense_deduction: [1_200, 0] + # A single filer enters the full line 7 amount: 2_400. + mt_child_dependent_care_expense_deduction: [2_400, 0] - name: Case 18, capable disabled adult care expenses are excluded. period: 2021 @@ -470,8 +470,8 @@ state_code: MT output: # Only the child qualifies, so 2_000 of adult care expenses are excluded. - # Head receives half of the 1_000 childcare expense deduction. - mt_child_dependent_care_expense_deduction: [500, 0, 0] + # A single filer enters the full 1_000 childcare expense deduction. + mt_child_dependent_care_expense_deduction: [1_000, 0, 0] - name: Case 19, a child and an incapacitated adult dependent both count toward the tier. period: 2021 @@ -500,8 +500,8 @@ output: # Two qualifying individuals cap expenses at 3_600 (Form 2441-M line 2). # Childcare 3_000 + adult care 1_000 = 4_000, capped at 3_600. - # Head receives half: 3_600 * 0.5 = 1_800. - mt_child_dependent_care_expense_deduction: [1_800, 0, 0] + # A single filer enters the full line 7 amount: 3_600. + mt_child_dependent_care_expense_deduction: [3_600, 0, 0] - name: Case 20, adult care expenses cannot exceed the one-qualifying-individual tier cap. period: 2021 @@ -525,8 +525,8 @@ state_code: MT output: # One qualifying individual caps expenses at 2_400 (Form 2441-M line 2). - # Head receives half: 2_400 * 0.5 = 1_200. - mt_child_dependent_care_expense_deduction: [1_200, 0] + # A single filer enters the full line 7 amount: 2_400. + mt_child_dependent_care_expense_deduction: [2_400, 0] - name: Case 21, incapacitated spouse care expenses qualify. period: 2021 @@ -606,8 +606,8 @@ output: # One qualifying individual caps expenses at 2_400 (Form 2441-M line 2). # Childcare 1_500 + care expenses 1_000 = 2_500, capped at 2_400. - # Head receives half: 2_400 * 0.5 = 1_200. - mt_child_dependent_care_expense_deduction: [1_200, 0] + # A single filer enters the full line 7 amount: 2_400. + mt_child_dependent_care_expense_deduction: [2_400, 0] - name: Case 24, combined childcare and adult care expenses are capped by the three-qualifying-individual tier. period: 2021 @@ -643,3 +643,109 @@ # Childcare 4_000 + adult care 2_000 = 6_000, capped at 4_800. # The deduction is divided equally between spouses: 4_800 * 0.5 = 2_400. mt_child_dependent_care_expense_deduction: [2_400, 2_400, 0, 0] + +- name: Case 25, the phase-out uses the couple's combined Montana AGI, then each column gets half + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + is_tax_unit_head: true + mt_agi_indiv: 20_000 + person2: + is_tax_unit_spouse: true + mt_agi_indiv: 0 + person3: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3] + tax_unit_childcare_expenses: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # Form 2441-M (2022): line 2 = min(3_000, 2_400) = 2_400; line 3 adds + # columns A and B of Form 2 line 14 = 20_000 + 0 = 20_000; line 5 = 2_000; + # line 6 = 1_000; line 7 = 1_400. Filing separately on the same form, each + # spouse enters one-half of line 7 (700). Applying the phase-out to each + # spouse's own AGI would give 700 and 1_200. + mt_child_dependent_care_expense_deduction_eligible_expenses: 2_400 + mt_child_dependent_care_expense_deduction: [700, 700, 0] + +- name: Case 26, a joint return uses the return's Montana AGI and claims the whole deduction + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + is_tax_unit_head: true + person2: + is_tax_unit_spouse: true + person3: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3] + tax_unit_childcare_expenses: 3_000 + mt_agi_joint: 20_000 + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # Form 2441-M lines 2-7 with line 3 = 20_000: 2_400 - 0.5 * 2_000 = 1_400, + # entered in full on the joint return. + mt_child_dependent_care_expense_deduction_joint: 1_400 + +- name: Case 27, the joint deduction is repealed beginning in 2024 + period: 2024 + input: + people: + person1: + is_tax_unit_head: true + person2: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + tax_unit_childcare_expenses: 3_000 + mt_agi_joint: 10_000 + households: + household: + members: [person1, person2] + state_code: MT + output: + mt_child_dependent_care_expense_deduction_joint: 0 + +- name: Case 28, a married person filing on a separate form cannot take the deduction + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + mt_agi_indiv: 15_000 + person2: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + filing_status: SEPARATE + tax_unit_childcare_expenses: 2_000 + mt_agi_joint: 15_000 + households: + household: + members: [person1, person2] + state_code: MT + output: + # MCA 15-30-2131(1)(c)(vi)(A): "married couples shall file a joint return + # or file separately on the same form". 2022 instructions, line 14: "If + # you are married and filing separately on separate forms, or your spouse + # is not filing, you cannot qualify for this deduction." + mt_child_dependent_care_expense_deduction: [0, 0] + mt_child_dependent_care_expense_deduction_joint: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_indiv.yaml new file mode 100644 index 00000000000..06f6e05ad30 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_indiv.yaml @@ -0,0 +1,142 @@ +# 2022 Form 2 instructions, Itemized Deductions Schedule, line 15 (PDF pp. 35-36): +# "To determine your casualty and/or theft loss, use your Montana Adjusted +# Gross Income in place of the Federal Adjusted Gross Income. If you and your +# spouse are filing separately, you each should complete a separate federal +# Form 4684 to determine the amount of your separate casualty and/or theft +# loss." +# 2022 Form 2 instructions, Filing Separately When Married (PDF p. 11): +# "Deductions that are attributable to only one spouse must be claimed by that +# spouse." +# Form 4684 reduces each casualty by $100 (2022 Form 4684 line 11) and allows the +# rest above 10% of adjusted gross income (line 17). IRS Publication 547 (2022, +# PDF p. 10): "If you and your spouse have a casualty or theft loss and you file +# separate returns, each of you must reduce your loss by $100." and "If one +# spouse owns the property, only that spouse can claim a loss deduction on a +# separate return." The model has no input that distinguishes federally declared +# disaster losses; like the federal deduction, it allows no personal casualty +# loss from 2018 unless gov.irs.deductions.itemized.casualty.active is switched +# on, as these tests do. + +- name: Only the spouse who had the loss deducts it, above 10% of their own Montana AGI + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 30_000 + mt_agi_indiv: 60_000 + person2: + age: 40 + mt_agi_indiv: 40_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # (30,000 - 100) - 10% x 60,000; the spouse has no loss. + mt_casualty_loss_deduction_indiv: [23_900, 0] + +- name: Each spouse's loss is floored at 10% of that spouse's Montana AGI + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 30_000 + mt_agi_indiv: 60_000 + person2: + age: 40 + casualty_loss: 5_000 + mt_agi_indiv: 40_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # (30,000 - 100) - 6,000 and (5,000 - 100) - 4,000: each spouse reduces + # their own loss by $100. + mt_casualty_loss_deduction_indiv: [23_900, 900] + +- name: A dependent's loss stays off the parents' columns, like the dependent's income + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 30_000 + person2: + age: 40 + employment_income: 40_000 + person3: + age: 17 + is_tax_unit_dependent: true + employment_income: 5_000 + casualty_loss: 10_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # The dependent's wages are not in the head's Montana AGI (60,000), and the + # dependent's loss belongs on the dependent's own return: + # (30,000 - 100) - 10% x 60,000 for the head. + mt_casualty_loss_deduction_indiv: [23_900, 0, 0] + +- name: Spouses filing separately on one form in 2024 have no Montana casualty line + period: 2024 + input: + # Allowing filing status 2a in 2024 (as a reform would) reaches the + # separate path; the discontinued schedule still gives no deduction. + gov.states.mt.tax.income.married_filing_separately_on_same_return_allowed: true + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 30_000 + mt_agi_indiv: 60_000 + person2: + age: 40 + mt_agi_indiv: 40_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + mt_casualty_loss_deduction_indiv: [0, 0] + +- name: No loss is deductible while the federal casualty deduction is suspended + period: 2022 + input: + people: + person1: + age: 40 + casualty_loss: 30_000 + mt_agi_indiv: 60_000 + person2: + age: 40 + mt_agi_indiv: 40_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + mt_casualty_loss_deduction_indiv: [0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_joint.yaml new file mode 100644 index 00000000000..261add5e5c5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_joint.yaml @@ -0,0 +1,205 @@ +# 2022 Form 2 instructions, Itemized Deductions Schedule, line 15 (PDF pp. 35-36): +# "You may deduct a casualty and theft loss from a federally declared disaster +# (other than net qualified disaster losses). If you have a casualty and/or +# theft loss, complete federal Form 4684 to figure the amount of the Montana +# loss that you can enter on this line. To determine your casualty and/or theft +# loss, use your Montana Adjusted Gross Income in place of the Federal Adjusted +# Gross Income." and "Deductions for all other casualty and theft losses are +# suspended until tax years beginning after December 31, 2025." +# Form 4684 reduces each casualty by $100 (2022 Form 4684 line 11) and allows the +# rest above 10% of adjusted gross income (line 17). IRS Publication 547 (2022, +# PDF p. 10): "If you and your spouse file a joint return, you are treated as one +# individual in applying the $100 rule." The model has no input that +# distinguishes federally declared disaster losses; like the federal deduction, +# it allows no personal casualty loss from 2018 unless +# gov.irs.deductions.itemized.casualty.active is switched on, as these tests do. + +- name: A joint return deducts the couple's loss once, above 10% of Montana AGI + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 30_000 + person2: + age: 40 + tax_units: + tax_unit: + members: [person1, person2] + mt_agi_joint: 100_000 + households: + household: + members: [person1, person2] + state_code: MT + output: + # (30,000 - 100) - 10% x 100,000 + mt_casualty_loss_deduction_joint: 19_900 + +- name: Both spouses' losses are pooled on a joint return + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 30_000 + person2: + age: 40 + casualty_loss: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + mt_agi_joint: 100_000 + households: + household: + members: [person1, person2] + state_code: MT + output: + # (35,000 - 100) - 10% x 100,000; the joint return reduces by $100 once. + mt_casualty_loss_deduction_joint: 24_900 + +- name: A dependent's loss is left to the dependent's own return + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 30_000 + person2: + age: 40 + employment_income: 40_000 + person3: + age: 17 + is_tax_unit_dependent: true + employment_income: 5_000 + casualty_loss: 10_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # Montana AGI is the spouses' 100,000 (the dependent's wages are on the + # dependent's own return), and so is the dependent's loss: + # (30,000 - 100) - 10% x 100,000. + mt_casualty_loss_deduction_joint: 19_900 + +- name: The 10% floor uses Montana AGI, not federal AGI + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 100_000 + casualty_loss: 30_000 + tax_units: + tax_unit: + members: [person1] + mt_agi_joint: 80_000 + households: + household: + members: [person1] + state_code: MT + output: + # (30,000 - 100) - 10% x 80,000. A federal AGI floor would give 19,900. + mt_casualty_loss_deduction_joint: 21_900 + +- name: A loss whose excess over $100 equals 10% of Montana AGI is not deductible + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 10_100 + tax_units: + tax_unit: + members: [person1] + mt_agi_joint: 100_000 + households: + household: + members: [person1] + state_code: MT + output: + mt_casualty_loss_deduction_joint: 0 + +- name: One dollar above the floor is deductible + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 10_101 + tax_units: + tax_unit: + members: [person1] + mt_agi_joint: 100_000 + households: + household: + members: [person1] + state_code: MT + output: + mt_casualty_loss_deduction_joint: 1 + +- name: A loss under $100 is not deductible even with no Montana AGI + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 80 + tax_units: + tax_unit: + members: [person1] + mt_agi_joint: 0 + households: + household: + members: [person1] + state_code: MT + output: + mt_casualty_loss_deduction_joint: 0 + +- name: No loss is deductible while the federal casualty deduction is suspended + period: 2022 + input: + people: + person1: + age: 40 + casualty_loss: 30_000 + tax_units: + tax_unit: + members: [person1] + mt_agi_joint: 100_000 + households: + household: + members: [person1] + state_code: MT + output: + mt_casualty_loss_deduction_joint: 0 + +- name: Montana discontinued its Itemized Deductions Schedule in 2024 + period: 2024 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + casualty_loss: 30_000 + tax_units: + tax_unit: + members: [person1] + mt_agi_joint: 100_000 + households: + household: + members: [person1] + state_code: MT + output: + mt_casualty_loss_deduction_joint: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_federal_income_tax_deduction_for_federal_itemization_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_federal_income_tax_deduction_for_federal_itemization_indiv.yaml index e0fed58cbeb..941a60e6c1b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_federal_income_tax_deduction_for_federal_itemization_indiv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_federal_income_tax_deduction_for_federal_itemization_indiv.yaml @@ -1,39 +1,46 @@ -- name: Deductions split evenly +# 2022 Form 2 instructions, Itemized Deductions Schedule, line 4 (PDF p. 33): +# withholding is reported by the spouse who earned the income, and each +# spouse filing separately is limited to 5,000. + +- name: Each spouse deducts their own withholding estimate period: 2021 input: people: person1: - mt_agi_indiv: 500 + mt_withheld_income_tax: 3_000 + adjusted_gross_income_person: 50_000 person2: - mt_agi_indiv: 500 + mt_withheld_income_tax: 1_000 + adjusted_gross_income_person: 50_000 tax_units: tax_unit: members: [person1, person2] - mt_federal_income_tax_deduction_for_federal_itemization: 3_000 state_filing_status_if_married_filing_separately_on_same_return: SEPARATE households: household: members: [person1, person2] state_code: MT output: - mt_federal_income_tax_deduction_for_federal_itemization_indiv: [1_500, 1_500] + # Prorating the couple's 4_000 by Montana AGI would give 2_000 / 2_000. + mt_federal_income_tax_deduction_for_federal_itemization_indiv: [3_000, 1_000] -- name: Deductions capped at max amount individually +- name: Each spouse is capped at 5,000 on their own amount period: 2021 input: people: person1: - mt_agi_indiv: 100 + mt_withheld_income_tax: 7_000 + adjusted_gross_income_person: 60_000 person2: - mt_agi_indiv: 900 + mt_withheld_income_tax: 1_000 + adjusted_gross_income_person: 40_000 tax_units: tax_unit: members: [person1, person2] - mt_federal_income_tax_deduction_for_federal_itemization: 10_000 state_filing_status_if_married_filing_separately_on_same_return: SEPARATE households: household: members: [person1, person2] state_code: MT output: - mt_federal_income_tax_deduction_for_federal_itemization_indiv: [1_000, 5_000] + mt_federal_income_tax_deduction_for_federal_itemization_indiv: [5_000, 1_000] 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..c7a4ffc9f8b 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 @@ -5,7 +5,7 @@ investment_interest_expense: 265 mt_salt_deduction: 5_000 mt_medical_expense_deduction_indiv: 1_000 - casualty_loss_deduction: 400 + mt_casualty_loss_deduction_indiv: 400 mt_child_dependent_care_expense_deduction: 123 mt_federal_income_tax_deduction_for_federal_itemization_indiv: 2_000 state_code: MT @@ -19,7 +19,7 @@ investment_interest_expense: 1_234 mt_salt_deduction: 10_000 mt_medical_expense_deduction_indiv: 3_000 - casualty_loss_deduction: 0 + mt_casualty_loss_deduction_indiv: 0 mt_child_dependent_care_expense_deduction: 0 mt_federal_income_tax_deduction_for_federal_itemization_indiv: 2_000 state_code: MT @@ -33,7 +33,7 @@ mortgage_interest: 34 mt_salt_deduction: 1_035 mt_medical_expense_deduction_indiv: 3_000 - casualty_loss_deduction: 745 + mt_casualty_loss_deduction_indiv: 745 mt_child_dependent_care_expense_deduction: 1_004 mt_federal_income_tax_deduction_for_federal_itemization_indiv: 2_000 state_code: MT @@ -47,20 +47,20 @@ people: person1: is_tax_unit_head_or_spouse: true - mt_misc_deductions: 100 + mt_casualty_loss_deduction_indiv: 100 mt_medical_expense_deduction_indiv: 200 mt_salt_deduction: 300 mt_federal_income_tax_deduction_for_federal_itemization_indiv: 400 person2: is_tax_unit_head_or_spouse: true - mt_misc_deductions: 100 + mt_casualty_loss_deduction_indiv: 100 mt_medical_expense_deduction_indiv: 200 mt_salt_deduction: 300 mt_federal_income_tax_deduction_for_federal_itemization_indiv: 100 person3: is_tax_unit_head_or_spouse: false is_tax_unit_dependent: true - mt_misc_deductions: 100 + mt_casualty_loss_deduction_indiv: 100 mt_medical_expense_deduction_indiv: 12 mt_salt_deduction: 200 mt_federal_income_tax_deduction_for_federal_itemization_indiv: 100 @@ -74,3 +74,37 @@ state_code: MT output: mt_itemized_deductions_for_federal_itemization_indiv: [1_000, 700, 0] + +# 2022 Form 2 instructions, Itemized Deductions Schedule, line 15 (PDF pp. 35-36): +# complete federal Form 4684 using Montana AGI in place of federal AGI; spouses +# filing separately each complete their own Form 4684. Each spouse deducts only +# their own loss, on their own Montana AGI; the tax unit's loss must not be +# given to every member. + +- name: Only the spouse who had the casualty loss deducts it when filing separately + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 30_000 + mt_salt_deduction: 0 + mt_federal_income_tax_deduction_for_federal_itemization_indiv: 0 + person2: + age: 40 + employment_income: 40_000 + mt_salt_deduction: 0 + mt_federal_income_tax_deduction_for_federal_itemization_indiv: 0 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # (30,000 - 100) - 10% x 60,000 Montana AGI in the head's column; none for + # the spouse. + mt_itemized_deductions_for_federal_itemization_indiv: [23_900, 0] 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..af31671a593 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 @@ -6,8 +6,8 @@ investment_interest_expense: 265 mt_salt_deduction: 5_000 mt_medical_expense_deduction_joint: 1_000 - casualty_loss_deduction: 400 - mt_child_dependent_care_expense_deduction: 123 + mt_casualty_loss_deduction_joint: 400 + mt_child_dependent_care_expense_deduction_joint: 123 mt_federal_income_tax_deduction_for_federal_itemization: 2_000 state_code: MT output: @@ -21,8 +21,8 @@ mortgage_interest: 1_234 mt_salt_deduction: 10_000 mt_medical_expense_deduction_joint: 3_000 - casualty_loss_deduction: 0 - mt_child_dependent_care_expense_deduction: 0 + mt_casualty_loss_deduction_joint: 0 + mt_child_dependent_care_expense_deduction_joint: 0 mt_federal_income_tax_deduction_for_federal_itemization: 2_000 state_code: MT output: @@ -36,8 +36,8 @@ mortgage_interest: 34 mt_salt_deduction: 1_035 mt_medical_expense_deduction_joint: 3_000 - casualty_loss_deduction: 745 - mt_child_dependent_care_expense_deduction: 1_004 + mt_casualty_loss_deduction_joint: 745 + mt_child_dependent_care_expense_deduction_joint: 1_004 mt_federal_income_tax_deduction_for_federal_itemization: 2_000 state_code: MT output: @@ -50,18 +50,15 @@ people: person1: is_tax_unit_head: true - mt_misc_deductions: 100 mt_medical_expense_deduction_joint: 200 mt_salt_deduction: 300 investment_interest_expense: 100 person2: is_tax_unit_head: false - mt_misc_deductions: 100 mt_medical_expense_deduction_joint: 200 mt_salt_deduction: 300 person3: is_tax_unit_head: false - mt_misc_deductions: 100 mt_medical_expense_deduction_joint: 12 mt_salt_deduction: 200 households: @@ -72,5 +69,66 @@ tax_unit: members: [person1, person2, person3] mt_federal_income_tax_deduction_for_federal_itemization: 600 + mt_casualty_loss_deduction_joint: 100 output: - mt_itemized_deductions_for_federal_itemization_joint: [2_212, 0, 0] + mt_itemized_deductions_for_federal_itemization_joint: [2_012, 0, 0] + +# 2022 Form 2 instructions, Itemized Deductions Schedule, line 15 (PDF pp. 35-36): +# complete federal Form 4684 using Montana AGI in place of federal AGI; spouses +# filing separately each complete their own Form 4684. A joint return pools the +# tax unit's losses, so they must be counted once, not once per member. + +- name: A couple's casualty loss counts once on a joint return + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 30_000 + mt_salt_deduction: 0 + person2: + age: 40 + employment_income: 40_000 + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [person1, person2] + mt_federal_income_tax_deduction_for_federal_itemization: 0 + households: + household: + members: [person1, person2] + state_code: MT + output: + # (30,000 - 100) - 10% x 100,000 Montana AGI, counted once. + mt_itemized_deductions_for_federal_itemization_joint: [19_900, 0] + +- name: A dependent in the tax unit does not repeat the joint casualty loss + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 30_000 + mt_salt_deduction: 0 + person2: + age: 40 + employment_income: 40_000 + mt_salt_deduction: 0 + person3: + age: 10 + is_tax_unit_dependent: true + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [person1, person2, person3] + mt_federal_income_tax_deduction_for_federal_itemization: 0 + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + mt_itemized_deductions_for_federal_itemization_joint: [19_900, 0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_federal_income_tax_deduction_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_federal_income_tax_deduction_indiv.yaml index 4b0d588ce5e..c7604752c4d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_federal_income_tax_deduction_indiv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_federal_income_tax_deduction_indiv.yaml @@ -1,39 +1,120 @@ -- name: Deductions split evenly +# 2022 Form 2 instructions, Itemized Deductions Schedule, line 4 (PDF p. 33): +# "If you are married filing separately with your spouse, the federal income +# tax withheld should be reported by the spouse who earned the income." and +# "If your filing status is Married Filing Separately, you are each limited to +# the $5,000 federal tax deduction and you cannot arbitrarily allocate this +# deduction between spouses." + +- name: Federal income tax is attributed by each spouse's share of federal AGI period: 2021 + absolute_error_margin: 0.01 input: people: person1: - mt_agi_indiv: 500 + adjusted_gross_income_person: 60_000 person2: - mt_agi_indiv: 500 + adjusted_gross_income_person: 40_000 tax_units: tax_unit: members: [person1, person2] - mt_federal_income_tax_deduction_unit: 3_000 + income_tax_before_refundable_credits: 3_000 state_filing_status_if_married_filing_separately_on_same_return: SEPARATE households: household: members: [person1, person2] state_code: MT output: - mt_federal_income_tax_deduction_indiv: [1_500, 1_500] + mt_federal_income_tax_deduction_share: [0.6, 0.4] + mt_federal_income_tax_deduction_indiv: [1_800, 1_200] -- name: Deductions capped at max amount individually - period: 2021 +- name: Each spouse's own federal tax is capped at 5,000, not a share of the joint cap + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + adjusted_gross_income_person: 80_000 + person2: + adjusted_gross_income_person: 20_000 + tax_units: + tax_unit: + members: [person1, person2] + income_tax_before_refundable_credits: 30_000 + state_filing_status_if_married_filing_separately_on_same_return: SEPARATE + households: + household: + members: [person1, person2] + state_code: MT + output: + # Federal tax attributed 24_000 / 6_000; each spouse is limited to 5_000. + # Capping the couple at 10_000 first and then splitting 80% / 20% would + # give 5_000 / 2_000. + mt_federal_income_tax_deduction_indiv: [5_000, 5_000] + +- name: Montana-only subtractions do not shift federal tax between spouses + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + adjusted_gross_income_person: 50_000 + person2: + adjusted_gross_income_person: 50_000 + mt_subtractions: 20_000 + tax_units: + tax_unit: + members: [person1, person2] + income_tax_before_refundable_credits: 6_000 + state_filing_status_if_married_filing_separately_on_same_return: SEPARATE + households: + household: + members: [person1, person2] + state_code: MT + output: + # The federal tax was paid on 50_000 of federal income each. Prorating by + # Montana AGI (50_000 / 30_000) would give 3_750 / 2_250. + mt_federal_income_tax_deduction_indiv: [3_000, 3_000] + +- name: A dependent's income does not draw a share of the parents' federal tax + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + adjusted_gross_income_person: 40_000 + person2: + adjusted_gross_income_person: 0 + person3: + is_tax_unit_dependent: true + adjusted_gross_income_person: 0 + tax_units: + tax_unit: + members: [person1, person2, person3] + income_tax_before_refundable_credits: 2_000 + state_filing_status_if_married_filing_separately_on_same_return: SEPARATE + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + mt_federal_income_tax_deduction_indiv: [2_000, 0, 0] + +- name: The deduction is repealed from 2024 + period: 2024 input: people: person1: - mt_agi_indiv: 100 + adjusted_gross_income_person: 60_000 person2: - mt_agi_indiv: 900 + adjusted_gross_income_person: 40_000 tax_units: tax_unit: members: [person1, person2] - mt_federal_income_tax_deduction_unit: 10_000 + income_tax_before_refundable_credits: 3_000 state_filing_status_if_married_filing_separately_on_same_return: SEPARATE households: household: members: [person1, person2] state_code: MT output: - mt_federal_income_tax_deduction_indiv: [1_000, 5_000] + mt_federal_income_tax_deduction_indiv: [0, 0] 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..d41523a13f9 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 @@ -5,7 +5,7 @@ investment_interest_expense: 265 mt_salt_deduction: 5_000 mt_medical_expense_deduction_indiv: 1_000 - casualty_loss_deduction: 400 + mt_casualty_loss_deduction_indiv: 400 mt_child_dependent_care_expense_deduction: 123 mt_federal_income_tax_deduction_indiv: 2_000 state_code: MT @@ -19,7 +19,7 @@ investment_interest_expense: 1_234 mt_salt_deduction: 10_000 mt_medical_expense_deduction_indiv: 3_000 - casualty_loss_deduction: 0 + mt_casualty_loss_deduction_indiv: 0 mt_child_dependent_care_expense_deduction: 0 mt_federal_income_tax_deduction_indiv: 2_000 state_code: MT @@ -33,7 +33,7 @@ mortgage_interest: 34 mt_salt_deduction: 1_035 mt_medical_expense_deduction_indiv: 3_000 - casualty_loss_deduction: 745 + mt_casualty_loss_deduction_indiv: 745 mt_child_dependent_care_expense_deduction: 1_004 mt_federal_income_tax_deduction_indiv: 2_000 state_code: MT @@ -47,20 +47,20 @@ people: person1: is_tax_unit_head_or_spouse: true - mt_misc_deductions: 100 + mt_casualty_loss_deduction_indiv: 100 mt_medical_expense_deduction_indiv: 200 mt_salt_deduction: 300 mt_federal_income_tax_deduction_indiv: 400 person2: is_tax_unit_head_or_spouse: true - mt_misc_deductions: 100 + mt_casualty_loss_deduction_indiv: 100 mt_medical_expense_deduction_indiv: 200 mt_salt_deduction: 300 mt_federal_income_tax_deduction_indiv: 100 person3: is_tax_unit_head_or_spouse: false is_tax_unit_dependent: true - mt_misc_deductions: 100 + mt_casualty_loss_deduction_indiv: 100 mt_medical_expense_deduction_indiv: 12 mt_salt_deduction: 200 mt_federal_income_tax_deduction_indiv: 100 @@ -74,3 +74,37 @@ state_code: MT output: mt_itemized_deductions_indiv: [1_000, 700, 0] + +# 2022 Form 2 instructions, Itemized Deductions Schedule, line 15 (PDF pp. 35-36): +# complete federal Form 4684 using Montana AGI in place of federal AGI; spouses +# filing separately each complete their own Form 4684. Each spouse deducts only +# their own loss, on their own Montana AGI; the tax unit's loss must not be +# given to every member. + +- name: Only the spouse who had the casualty loss deducts it when filing separately + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 30_000 + mt_salt_deduction: 0 + mt_federal_income_tax_deduction_indiv: 0 + person2: + age: 40 + employment_income: 40_000 + mt_salt_deduction: 0 + mt_federal_income_tax_deduction_indiv: 0 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # (30,000 - 100) - 10% x 60,000 Montana AGI in the head's column; none for + # the spouse. + mt_itemized_deductions_indiv: [23_900, 0] 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..dbab8e1a2a5 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 @@ -6,8 +6,8 @@ investment_interest_expense: 265 mt_salt_deduction: 5_000 mt_medical_expense_deduction_joint: 1_000 - casualty_loss_deduction: 400 - mt_child_dependent_care_expense_deduction: 123 + mt_casualty_loss_deduction_joint: 400 + mt_child_dependent_care_expense_deduction_joint: 123 mt_federal_income_tax_deduction_unit: 2_000 state_code: MT output: @@ -21,8 +21,8 @@ mortgage_interest: 1_234 mt_salt_deduction: 10_000 mt_medical_expense_deduction_joint: 3_000 - casualty_loss_deduction: 0 - mt_child_dependent_care_expense_deduction: 0 + mt_casualty_loss_deduction_joint: 0 + mt_child_dependent_care_expense_deduction_joint: 0 mt_federal_income_tax_deduction_unit: 2_000 state_code: MT output: @@ -36,8 +36,8 @@ mortgage_interest: 34 mt_salt_deduction: 1_035 mt_medical_expense_deduction_joint: 3_000 - casualty_loss_deduction: 745 - mt_child_dependent_care_expense_deduction: 1_004 + mt_casualty_loss_deduction_joint: 745 + mt_child_dependent_care_expense_deduction_joint: 1_004 mt_federal_income_tax_deduction_unit: 2_000 state_code: MT output: @@ -50,18 +50,15 @@ people: person1: is_tax_unit_head: true - mt_misc_deductions: 100 mt_medical_expense_deduction_joint: 200 mt_salt_deduction: 300 investment_interest_expense: 100 person2: is_tax_unit_head: false - mt_misc_deductions: 100 mt_medical_expense_deduction_joint: 200 mt_salt_deduction: 300 person3: is_tax_unit_head: false - mt_misc_deductions: 100 mt_medical_expense_deduction_joint: 12 mt_salt_deduction: 200 households: @@ -72,5 +69,66 @@ tax_unit: members: [person1, person2, person3] mt_federal_income_tax_deduction_unit: 600 + mt_casualty_loss_deduction_joint: 100 output: - mt_itemized_deductions_joint: [2_212, 0, 0] + mt_itemized_deductions_joint: [2_012, 0, 0] + +# 2022 Form 2 instructions, Itemized Deductions Schedule, line 15 (PDF pp. 35-36): +# complete federal Form 4684 using Montana AGI in place of federal AGI; spouses +# filing separately each complete their own Form 4684. A joint return pools the +# tax unit's losses, so they must be counted once, not once per member. + +- name: A couple's casualty loss counts once on a joint return + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 30_000 + mt_salt_deduction: 0 + person2: + age: 40 + employment_income: 40_000 + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [person1, person2] + mt_federal_income_tax_deduction_unit: 0 + households: + household: + members: [person1, person2] + state_code: MT + output: + # (30,000 - 100) - 10% x 100,000 Montana AGI, counted once. + mt_itemized_deductions_joint: [19_900, 0] + +- name: A dependent in the tax unit does not repeat the joint casualty loss + period: 2022 + input: + gov.irs.deductions.itemized.casualty.active: true + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 30_000 + mt_salt_deduction: 0 + person2: + age: 40 + employment_income: 40_000 + mt_salt_deduction: 0 + person3: + age: 10 + is_tax_unit_dependent: true + mt_salt_deduction: 0 + tax_units: + tax_unit: + members: [person1, person2, person3] + mt_federal_income_tax_deduction_unit: 0 + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + mt_itemized_deductions_joint: [19_900, 0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/integration.yaml index 1427235ceaa..687a3ecabbf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/integration.yaml @@ -564,9 +564,12 @@ output: # $2,500 per-return cap split $1,250 per spouse (was double-counted to $5,000) mt_income_tax_rebate: [1_250, 1_250] - # Files separately: 5,099.51 - 1,250 + 3,719.51 - 1,250 = 6,319.02 + # Each spouse deducts their own federal income tax up to $5,000 (2021 + # federal tax 21,175 attributed 90/160 and 70/160), so both itemize 5,000 + # over the 4,830 standard deduction. Taxable income 82,420 and 62,420. + # Files separately: 5,087.78 - 1,250 + 3,707.78 - 1,250 = 6,295.56 # (old double-count subtracted $2,500 per column, understating tax by $2,500) - mt_income_tax: 6_319.02 + mt_income_tax: 6_295.56 - name: MT property tax rebate is not a Form 2 credit and is not tripled (issue 9347) absolute_error_margin: 0.01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/itemized/ny_casualty_loss_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/itemized/ny_casualty_loss_deduction.yaml new file mode 100644 index 00000000000..d0e452a5448 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/itemized/ny_casualty_loss_deduction.yaml @@ -0,0 +1,145 @@ +# 2025 Form IT-196 instructions, line 20 (PDF p. 3): "Your New York itemized +# deduction for casualty and theft losses is calculated using the federal rules +# that applied to tax year 2017." A loss is deductible only to the extent "the +# amount of each separate casualty or theft loss is more than $100, and ... the +# total amount of all losses during the year (reduced by the $100 limit in +# number 1 above) is more than 10% of the amount on Form IT-201, line 19". +# Casualty and theft worksheet, Section A (PDF p. 4): line 11 "Limitation per +# casualty" 100; line 17 "Enter 10% of your federal AGI from Form IT-201, line +# 19"; line 18 "Subtract line 17 from line 16 ... If the amount is zero or +# less, enter 0." +# IRS Publication 547 (2017, PDF p. 10): "If you and your spouse file a joint +# return, you are treated as one individual in applying the $100 rule." +# The model records one loss amount per person, not separate casualty events, +# so a return's losses are treated as one casualty. A dependent's loss belongs +# on the dependent's own return, as the dependent's income does. + +- name: Case 1, the $100 reduction applies before the 10 percent floor. + period: 2025 + input: + state_code: NY + employment_income: 100_000 + casualty_loss: 15_000 + output: + # Worksheet: line 12 = 15,000 - 100 = 14,900; line 17 = 10% x 100,000 + # = 10,000; line 18 = 14,900 - 10,000. + ny_casualty_loss_deduction: 4_900 + # New York allows the loss though the federal deduction is suspended. + casualty_loss_deduction: 0 + +- name: Case 2, a loss $100 above the floor nets to zero. + period: 2025 + input: + state_code: NY + employment_income: 100_000 + casualty_loss: 10_100 + output: + # (10,100 - 100) - 10% x 100,000 = 10,000 - 10,000 + ny_casualty_loss_deduction: 0 + +- name: Case 3, a loss $101 above the floor leaves $1. + period: 2025 + input: + state_code: NY + employment_income: 100_000 + casualty_loss: 10_101 + output: + # (10,101 - 100) - 10% x 100,000 = 10,001 - 10,000 + ny_casualty_loss_deduction: 1 + +- name: Case 4, a loss of exactly $100 is fully absorbed by the $100 reduction. + period: 2025 + input: + state_code: NY + casualty_loss: 100 + output: + ny_casualty_loss_deduction: 0 + +- name: Case 5, a loss under $100 is not deductible. + period: 2025 + input: + state_code: NY + casualty_loss: 90 + output: + ny_casualty_loss_deduction: 0 + +- name: Case 6, Publication 547 Example 1 with $80,000 of AGI. + period: 2025 + input: + state_code: NY + employment_income: 80_000 + casualty_loss: 14_800 + output: + # IRS Publication 547 (2017, PDF p. 10), Example 1: loss after + # reimbursement 14,800; subtract $100 = 14,700; subtract 10% of 80,000 AGI + # = 6,700. + ny_casualty_loss_deduction: 6_700 + +- name: Case 7, a joint return reduces the spouses' pooled losses by $100 once. + period: 2025 + input: + people: + person1: + age: 40 + employment_income: 60_000 + casualty_loss: 10_000 + person2: + age: 40 + employment_income: 40_000 + casualty_loss: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NY + output: + filing_status: JOINT + # (10,000 + 5,000 - 100) - 10% x 100,000 = 14,900 - 10,000 + ny_casualty_loss_deduction: 4_900 + +- name: Case 8, a dependent's loss is left to the dependent's own return. + period: 2025 + input: + people: + person1: + age: 40 + employment_income: 100_000 + casualty_loss: 15_000 + person2: + age: 10 + casualty_loss: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NY + output: + is_tax_unit_dependent: [false, true] + # The child's 5,000 is not the parent's loss. + # (15,000 - 100) - 10% x 100,000 = 14,900 - 10,000 + ny_casualty_loss_deduction: 4_900 + +- name: Case 9, a loss only the dependent had gives the parent nothing. + period: 2025 + input: + people: + person1: + age: 40 + employment_income: 100_000 + person2: + age: 10 + casualty_loss: 15_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NY + output: + is_tax_unit_dependent: [false, true] + ny_casualty_loss_deduction: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/itemized/ny_pre_tcja_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/itemized/ny_pre_tcja_deductions.yaml index 502aab68f83..38c4e4f88cc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/itemized/ny_pre_tcja_deductions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/itemized/ny_pre_tcja_deductions.yaml @@ -59,10 +59,10 @@ employment_income: 100_000 casualty_loss: 15_000 output: - # Casualty loss: 15,000 + # Casualty loss: 15,000, less $100 per casualty = 14,900 # AGI floor (10%): 100,000 * 0.10 = 10,000 - # Deduction: 15,000 - 10,000 = 5,000 - ny_casualty_loss_deduction: 5_000 + # Deduction: 14,900 - 10,000 = 4,900 + ny_casualty_loss_deduction: 4_900 - name: NY itemized deductions max includes all pre-TCJA components period: 2024 @@ -81,6 +81,6 @@ # Medical: 10,000 - (100,000 * 0.075) = 2,500 # NY SALT: 12,000 real estate only (sales tax 3,000 added back per s.615(c)(1)) # NY Misc: 4,000 - (100,000 * 0.02) = 2,000 - # NY Casualty: 15,000 - (100,000 * 0.10) = 5,000 - # Total: 5,000 + 2,500 + 12,000 + 2,000 + 5,000 = 26,500 - ny_itemized_deductions_max: 26_500 + # NY Casualty: (15,000 - 100) - (100,000 * 0.10) = 4,900 + # Total: 5,000 + 2,500 + 12,000 + 2,000 + 4,900 = 26,400 + ny_itemized_deductions_max: 26_400 diff --git a/policyengine_us/tests/unit/test_casualty_loss_deduction_properties.py b/policyengine_us/tests/unit/test_casualty_loss_deduction_properties.py new file mode 100644 index 00000000000..a60f2fc5814 --- /dev/null +++ b/policyengine_us/tests/unit/test_casualty_loss_deduction_properties.py @@ -0,0 +1,235 @@ +"""Properties of PolicyEngine's copies of the Form 4684 casualty loss computation. + +26 U.S.C. 165(h)(1) reduces each personal casualty loss by $100 (Form 4684 +line 11), and 165(h)(2)(A) allows the rest only above 10% of adjusted gross +income (line 17). A joint return is one individual for the $100 rule +(165(h)(4)(B)), and a dependent's loss belongs on the dependent's own return. +The model records one loss amount per person and no event count, so a return's +losses are treated as one casualty. Four variables copy the computation: + +- the federal `casualty_loss_deduction`, on federal AGI, suspended from 2018 + (gov.irs.deductions.itemized.casualty.active); +- New York's `ny_casualty_loss_deduction`, on federal AGI, under the 2017 + federal rules in every year (Form IT-196 line 20); +- Alabama's `al_casualty_loss_deduction`, on Alabama AGI, following 165(h) as in + effect from time to time, so suspended with the federal deduction; +- Hawaii's `hi_casualty_loss_deduction`, on Hawaii AGI (floored at zero), with + Hawaii's own $100, allowed for non-disaster losses through 2025 (Act 35, + SLH 2026, adopts 165(h)(5) from 2026). + +Hypothesis draws batches of tax units (single or joint, with up to two +dependents who have their own losses), each placed in New York, Alabama and +Hawaii, and gives every copy the same AGI. Each batch runs as one vectorized +baseline simulation. For every tax unit and year: + +1. Each copy equals a closed-form reference on the head's and spouse's losses: + gate x max(max(loss - 100, 0) - 10% x max(AGI, 0), 0). Dependents' losses + never enter it. +2. Bounds: 0 <= deduction <= max(loss - 100, 0). +3. A state copy is zero outside its state. +4. Differential: where their gates are on, the four copies agree with each + other, since they share the computation and the AGI. + +A deterministic grid adds the boundary inputs ($0, $99, $100, $101, the floor +plus $100) and checks monotonicity: each copy rises with the loss and falls +with AGI, and is zero for a loss of $100 or less. The YAML tests cover a reform +that lifts the federal suspension, which Alabama follows and Hawaii does not. +""" + +import itertools + +import numpy as np +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation + +REDUCTION = 100 # Form 4684 line 11; HRS 235-2.4(l)(1) +FLOOR = 0.1 # Form 4684 line 17 +TOLERANCE = 0.01 +STATES = ["NY", "AL", "HI"] +YEARS = [2017, 2025, 2026] +# Whether each copy allows a non-disaster loss, by year, in baseline. Hawaii's +# variables start in 2018, when its itemized deductions do. +GATES = { + "casualty_loss_deduction": {2017: 1, 2025: 0, 2026: 0}, + "ny_casualty_loss_deduction": {2017: 1, 2025: 1, 2026: 1}, + "al_casualty_loss_deduction": {2017: 1, 2025: 0, 2026: 0}, + "hi_casualty_loss_deduction": {2025: 1, 2026: 0}, +} +STATE_OF = { + "ny_casualty_loss_deduction": "NY", + "al_casualty_loss_deduction": "AL", + "hi_casualty_loss_deduction": "HI", +} + + +def reference(loss, agi): + reduced = np.maximum(loss - REDUCTION, 0) + return np.maximum(reduced - FLOOR * np.maximum(agi, 0), 0) + + +def every_year(value): + return {year: value for year in YEARS} + + +def build_situation(units): + """Place each unit in each state, with the same AGI for every copy.""" + people, tax_units, households = {}, {}, {} + rows = [] # (filer loss, AGI, state) for each tax unit, in order + for state in STATES: + for i, unit in enumerate(units): + name = f"{state}{i}" + members = [f"{name}_head"] + people[members[0]] = { + "age": every_year(40), + "casualty_loss": every_year(unit["head_loss"]), + } + filer_loss = unit["head_loss"] + if unit["joint"]: + members.append(f"{name}_spouse") + people[members[-1]] = { + "age": every_year(40), + "casualty_loss": every_year(unit["spouse_loss"]), + } + filer_loss += unit["spouse_loss"] + for d, dependent_loss in enumerate(unit["dependent_losses"]): + members.append(f"{name}_dep{d}") + people[members[-1]] = { + "age": every_year(10), + "is_tax_unit_dependent": every_year(True), + "casualty_loss": every_year(dependent_loss), + } + agi = unit["agi"] + tax_units[name] = { + "members": members, + "adjusted_gross_income": every_year(agi), + "al_agi": every_year(agi), + "hi_agi": every_year(agi), + } + households[name] = {"members": members, "state_code": every_year(state)} + rows.append((filer_loss, agi, state)) + situation = {"people": people, "tax_units": tax_units, "households": households} + loss, agi, state = (np.array(column) for column in zip(*rows)) + return situation, loss.astype(float), agi.astype(float), state + + +def check_reference_and_bounds(sim, loss, agi, state, gates): + for variable, by_year in gates.items(): + for year, gate in by_year.items(): + value = sim.calculate(variable, year) + expected = gate * reference(loss, agi) + in_state = state == STATE_OF.get(variable, state) + expected = np.where(in_state, expected, 0) + np.testing.assert_allclose( + value, expected, atol=TOLERANCE, err_msg=f"{variable} {year}" + ) + assert np.all(value >= 0) + assert np.all(value <= np.maximum(loss - REDUCTION, 0) + TOLERANCE) + + +def check_copies_agree(sim, state, gates): + for year in YEARS: + on = [v for v, by_year in gates.items() if by_year.get(year) == 1] + federal = sim.calculate("casualty_loss_deduction", year) + for variable in on: + value = sim.calculate(variable, year) + if variable in STATE_OF: + in_state = state == STATE_OF[variable] + if "casualty_loss_deduction" in on: + np.testing.assert_allclose( + value[in_state], federal[in_state], atol=TOLERANCE + ) + for other in on: + if other in STATE_OF and other != variable: + # Compare the same drawn units across states. + other_state = state == STATE_OF[other] + np.testing.assert_allclose( + value[in_state], + sim.calculate(other, year)[other_state], + atol=TOLERANCE, + ) + + +money = st.one_of( + st.sampled_from([0, 50, 99, 100, 101, 150]), + st.integers(0, 60_000), +).map(float) +agis = st.one_of( + st.sampled_from([0, 1_000, 50_000]), + st.integers(-20_000, 300_000), +).map(float) +tax_unit_strategy = st.fixed_dictionaries( + { + "joint": st.booleans(), + "head_loss": money, + "spouse_loss": money, + "dependent_losses": st.lists(money, max_size=2), + "agi": agis, + } +) +SETTINGS = dict( + max_examples=20, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) + + +@settings(**SETTINGS) +@given(st.lists(tax_unit_strategy, min_size=4, max_size=15)) +def test_copies_match_the_form_4684_reference(units): + situation, loss, agi, state = build_situation(units) + sim = Simulation(situation=situation) + check_reference_and_bounds(sim, loss, agi, state, GATES) + check_copies_agree(sim, state, GATES) + + +GRID_LOSSES = [0, 50, 99, 100, 101, 150, 5_000, 10_100, 10_101, 30_000] +GRID_AGIS = [-10_000, 0, 1_000, 50_000, 100_000, 300_000] +GRID_DEPENDENT_LOSSES = [0, 20_000] + + +def grid_situation(): + units = [ + { + "joint": False, + "head_loss": float(loss), + "spouse_loss": 0.0, + "dependent_losses": [float(dependent_loss)], + "agi": float(agi), + } + for loss, agi, dependent_loss in itertools.product( + GRID_LOSSES, GRID_AGIS, GRID_DEPENDENT_LOSSES + ) + ] + return build_situation(units) + + +@pytest.fixture(scope="module") +def grid(): + situation, loss, agi, state = grid_situation() + return Simulation(situation=situation), loss, agi, state + + +@pytest.mark.parametrize( + "variable, year", + [(v, y) for v, by_year in GATES.items() for y, gate in by_year.items() if gate], +) +def test_grid_monotone_and_boundaries(grid, variable, year): + sim, loss, agi, state = grid + rows = state == STATE_OF.get(variable, "NY") + value = sim.calculate(variable, year)[rows] + np.testing.assert_allclose(value, reference(loss[rows], agi[rows]), atol=TOLERANCE) + shape = (len(GRID_LOSSES), len(GRID_AGIS), len(GRID_DEPENDENT_LOSSES)) + table = value.reshape(shape) + # A dependent's loss never changes the filer's deduction. + np.testing.assert_allclose(table[..., 0], table[..., 1], atol=TOLERANCE) + assert np.all(np.diff(table, axis=0) >= -TOLERANCE), "falls as the loss rises" + assert np.all(np.diff(table, axis=1) <= TOLERANCE), "rises as AGI rises" + # A loss of $100 or less is absorbed by the $100 reduction. + small = np.array(GRID_LOSSES) <= REDUCTION + assert np.all(table[small] == 0) + # Guard against a vacuous pass. + assert table.max() > 0 diff --git a/policyengine_us/tests/unit/test_mt_casualty_loss_deduction_properties.py b/policyengine_us/tests/unit/test_mt_casualty_loss_deduction_properties.py new file mode 100644 index 00000000000..bb78c499d1f --- /dev/null +++ b/policyengine_us/tests/unit/test_mt_casualty_loss_deduction_properties.py @@ -0,0 +1,194 @@ +"""Properties of the Montana casualty and theft loss deduction (2021-2023). + +The 2021-2023 Form 2 instructions (Itemized Deductions Schedule, line 15) say +to complete federal Form 4684 with Montana AGI in place of federal AGI, and +that spouses filing separately each complete their own Form 4684. Each test +evaluates every point of an input grid in one vectorized simulation, so the +properties hold for all grid inputs rather than for a few examples: + +- both variants match a closed-form reference of Form 4684 lines 11-12 and + 17-18: the loss less $100, above 10% of Montana AGI; +- a joint return counts the spouses' losses once, however many members the + tax unit has, and Montana's joint itemized deductions add it once; +- filing separately, each spouse deducts only their own loss, floored at their + own Montana AGI; +- a dependent's loss is left to the dependent's own return on both paths; +- the deductions are non-negative, never exceed the loss less $100, rise with + the loss and fall with Montana AGI; +- for a single filer the joint and separate variants agree; +- the deduction ends in 2024, when Montana discontinued its Itemized + Deductions Schedule. + +The model has no input that distinguishes federally declared disaster losses, +so, like the federal deduction, it allows no personal casualty loss from 2018 +unless gov.irs.deductions.itemized.casualty.active is on; a reform switches it +on so the properties are not vacuous. +""" + +import itertools + +import numpy as np +import pytest +from policyengine_core.reforms import Reform + +from policyengine_us import Simulation + +REDUCTION = 100 # Form 4684 line 11 +FLOOR = 0.1 # Form 4684 line 17 + +HEAD_LOSSES = [0, 80, 100, 101, 5_000, 30_000] +SPOUSE_LOSSES = [0, 100, 5_000] +HEAD_AGIS = [0, 40_000, 300_000] +SPOUSE_AGIS = [0, 60_000] +# (number of dependents, the first dependent's loss) +DEPENDENTS = [(0, 0), (1, 0), (1, 2_000), (2, 0)] +COUPLE_GRID = list( + itertools.product(HEAD_LOSSES, SPOUSE_LOSSES, HEAD_AGIS, SPOUSE_AGIS, DEPENDENTS) +) +SINGLE_GRID = list(itertools.product(HEAD_LOSSES, HEAD_AGIS)) +YEARS = [2021, 2022, 2023, 2024] + +ACTIVE = Reform.from_dict( + {"gov.irs.deductions.itemized.casualty.active": {"2010-01-01.2100-12-31": True}}, + country_id="us", +) + + +def reference(loss, agi): + return np.maximum(np.maximum(loss - REDUCTION, 0) - FLOOR * agi, 0) + + +def every_year(value): + return {year: value for year in YEARS} + + +@pytest.fixture(scope="module") +def grid(): + """One simulation holding every couple and single-filer grid point.""" + people, tax_units, households = {}, {}, {} + roles = [] # (unit index, role) for each person, in order + for i, (l1, l2, a1, a2, (n_deps, dep_loss)) in enumerate(COUPLE_GRID): + members = [f"c{i}_head", f"c{i}_spouse"] + people[members[0]] = { + "age": every_year(40), + "casualty_loss": every_year(l1), + "mt_agi_indiv": every_year(a1), + } + people[members[1]] = { + "age": every_year(40), + "casualty_loss": every_year(l2), + "mt_agi_indiv": every_year(a2), + } + roles += [(i, "head"), (i, "spouse")] + for d in range(n_deps): + name = f"c{i}_dep{d}" + people[name] = { + "age": every_year(10), + "is_tax_unit_dependent": every_year(True), + "casualty_loss": every_year(dep_loss if d == 0 else 0), + "mt_agi_indiv": every_year(0), + } + members.append(name) + roles.append((i, "dependent")) + tax_units[f"c{i}"] = {"members": members, "mt_agi_joint": every_year(a1 + a2)} + households[f"c{i}"] = {"members": members, "state_code": every_year("MT")} + for j, (loss, agi) in enumerate(SINGLE_GRID): + name = f"s{j}" + people[name] = { + "age": every_year(40), + "casualty_loss": every_year(loss), + "mt_agi_indiv": every_year(agi), + } + roles.append((len(COUPLE_GRID) + j, "single")) + tax_units[name] = {"members": [name], "mt_agi_joint": every_year(agi)} + households[name] = {"members": [name], "state_code": every_year("MT")} + # Zero the other itemized deductions so the aggregators show the casualty + # loss alone; the grid has no medical, care, charitable or interest items. + for person in people.values(): + person["mt_salt_deduction"] = every_year(0) + person["mt_federal_income_tax_deduction_indiv"] = every_year(0) + for unit in tax_units.values(): + unit["mt_federal_income_tax_deduction_unit"] = every_year(0) + sim = Simulation( + situation={"people": people, "tax_units": tax_units, "households": households}, + reform=ACTIVE, + ) + unit = np.array([r[0] for r in roles]) + role = np.array([r[1] for r in roles]) + return sim, unit, role + + +def couple_arrays(): + columns = np.array( + [(l1, l2, a1, a2, n, d) for l1, l2, a1, a2, (n, d) in COUPLE_GRID], + dtype=float, + ).T + return columns # head loss, spouse loss, head AGI, spouse AGI, deps, dep loss + + +@pytest.mark.parametrize("year", [2021, 2022, 2023]) +def test_joint_return_counts_the_unit_loss_once(grid, year): + sim, unit, role = grid + l1, l2, a1, a2, _, _ = couple_arrays() + n = len(COUPLE_GRID) + joint = sim.calculate("mt_casualty_loss_deduction_joint", year)[:n] + # A dependent's loss is left to the dependent's own return. + np.testing.assert_allclose(joint, reference(l1 + l2, a1 + a2)) + # Montana's joint itemized deductions add it once, at the head, however + # many members the tax unit has. + itemized = sim.calculate("mt_itemized_deductions_joint", year) + per_unit = np.bincount(unit, weights=itemized)[:n] + np.testing.assert_allclose(per_unit, joint) + assert np.all(itemized[(role != "head") & (role != "single")] == 0) + assert np.all(joint >= 0) + assert np.all(joint <= np.maximum(l1 + l2 - REDUCTION, 0)) + # Guard against a vacuous pass. + assert joint.max() > 0 + + +@pytest.mark.parametrize("year", [2021, 2022, 2023]) +def test_separate_filers_deduct_only_their_own_loss(grid, year): + sim, unit, role = grid + l1, l2, a1, a2, _, _ = couple_arrays() + indiv = sim.calculate("mt_casualty_loss_deduction_indiv", year) + itemized = sim.calculate("mt_itemized_deductions_indiv", year) + head = indiv[role == "head"] + spouse = indiv[role == "spouse"] + # Each spouse's own Form 4684, on their own Montana AGI; a dependent's + # loss is in neither column. + np.testing.assert_allclose(head, reference(l1, a1)) + np.testing.assert_allclose(spouse, reference(l2, a2)) + assert np.all(indiv[role == "dependent"] == 0) + # A spouse without a loss deducts nothing, whatever the other spouse lost. + assert np.all(spouse[l2 == 0] == 0) + assert np.all(head[l1 == 0] == 0) + # The separate itemized deductions carry each spouse's own amount. + np.testing.assert_allclose(itemized[role == "head"], head) + np.testing.assert_allclose(itemized[role == "spouse"], spouse) + assert np.all(itemized[role == "dependent"] == 0) + assert np.all(indiv >= 0) + assert head.max() > 0 and spouse.max() > 0 + + +@pytest.mark.parametrize("year", [2021, 2022, 2023]) +def test_single_filer_variants_agree_and_are_monotone(grid, year): + sim, unit, role = grid + single = role == "single" + single_units = unit[single] + loss = np.array([g[0] for g in SINGLE_GRID], dtype=float) + agi = np.array([g[1] for g in SINGLE_GRID], dtype=float) + indiv = sim.calculate("mt_casualty_loss_deduction_indiv", year)[single] + joint = sim.calculate("mt_casualty_loss_deduction_joint", year)[single_units] + np.testing.assert_allclose(joint, reference(loss, agi)) + np.testing.assert_allclose(indiv, joint) + table = joint.reshape(len(HEAD_LOSSES), len(HEAD_AGIS)) + assert np.all(np.diff(table, axis=0) >= 0), "falls as the loss rises" + assert np.all(np.diff(table, axis=1) <= 0), "rises as Montana AGI rises" + + +def test_deduction_ends_with_the_2024_schedule(grid): + sim, _, _ = grid + assert np.all(sim.calculate("mt_casualty_loss_deduction_joint", 2024) == 0) + assert np.all(sim.calculate("mt_casualty_loss_deduction_indiv", 2024) == 0) + # The same inputs are deductible in 2023. + assert sim.calculate("mt_casualty_loss_deduction_joint", 2023).max() > 0 diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/casualty_loss_deduction.py b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/casualty_loss_deduction.py index 095a3feceb7..329bd3b95fb 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/casualty_loss_deduction.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/casualty_loss_deduction.py @@ -7,10 +7,28 @@ class casualty_loss_deduction(Variable): label = "Casualty loss deduction" unit = USD definition_period = YEAR + reference = ( + "https://www.law.cornell.edu/uscode/text/26/165#h", + # 2017 Form 4684, lines 10-18 + "https://www.irs.gov/pub/irs-prior/f4684--2017.pdf#page=1", + # IRS Publication 547 (2017), $100 Rule + "https://www.irs.gov/pub/irs-prior/p547--2017.pdf#page=10", + ) def formula(tax_unit, period, parameters): - loss = add(tax_unit, period, ["casualty_loss"]) p = parameters(period).gov.irs.deductions.itemized.casualty + # Only the owner of the property claims the loss. A dependent's loss + # belongs on the dependent's own return, as the dependent's income + # does: adjusted gross income leaves it out. + loss = tax_unit_non_dep_add(tax_unit, period, ["casualty_loss"]) + # 26 U.S.C. 165(h)(1) reduces each casualty by $100 (Form 4684 + # line 11). A joint return is one individual for the $100 rule + # (165(h)(4)(B)). The model records one loss amount per person, not + # separate casualty events, so the return's losses are treated as one + # casualty and the reduction applies once. + reduced_loss = max_(loss - p.per_casualty_reduction, 0) + # 165(h)(2)(A): the rest is allowed above 10% of adjusted gross income + # (Form 4684 line 17). positive_agi = tax_unit("positive_agi", period) - amount_over_floor = max_(0, loss - positive_agi * p.floor) + amount_over_floor = max_(reduced_loss - positive_agi * p.floor, 0) return p.active * amount_over_floor diff --git a/policyengine_us/variables/gov/states/al/tax/income/deductions/itemized/al_casualty_loss_deduction.py b/policyengine_us/variables/gov/states/al/tax/income/deductions/itemized/al_casualty_loss_deduction.py index 595e55871f9..313414d75d7 100644 --- a/policyengine_us/variables/gov/states/al/tax/income/deductions/itemized/al_casualty_loss_deduction.py +++ b/policyengine_us/variables/gov/states/al/tax/income/deductions/itemized/al_casualty_loss_deduction.py @@ -7,10 +7,49 @@ class al_casualty_loss_deduction(Variable): label = "Alabama casualty loss deduction" unit = USD definition_period = YEAR + reference = ( + # Ala. Code § 40-18-15(a)(6) + "https://alison.legislature.state.al.us/code-of-alabama?section=40-18-15", + # Ala. Code § 40-18-1.1(b): "26 U.S.C." means the Internal Revenue + # Code as in effect from time to time + "https://alison.legislature.state.al.us/code-of-alabama?section=40-18-1.1", + # 2025 Form 40 instructions, Schedule A lines 19a-c, and Schedule A + "https://www.revenue.alabama.gov/wp-content/uploads/2026/01/25f40bk.pdf#page=20", + "https://www.revenue.alabama.gov/wp-content/uploads/2026/01/25f40schabdc_blk.pdf#page=1", + # 2021 Form 40 instructions, Schedule A lines 19a-c + "https://www.revenue.alabama.gov/wp-content/uploads/2022/06/21f40bk.pdf#page=20", + # 2025 Form 4684, lines 10-16 + "https://www.irs.gov/pub/irs-prior/f4684--2025.pdf#page=1", + # Alabama Department of Revenue, OBBBA Executive Summary: 26 U.S.C. + # 165(h)(5) is "Tied to Federal: Yes" through 40-18-15(a)(6) + "https://www.revenue.alabama.gov/wp-content/uploads/2025/11/OBBBA-Executive-Summary_FinalwAppendixA_10.31.25.pdf#page=8", + ) defined_for = StateCode.AL def formula(tax_unit, period, parameters): - loss = add(tax_unit, period, ["casualty_loss"]) - deduction = parameters(period).gov.irs.deductions.itemized.casualty - al_agi = tax_unit("al_agi", period) - return max_(0, loss - al_agi * deduction.floor) + p = parameters(period).gov.irs.deductions.itemized.casualty + # Alabama allows the loss as determined under 26 U.S.C. 165(c)(3) and + # (h), as in effect from time to time. Schedule A line 19a takes the + # loss from federal Form 4684, after each casualty is reduced by $100 + # (line 11) and, from 2018, after the limit to losses attributable to + # declared disasters (165(h)(5), line 14). The Department of Revenue + # ties Alabama to 165(h)(5) explicitly for tax years after 2025; for + # 2018-2025 the limit follows from the rolling conformity and the form + # flow. The model has no input that distinguishes disaster losses, so, + # like the federal deduction, no personal casualty loss is deductible + # while gov.irs.deductions.itemized.casualty.active is false (from + # 2018). + # Only the owner of the property claims the loss. A dependent's loss + # belongs on the dependent's own return. + loss = tax_unit_non_dep_add(tax_unit, period, ["casualty_loss"]) + # A joint return is one individual for the $100 rule. The model records + # one loss amount per person, not separate casualty events, so the + # return's losses are treated as one casualty and the reduction + # applies once. + reduced_loss = max_(loss - p.per_casualty_reduction, 0) + # Line 19b: 10% of Alabama adjusted gross income (Form 40, line 10). + # The form is silent on a negative AGI; like the federal deduction + # (positive_agi) and Hawaii's Worksheet A-5, the floor is not allowed + # to go below zero, so the deduction never exceeds the reduced loss. + al_agi = max_(tax_unit("al_agi", period), 0) + return p.active * max_(reduced_loss - al_agi * p.floor, 0) diff --git a/policyengine_us/variables/gov/states/hi/tax/income/deductions/itemized/hi_casualty_loss_deduction.py b/policyengine_us/variables/gov/states/hi/tax/income/deductions/itemized/hi_casualty_loss_deduction.py index 29ec2090d92..eb9a110cde9 100644 --- a/policyengine_us/variables/gov/states/hi/tax/income/deductions/itemized/hi_casualty_loss_deduction.py +++ b/policyengine_us/variables/gov/states/hi/tax/income/deductions/itemized/hi_casualty_loss_deduction.py @@ -6,22 +6,50 @@ class hi_casualty_loss_deduction(Variable): entity = TaxUnit label = "Hawaii casualty loss deduction" unit = USD - documentation = ( - "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=18\n" - "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=32" # total itemized deduction worksheet - ) definition_period = YEAR + reference = ( + # HRS § 235-2.4(l) + "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=12", + # 2022 Form N-11 instructions, Casualty and Theft Losses and + # Worksheet A-5 + "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=18", + "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=32", + # 2025 Form N-11 instructions, Casualty and Theft Losses and + # Worksheet A-5 + "https://files.hawaii.gov/tax/forms/2025/n11ins.pdf#page=19", + "https://files.hawaii.gov/tax/forms/2025/n11ins.pdf#page=34", + # 2017 Form 4684, lines 10-16 + "https://www.irs.gov/pub/irs-prior/f4684--2017.pdf#page=1", + # Department of Taxation Announcement 2026-06: Act 35, SLH 2026, + # conforms to 26 U.S.C. 165(h)(5) from 2026 + "https://files.hawaii.gov/tax/news/announce/ann26-06.pdf#page=2", + ) defined_for = StateCode.HI def formula(tax_unit, period, parameters): - p_deductions = parameters(period).gov.irs.deductions - # 5. casualty_loss_deduction: worksheet A-5 - # Hawaii did not - # (1) limit the personal casualty loss deduction for property losses (not used in connection with a trade or business - # or transaction entered into for profit) - # (2) waive the requirement that casualty losses from qualified disasters exceed 10% of adjusted gross income - # to be deductible, and that such losses must exceed $500. - casualty_loss = add(tax_unit, period, ["casualty_loss"]) + p = parameters(period).gov.states.hi.tax.income.deductions.itemized + p_irs = parameters(period).gov.irs.deductions.itemized.casualty + # Worksheet A-5 line 19 takes the loss from the 2017 federal Form 4684, + # line 16: each casualty less Hawaii's $100 (HRS 235-2.4(l)(1)). + # Hawaii did not adopt the federal qualified-disaster rules, which + # replace the $100 with $500 and waive the 10% floor. + # Only the owner of the property claims the loss. A dependent's loss + # belongs on the dependent's own return. + loss = tax_unit_non_dep_add(tax_unit, period, ["casualty_loss"]) + # A joint return is one individual for the $100 rule. The model records + # one loss amount per person, not separate casualty events, so the + # return's losses are treated as one casualty and the reduction + # applies once. + reduced_loss = max_(loss - p.casualty_loss.per_casualty_reduction, 0) + # Lines 20-22: less 10% of Hawaii adjusted gross income, floored at + # zero. hi_agi = tax_unit("hi_agi", period) - casualty_agi_amount = max_(0, p_deductions.itemized.casualty.floor * hi_agi) - return max_(0, casualty_loss - casualty_agi_amount) + floor = max_(0, p_irs.floor * hi_agi) + deduction = max_(reduced_loss - floor, 0) + # Through 2025 Hawaii did not limit personal casualty losses to + # declared disasters (HRS 235-2.4(l)(3) made 26 U.S.C. 165(h)(5) + # inoperative). Act 35, SLH 2026, adopts that limit from 2026. The + # model has no input that distinguishes disaster losses, so, like the + # federal deduction, no personal casualty loss is deductible once the + # limit applies. + return p.casualty_loss.non_disaster_losses_allowed * deduction diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_household_income.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_household_income.py index e4a6976f246..21c77cdc399 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_household_income.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_household_income.py @@ -8,7 +8,13 @@ class mt_elderly_homeowner_or_renter_credit_gross_household_income(Variable): unit = USD definition_period = YEAR defined_for = StateCode.MT - reference = "https://law.justia.com/codes/montana/2022/title-15/chapter-30/part-23/section-15-30-2337/" + reference = ( + "https://law.justia.com/codes/montana/2022/title-15/chapter-30/part-23/section-15-30-2337/", + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0370/0150-0300-0230-0370.html", + # 2023 Form 2 instructions, Elderly Homeowner/Renter Credit Schedule, line 9 + # (renamed Schedule 2EC from 2024) + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2023_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=52", + ) def formula(person, period, parameters): p = parameters( @@ -20,4 +26,11 @@ def formula(person, period, parameters): social_security = person("social_security", period) taxable_social_security = person("taxable_social_security", period) untaxed_social_security = max_(social_security - taxable_social_security, 0) - return sources + untaxed_social_security + # Income is federal AGI "without regard to loss" (§ 15-30-2337(9)(a)), + # so the business and capital losses deducted in computing federal + # AGI are added back (2023 Elderly Homeowner/Renter Credit Schedule, + # line 9: "The gross household income cannot be reduced by any + # losses."). The return's losses are added once, to the head. + head = person("is_tax_unit_head", period) + losses = head * person.tax_unit("loss_ald", period) + return sources + untaxed_social_security + losses diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction.py index 2efb5ad2407..229fe2db8e6 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction.py @@ -7,9 +7,16 @@ class mt_child_dependent_care_expense_deduction(Variable): label = "Montana child dependent care expense deduction" unit = USD definition_period = YEAR + documentation = ( + "The deduction in each filer's column: an unmarried filer's return, or " + "each spouse's column when spouses file separately on the same form. " + "A joint return uses mt_child_dependent_care_expense_deduction_joint." + ) reference = ( "https://mca.legmt.gov/bills/2019/mca/title_0150/chapter_0300/part_0210/section_0310/0150-0300-0210-0310.html", "https://web.archive.org/web/20230914140156/https://mtrevenue.gov/wp-content/uploads/dlm_uploads/2022/12/2441-M_2022.pdf#page=1", + # 2022 Form 2 instructions, Itemized Deductions Schedule, line 14 + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=35", ) defined_for = StateCode.MT @@ -19,26 +26,26 @@ def formula(person, period, parameters): ).gov.states.mt.tax.income.deductions.child_dependent_care_expense if not p.in_effect: return 0 - tax_unit = person.tax_unit - members = tax_unit.members - qualifying_individual = members( - "mt_child_dependent_care_expense_deduction_qualifying_individual", - period, - ) - # Form 2441-M line 1 - qualifying_individuals = tax_unit.sum(qualifying_individual) - qualifying_care_expenses = tax_unit.sum( - members("care_expenses", period) * qualifying_individual + # Form 2441-M line 2 + eligible_expenses = person.tax_unit( + "mt_child_dependent_care_expense_deduction_eligible_expenses", period ) - childcare_expenses = tax_unit("tax_unit_childcare_expenses", period) - total_expenses = childcare_expenses + qualifying_care_expenses - # Form 2441-M line 2: the lesser of actual dependent care expenses - # or the cap based on the number of qualifying individuals. - capped_expenses = min_(total_expenses, p.cap.calc(qualifying_individuals)) - # Line 3 - agi = person("mt_agi_indiv", period) - # Line 6 - reduction = p.phase_out.calc(agi) - # The deduction has to be allocated equally between spouses + # Line 3: add the Montana adjusted gross income in columns A and B, + # that is, the couple's combined income, not each spouse's own. head_or_spouse = person("is_tax_unit_head_or_spouse", period) - return head_or_spouse * (max_(0, capped_expenses - reduction) * 0.5) + combined_agi = person.tax_unit.sum( + head_or_spouse * person("mt_agi_indiv", period) + ) + # Lines 4-7 + deduction = max_(eligible_expenses - p.phase_out.calc(combined_agi), 0) + # Spouses filing separately on the same form each enter one-half of + # line 7 in their column; an unmarried filer enters all of it. + married = person.tax_unit("tax_unit_married", period) + head = person("is_tax_unit_head", period) + share = where(married, head_or_spouse * 0.5, head * 1.0) + # Married couples must file a joint return or file separately on the + # same form (MCA 15-30-2131(1)(c)(vi)(A)); a spouse filing on a + # separate form cannot take the deduction. + filing_status = person.tax_unit("filing_status", period) + separate_form = filing_status == filing_status.possible_values.SEPARATE + return deduction * share * ~separate_form diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction_eligible_expenses.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction_eligible_expenses.py new file mode 100644 index 00000000000..642214c3e55 --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction_eligible_expenses.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class mt_child_dependent_care_expense_deduction_eligible_expenses(Variable): + value_type = float + entity = TaxUnit + label = "Montana child and dependent care expenses eligible for the deduction" + unit = USD + definition_period = YEAR + reference = ( + "https://mca.legmt.gov/bills/2019/mca/title_0150/chapter_0300/part_0210/section_0310/0150-0300-0210-0310.html", + "https://web.archive.org/web/20230914140156/https://mtrevenue.gov/wp-content/uploads/dlm_uploads/2022/12/2441-M_2022.pdf#page=1", + ) + defined_for = StateCode.MT + + def formula(tax_unit, period, parameters): + p = parameters( + period + ).gov.states.mt.tax.income.deductions.child_dependent_care_expense + person = tax_unit.members + qualifying_individual = person( + "mt_child_dependent_care_expense_deduction_qualifying_individual", + period, + ) + # Form 2441-M line 1 + qualifying_individuals = tax_unit.sum(qualifying_individual) + qualifying_care_expenses = tax_unit.sum( + person("care_expenses", period) * qualifying_individual + ) + childcare_expenses = tax_unit("tax_unit_childcare_expenses", period) + total_expenses = childcare_expenses + qualifying_care_expenses + # Form 2441-M line 2: the lesser of actual dependent care expenses + # or the cap based on the number of qualifying individuals. + return min_(total_expenses, p.cap.calc(qualifying_individuals)) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction_joint.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction_joint.py new file mode 100644 index 00000000000..967ce181cb0 --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/cdcc/mt_child_dependent_care_expense_deduction_joint.py @@ -0,0 +1,35 @@ +from policyengine_us.model_api import * + + +class mt_child_dependent_care_expense_deduction_joint(Variable): + value_type = float + entity = TaxUnit + label = "Montana child dependent care expense deduction on a joint return" + unit = USD + definition_period = YEAR + reference = ( + "https://mca.legmt.gov/bills/2019/mca/title_0150/chapter_0300/part_0210/section_0310/0150-0300-0210-0310.html", + "https://web.archive.org/web/20230914140156/https://mtrevenue.gov/wp-content/uploads/dlm_uploads/2022/12/2441-M_2022.pdf#page=1", + # 2022 Form 2 instructions, Itemized Deductions Schedule, line 14 + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=35", + ) + defined_for = StateCode.MT + + def formula(tax_unit, period, parameters): + p = parameters( + period + ).gov.states.mt.tax.income.deductions.child_dependent_care_expense + if not p.in_effect: + return 0 + # Form 2441-M line 2 + eligible_expenses = tax_unit( + "mt_child_dependent_care_expense_deduction_eligible_expenses", period + ) + # Line 3: the return's Montana adjusted gross income; lines 4-7. + agi = tax_unit("mt_agi_joint", period) + deduction = max_(eligible_expenses - p.phase_out.calc(agi), 0) + # A married person filing on a separate form cannot take the deduction + # (MCA 15-30-2131(1)(c)(vi)(A)). + filing_status = tax_unit("filing_status", period) + separate_form = filing_status == filing_status.possible_values.SEPARATE + return deduction * ~separate_form diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_indiv.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_indiv.py new file mode 100644 index 00000000000..fa9b40ac705 --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_indiv.py @@ -0,0 +1,48 @@ +from policyengine_us.model_api import * + + +class mt_casualty_loss_deduction_indiv(Variable): + value_type = float + entity = Person + label = ( + "Montana casualty and theft loss deduction when married couples file separately" + ) + unit = USD + definition_period = YEAR + reference = ( + # MCA § 15-30-2131(1)(a) (2021) + "https://mca.legmt.gov/bills/2022/mca/title_0150/chapter_0300/part_0210/section_0310/0150-0300-0210-0310.html", + # 2022 Form 2 instructions, Itemized Deductions Schedule, line 15 + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=35", + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=36", + # 2022 Form 2 instructions, allocation of deductions when filing separately + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=11", + # 2022 Form 4684, lines 10-12 and 17; IRS Publication 547, $100 Rule + "https://www.irs.gov/pub/irs-prior/f4684--2022.pdf#page=1", + "https://www.irs.gov/pub/irs-prior/p547--2022.pdf#page=10", + ) + defined_for = "mt_married_filing_separately_on_same_return_eligible" + + def formula(person, period, parameters): + p = parameters(period).gov.states.mt.tax.income.deductions.itemized + if not p.casualty_loss.applies: + return 0 + # Spouses filing separately each complete a separate federal Form 4684 + # for their own loss, using their own Montana adjusted gross income in + # place of federal adjusted gross income. A deduction attributable to + # only one spouse must be claimed by that spouse. + # Montana allows only federally declared disaster losses (line 15). The + # model has no input that distinguishes them, so, like the federal + # deduction, no personal casualty loss is deductible while + # gov.irs.deductions.itemized.casualty.active is false (from 2018). + p_casualty = parameters(period).gov.irs.deductions.itemized.casualty + # Only the owner of the property claims the loss. A dependent's loss + # belongs on the dependent's own return, as the dependent's income does: + # adjusted_gross_income_person, and so Montana AGI, leaves it out. + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + loss = head_or_spouse * person("casualty_loss", period) + # Spouses filing separately each reduce their own loss by $100 + # (Form 4684 line 11), treating each column's losses as one casualty. + reduced_loss = max_(loss - p_casualty.per_casualty_reduction, 0) + agi = person("mt_agi_indiv", period) + return p_casualty.active * max_(reduced_loss - agi * p_casualty.floor, 0) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_joint.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_joint.py new file mode 100644 index 00000000000..ef6dcd421e1 --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/casualty_loss/mt_casualty_loss_deduction_joint.py @@ -0,0 +1,44 @@ +from policyengine_us.model_api import * + + +class mt_casualty_loss_deduction_joint(Variable): + value_type = float + entity = TaxUnit + label = "Montana casualty and theft loss deduction on a joint return" + unit = USD + definition_period = YEAR + reference = ( + # MCA § 15-30-2131(1)(a) (2021) + "https://mca.legmt.gov/bills/2022/mca/title_0150/chapter_0300/part_0210/section_0310/0150-0300-0210-0310.html", + # 2022 Form 2 instructions, Itemized Deductions Schedule, line 15 + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=35", + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=36", + # 2022 Form 4684, lines 10-12 and 17; IRS Publication 547, $100 Rule + "https://www.irs.gov/pub/irs-prior/f4684--2022.pdf#page=1", + "https://www.irs.gov/pub/irs-prior/p547--2022.pdf#page=10", + ) + defined_for = StateCode.MT + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.mt.tax.income.deductions.itemized + if not p.casualty_loss.applies: + return 0 + # The return figures its loss as on federal Form 4684 (lines 10-18), + # using its Montana adjusted gross income in place of federal adjusted + # gross income. + # Montana allows only federally declared disaster losses (line 15). The + # model has no input that distinguishes them, so, like the federal + # deduction, no personal casualty loss is deductible while + # gov.irs.deductions.itemized.casualty.active is false (from 2018). + p_casualty = parameters(period).gov.irs.deductions.itemized.casualty + # A joint return is one individual for the $100 rule. The model records + # one loss amount per person, not separate casualty events, so the + # return's losses are treated as one casualty and the $100 reduction + # (Form 4684 line 11) applies once. + # Only the owner of the property claims the loss. A dependent's loss + # belongs on the dependent's own return, as the dependent's income does: + # adjusted_gross_income_person, and so Montana AGI, leaves it out. + loss = tax_unit_non_dep_add(tax_unit, period, ["casualty_loss"]) + reduced_loss = max_(loss - p_casualty.per_casualty_reduction, 0) + agi = tax_unit("mt_agi_joint", period) + return p_casualty.active * max_(reduced_loss - agi * p_casualty.floor, 0) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_federal_income_tax_deduction_for_federal_itemization_indiv.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_federal_income_tax_deduction_for_federal_itemization_indiv.py index 94951d1ad9c..967ce5bdfb5 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_federal_income_tax_deduction_for_federal_itemization_indiv.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_itemization/mt_federal_income_tax_deduction_for_federal_itemization_indiv.py @@ -7,28 +7,24 @@ class mt_federal_income_tax_deduction_for_federal_itemization_indiv(Variable): definition_period = YEAR label = "Montana federal income tax deduction when married couples are filing separately" reference = ( - "https://law.justia.com/codes/montana/2021/title-15/chapter-30/part-21/section-15-30-2131/" + "https://law.justia.com/codes/montana/2021/title-15/chapter-30/part-21/section-15-30-2131/", # MT Code § 15-30-2131 (2021) (1)(b) + # 2022 Form 2 instructions, Itemized Deductions Schedule, line 4 + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=33", ) unit = USD defined_for = "mt_married_filing_separately_on_same_return_eligible" def formula(person, period, parameters): - unit_deds = person.tax_unit( - "mt_federal_income_tax_deduction_for_federal_itemization", period - ) - person_agi = person("mt_agi_indiv", period) - total_agi = person.tax_unit.sum(person_agi) - - prorate = np.zeros_like(total_agi) - mask = total_agi > 0 - prorate[mask] = person_agi[mask] / total_agi[mask] + p = parameters( + period + ).gov.states.mt.tax.income.deductions.itemized.federal_income_tax + # The withholding estimate is computed on each person's own income, so + # each spouse deducts their own amount, up to their own cap. + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + withheld_income_tax = head_or_spouse * person("mt_withheld_income_tax", period) filing_status = person.tax_unit( "state_filing_status_if_married_filing_separately_on_same_return", period, ) - p = parameters( - period - ).gov.states.mt.tax.income.deductions.itemized.federal_income_tax - cap = p.cap[filing_status] - return min_(unit_deds * prorate, cap) + return min_(withheld_income_tax, p.cap[filing_status]) 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..a47e94c3ea8 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 @@ -28,7 +28,8 @@ def formula(person, period, parameters): person, period, [ - "mt_misc_deductions", + "mt_casualty_loss_deduction_indiv", + "mt_child_dependent_care_expense_deduction", "mt_medical_expense_deduction_indiv", "mt_salt_deduction", "mt_federal_income_tax_deduction_for_federal_itemization_indiv", 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..5e159b7d606 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 @@ -23,7 +23,8 @@ def formula(person, period, parameters): person.tax_unit, period, [ - "mt_misc_deductions", + "mt_casualty_loss_deduction_joint", + "mt_child_dependent_care_expense_deduction_joint", "mt_medical_expense_deduction_joint", "mt_salt_deduction", "mt_federal_income_tax_deduction_for_federal_itemization", diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_tax/mt_federal_income_tax_deduction_indiv.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_tax/mt_federal_income_tax_deduction_indiv.py index 792174d9142..f84c008f403 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_tax/mt_federal_income_tax_deduction_indiv.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_tax/mt_federal_income_tax_deduction_indiv.py @@ -7,26 +7,31 @@ class mt_federal_income_tax_deduction_indiv(Variable): definition_period = YEAR label = "Montana federal income tax deduction when married couples are filing separately" reference = ( - "https://law.justia.com/codes/montana/2021/title-15/chapter-30/part-21/section-15-30-2131/" + "https://law.justia.com/codes/montana/2021/title-15/chapter-30/part-21/section-15-30-2131/", # MT Code § 15-30-2131 (2021) (1)(b) + # 2022 Form 2 instructions, Itemized Deductions Schedule, line 4 + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=33", ) unit = USD defined_for = "mt_married_filing_separately_on_same_return_eligible" def formula(person, period, parameters): - unit_deds = person.tax_unit("mt_federal_income_tax_deduction_unit", period) - person_agi = person("mt_agi_indiv", period) - total_agi = person.tax_unit.sum(person_agi) - - prorate = np.zeros_like(total_agi) - mask = total_agi > 0 - prorate[mask] = person_agi[mask] / total_agi[mask] + p = parameters( + period + ).gov.states.mt.tax.income.deductions.itemized.federal_income_tax + if not p.applies: + return 0 + # Federal income tax is reported by the spouse who earned the income + # it was paid on, and each spouse is held to their own cap; the + # deduction cannot be arbitrarily allocated. Without each spouse's + # federal withholding, attribute the couple's federal income tax by + # each spouse's share of federal adjusted gross income, then cap it. + federal_income_tax = max_( + person.tax_unit("income_tax_before_refundable_credits", period), 0 + ) + share = person("mt_federal_income_tax_deduction_share", period) filing_status = person.tax_unit( "state_filing_status_if_married_filing_separately_on_same_return", period, ) - p = parameters( - period - ).gov.states.mt.tax.income.deductions.itemized.federal_income_tax - cap = p.cap[filing_status] - return min_(unit_deds * prorate, cap) + return min_(federal_income_tax * share, p.cap[filing_status]) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_tax/mt_federal_income_tax_deduction_share.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_tax/mt_federal_income_tax_deduction_share.py new file mode 100644 index 00000000000..2c6dfd8556b --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/federal_tax/mt_federal_income_tax_deduction_share.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class mt_federal_income_tax_deduction_share(Variable): + value_type = float + entity = Person + definition_period = YEAR + label = "Share of the couple's federal income tax attributed to each spouse for the Montana deduction" + reference = ( + # 2022 Form 2 instructions, Itemized Deductions Schedule, line 4a: + # "If you are married filing separately with your spouse, the federal + # income tax withheld should be reported by the spouse who earned the + # income." + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2022_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=33", + ) + unit = "/1" + defined_for = "mt_married_filing_separately_on_same_return_eligible" + + def formula(person, period, parameters): + # Each filer's share of the federal income the tax was paid on, + # counting only positive federal adjusted gross income. A dependent's + # income is on the dependent's own return. With no positive income, + # the tax is attributed to the head. + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + income = head_or_spouse * max_( + person("adjusted_gross_income_person", period), 0 + ) + total_income = person.tax_unit.sum(income) + share = np.zeros_like(total_income) + mask = total_income > 0 + share[mask] = income[mask] / total_income[mask] + head = person("is_tax_unit_head", period) + return where(total_income > 0, share, head) 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..808615ac88f 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 @@ -30,7 +30,8 @@ def formula(person, period, parameters): person, period, [ - "mt_misc_deductions", + "mt_casualty_loss_deduction_indiv", + "mt_child_dependent_care_expense_deduction", "mt_medical_expense_deduction_indiv", "mt_salt_deduction", "mt_federal_income_tax_deduction_indiv", 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..5648c843633 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 @@ -23,7 +23,8 @@ def formula(person, period, parameters): person.tax_unit, period, [ - "mt_misc_deductions", + "mt_casualty_loss_deduction_joint", + "mt_child_dependent_care_expense_deduction_joint", "mt_medical_expense_deduction_joint", "mt_salt_deduction", "mt_federal_income_tax_deduction_unit", diff --git a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_misc_deductions.py b/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_misc_deductions.py deleted file mode 100644 index 354dc6ca059..00000000000 --- a/policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_misc_deductions.py +++ /dev/null @@ -1,17 +0,0 @@ -from policyengine_us.model_api import * - - -class mt_misc_deductions(Variable): - value_type = float - entity = Person - label = "Montana miscellaneous deductions" - unit = USD - definition_period = YEAR - reference = ( - "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/", - # Montana Code Annotated MT Code § 15-30-2131 (2022) (1)(a)&(c) - ) - defined_for = StateCode.MT - - adds = "gov.states.mt.tax.income.deductions.itemized.misc_deductions" diff --git a/policyengine_us/variables/gov/states/ny/tax/income/taxable_income/deductions/itemized/pre_tcja/ny_casualty_loss_deduction.py b/policyengine_us/variables/gov/states/ny/tax/income/taxable_income/deductions/itemized/pre_tcja/ny_casualty_loss_deduction.py index b179c6f0fab..815ff506ac5 100644 --- a/policyengine_us/variables/gov/states/ny/tax/income/taxable_income/deductions/itemized/pre_tcja/ny_casualty_loss_deduction.py +++ b/policyengine_us/variables/gov/states/ny/tax/income/taxable_income/deductions/itemized/pre_tcja/ny_casualty_loss_deduction.py @@ -9,21 +9,40 @@ class ny_casualty_loss_deduction(Variable): definition_period = YEAR reference = ( "https://www.nysenate.gov/legislation/laws/TAX/615", - "https://www.tax.ny.gov/pit/file/itemized-deductions.htm", + # 2025 Form IT-196 instructions, line 20 and the Casualty and theft + # worksheet, Section A + "https://www.tax.ny.gov/pdf/2025/inc/it196i_2025.pdf#page=3", + "https://www.tax.ny.gov/pdf/2025/inc/it196i_2025.pdf#page=4", + "https://www.tax.ny.gov/pdf/2024/inc/it196i_2024.pdf#page=3", + "https://www.tax.ny.gov/pdf/2024/inc/it196i_2024.pdf#page=4", + # IRS Publication 547 (2017), $100 Rule + "https://www.irs.gov/pub/irs-prior/p547--2017.pdf#page=10", ) defined_for = StateCode.NY documentation = """ NY Tax Law § 615 requires itemized deductions to be computed using - pre-TCJA federal rules. Unlike federal rules post-2017, NY still - allows casualty and theft loss deductions not limited to federally - declared disasters. The 10% AGI floor still applies. + pre-TCJA federal rules. Form IT-196 line 20 figures the casualty and theft + loss "using the federal rules that applied to tax year 2017", so, unlike the + federal deduction after 2017, it is not limited to federally declared + disasters. Each casualty is reduced by $100, and the rest is deductible + above 10% of federal adjusted gross income. """ def formula(tax_unit, period, parameters): - # NY uses pre-TCJA rules: casualty losses are still deductible - # (not limited to federally declared disasters like federal post-2017) - loss = add(tax_unit, period, ["casualty_loss"]) p = parameters(period).gov.irs.deductions.itemized.casualty + # NY uses pre-TCJA rules: casualty losses are still deductible (not + # limited to federally declared disasters like federal post-2017), so + # the federal suspension flag does not apply. + # Only the owner of the property claims the loss. A dependent's loss + # belongs on the dependent's own return, as the dependent's income + # does: federal adjusted gross income leaves it out. + loss = tax_unit_non_dep_add(tax_unit, period, ["casualty_loss"]) + # Worksheet line 11 reduces each casualty by $100. A joint return is + # one individual for the $100 rule. The model records one loss amount + # per person, not separate casualty events, so the return's losses are + # treated as one casualty and the reduction applies once. + reduced_loss = max_(loss - p.per_casualty_reduction, 0) + # Worksheet line 17: 10% of federal adjusted gross income (Form IT-201, + # line 19). positive_agi = tax_unit("positive_agi", period) - # Apply the 10% AGI floor (pre-TCJA rule) - return max_(0, loss - positive_agi * p.floor) + return max_(reduced_loss - positive_agi * p.floor, 0)