diff --git a/changelog.d/taxsim-sweep-ar-mt-nm-fixes.fixed.md b/changelog.d/taxsim-sweep-ar-mt-nm-fixes.fixed.md new file mode 100644 index 00000000000..cd827e1a467 --- /dev/null +++ b/changelog.d/taxsim-sweep-ar-mt-nm-fixes.fixed.md @@ -0,0 +1 @@ +Fixed Arkansas gross income to include partnership and S-corporation income and to let one spouse's loss offset the other's income on a joint return; Montana's capital gain credit to be zero rather than negative on net losses, dependent exemptions to cover non-child dependents whose own Montana gross income (excluding unemployment compensation; only taxable Social Security) is at or below the exemption amount, and permanently and totally disabled adult children to count as qualifying children, and Montana joint AGI to leave out a dependent's Montana additions and subtractions, which are not on the filer's return; and New Mexico's net capital gains deduction to exclude short-term gains in every year, following the IRC Section 1222(11) definition that New Mexico law has used since 2019, and to include capital gain distributions. diff --git a/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml b/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml index 6c709962bc8..867de64db9e 100644 --- a/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml +++ b/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml @@ -19,6 +19,7 @@ values: - taxable_pension_income # Line 17A/17B - disability_benefits # Line 17A/17B - rental_income # Line 18 + - partnership_s_corp_income # Line 18 - estate_income # Line 18 - farm_rent_income # Line 18, Form 4835 rent is reported on Schedule E - farm_operations_income # Line 19, Schedule F @@ -44,6 +45,7 @@ values: - taxable_pension_income # Line 18A/18B - disability_benefits # Line 18A/18B - rental_income # Line 19 + - partnership_s_corp_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E - farm_operations_income # Line 20, Schedule F @@ -63,6 +65,7 @@ values: - taxable_pension_income # Line 18A/18B - disability_benefits # Line 18A/18B - rental_income # Line 19 + - partnership_s_corp_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E - farm_operations_income # Line 20, Schedule F @@ -85,6 +88,7 @@ values: - keogh_distributions # Line 18A/18B - disability_benefits # Line 18A/18B - rental_income # Line 19 + - partnership_s_corp_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E - farm_operations_income # Line 20, Schedule F diff --git a/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/joint.yaml b/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/joint.yaml index f5e8bf42c71..ea66014a09b 100644 --- a/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/joint.yaml +++ b/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/joint.yaml @@ -19,6 +19,7 @@ values: - taxable_pension_income # Line 17A/17B - disability_benefits # Line 17A/17B - rental_income # Line 18 + - partnership_s_corp_income # Line 18 - estate_income # Line 18 - farm_rent_income # Line 18, Form 4835 rent is reported on Schedule E - farm_operations_income # Line 19, Schedule F @@ -44,6 +45,7 @@ values: - taxable_pension_income # Line 18A/18B - disability_benefits # Line 18A/18B - rental_income # Line 19 + - partnership_s_corp_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E - farm_operations_income # Line 20, Schedule F @@ -63,6 +65,7 @@ values: - taxable_pension_income # Line 18A/18B - disability_benefits # Line 18A/18B - rental_income # Line 19 + - partnership_s_corp_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E - farm_operations_income # Line 20, Schedule F @@ -85,6 +88,7 @@ values: - keogh_distributions # Line 18A/18B - disability_benefits # Line 18A/18B - rental_income # Line 19 + - partnership_s_corp_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E - farm_operations_income # Line 20, Schedule F diff --git a/policyengine_us/tests/code_health/test_ar_gross_income_source_line_comments.py b/policyengine_us/tests/code_health/test_ar_gross_income_source_line_comments.py index 9bcafacd5aa..7ab012c7ad6 100644 --- a/policyengine_us/tests/code_health/test_ar_gross_income_source_line_comments.py +++ b/policyengine_us/tests/code_health/test_ar_gross_income_source_line_comments.py @@ -11,7 +11,7 @@ 13 business income (Schedule C), 14 capital gains, 16 nonqualified IRA distributions and taxable annuities, 17A/17B employer pensions and qualified IRAs, where military retirement and disability retirement also go, 18 Schedule -E, 19 Schedule F, 20 other income (Form AR-OI, including gambling winnings). +E (rents, royalties, partnerships, S corporations, estates and trusts), 19 Schedule F, 20 other income (Form AR-OI, including gambling winnings). TY2018+ AR1000F (2018 booklet, form on #page=15; 2022 and 2025 AR1000F, #page=2): 13 business income, 14 capital gains, 16 nonqualified IRA @@ -49,6 +49,7 @@ "taxable_pension_income": "17A/17B", "disability_benefits": "17A/17B", "rental_income": "18", + "partnership_s_corp_income": "18", "estate_income": "18", "farm_rent_income": "18", "farm_operations_income": "19", @@ -73,6 +74,7 @@ "keogh_distributions": "18A/18B", "disability_benefits": "18A/18B", "rental_income": "19", + "partnership_s_corp_income": "19", "estate_income": "19", "farm_rent_income": "19", "farm_operations_income": "20", diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_agi_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_agi_joint.yaml index ce671aa83aa..b481feb47b3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_agi_joint.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_agi_joint.yaml @@ -19,7 +19,7 @@ output: ar_agi_joint: [900, 1_800] -- name: Dependent AGI gets attributed to the head, AGI capped at 0 +- name: Dependent AGI gets attributed to the head; spouse net income is not floored on a joint return period: 2022 input: people: @@ -43,4 +43,32 @@ members: [person1, person2, person3] state_code: AR output: - ar_agi_joint: [1_200, 0, 0] + # Head: 900 + dependent's 300 (dependent income floored at 0, then + # attributed to the head). Spouse: 100 - 200 = -100. On a joint return all + # income goes in Column A, so the spouse's amount offsets the head's; the + # tax unit total is floored at 0 only when used as a tax base. + ar_agi_joint: [1_200, -100, 0] + +- name: A spouse's business loss offsets the other spouse's income on a joint return + period: 2024 + input: + people: + person1: + ar_gross_income_joint: 50_000 + ar_exemptions: 0 + is_tax_unit_dependent: false + is_tax_unit_head: true + person2: + ar_gross_income_joint: -10_000 + ar_exemptions: 0 + is_tax_unit_dependent: false + is_tax_unit_head: false + households: + household: + members: [person1, person2] + state_code: AR + output: + # AR1000F instructions: "If your filing status is Married Filing + # Separately on the Same Return, both Column A and Column B must be used. + # ... For all other filing statuses, write all income in Column A only." + ar_agi_joint: [50_000, -10_000] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_gross_income_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_gross_income_indiv.yaml index 0b095676ec0..930e680bab8 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_gross_income_indiv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_gross_income_indiv.yaml @@ -161,6 +161,19 @@ ar_gross_income_indiv: 33_000 ar_gross_income_joint: 33_000 +- name: Arkansas gross income includes partnership and S-corporation income + period: 2024 + input: + irs_employment_income: 30_000 + partnership_s_corp_income: 20_000 + state_code: AR + output: + # AR1000F Line 19: "income from rents, royalties, estates or trusts, + # profits (whether received or not) from partnerships, fiduciaries, small + # business corporations, etc." + ar_gross_income_indiv: 50_000 + ar_gross_income_joint: 50_000 + - name: Arkansas gross income includes estate and trust income (AR1000F line 19) period: 2024 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_net_taxable_income_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_net_taxable_income_joint.yaml index 75a01bb0fee..0c8b2a264a0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_net_taxable_income_joint.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_net_taxable_income_joint.yaml @@ -106,3 +106,26 @@ output: # Total AGI = 10k + 10k = 20k, all attributed to head ar_net_taxable_income_joint: [20_000, 0] + +- name: A negative joint total is floored at zero when the low income table is used + period: 2024 + input: + people: + person1: + ar_taxable_income_joint: 0 + ar_agi_joint: 5_000 + is_tax_unit_head: true + person2: + ar_taxable_income_joint: 0 + ar_agi_joint: -10_000 + tax_units: + tax_unit: + members: [person1, person2] + ar_uses_low_income_tax_tables: true + households: + household: + members: [person1, person2] + state_code: AR + output: + # 5,000 - 10,000 = -5,000 combined; the tax base cannot be negative. + ar_net_taxable_income_joint: [0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.yaml index 86cca44a96e..baf51c21542 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.yaml @@ -86,3 +86,24 @@ state_code: AR output: ar_casualty_loss_deduction_joint: 14_500 + +- name: A spouse's loss that makes the joint AGI negative does not raise the casualty loss deduction + period: 2024 + input: + people: + person1: + casualty_loss: 1_000 + ar_agi_joint: 5_000 + person2: + ar_agi_joint: -10_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Joint AGI 5,000 - 10,000 = -5,000, floored at 0: + # 1,000 - 100 - 10% * 0 = 900 (an unfloored AGI would give 900 + 500). + ar_casualty_loss_deduction_joint: 900 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.yaml index d059cdafa4b..2a3b9666fe4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.yaml @@ -204,6 +204,29 @@ # 9_000 - 0.075 * 50_000; Form AR3 Line 3B: "if either you or your spouse were age 65 or over" ar_medical_expense_deduction_joint: [5_250, 0] +- name: A spouse's loss that makes the joint AGI negative does not raise the medical expense deduction + period: 2024 + input: + people: + person1: + age: 40 + ar_agi_joint: 5_000 + person2: + age: 40 + ar_agi_joint: -10_000 + tax_units: + tax_unit: + members: [person1, person2] + itemized_medical_expenses: 1_000 + households: + household: + members: [person1, person2] + state_code: AR + output: + # Joint AGI 5,000 - 10,000 = -5,000, floored at 0, so the 10% floor is 0: + # 1,000 - 0.1 * 0 = 1,000 (an unfloored AGI would give 1,000 + 500). + ar_medical_expense_deduction_joint: 1_000 + - name: Arkansas joint medical deduction excludes self-employed premiums before its 10% floor period: 2025 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_misc_deduction_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_misc_deduction_joint.yaml index f862cd1d699..9054f751b53 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_misc_deduction_joint.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_misc_deduction_joint.yaml @@ -63,3 +63,24 @@ state_code: AR output: ar_misc_deduction_joint: 5_500 + +- name: A spouse's loss that makes the joint AGI negative does not raise the miscellaneous deduction + period: 2024 + input: + people: + person1: + ar_agi_joint: 5_000 + person2: + ar_agi_joint: -10_000 + tax_units: + tax_unit: + members: [person1, person2] + total_misc_deductions: 1_000 + households: + household: + members: [person1, person2] + state_code: AR + output: + # Joint AGI 5,000 - 10,000 = -5,000, floored at 0: + # 1,000 - 2% * 0 = 1,000 (an unfloored AGI would give 1,000 + 100). + ar_misc_deduction_joint: 1_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/integration.yaml index 82380261ea1..f12cef5c9b3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/integration.yaml @@ -388,3 +388,255 @@ # Tax: max($321.44 - $236, 0) = $85.44 # TaxAct reference: $86 (from TAXSIM issue #493) ar_income_tax: 85 + +# Married couples filing jointly: all income goes in Column A, so one spouse's +# partnership/S-corporation loss offsets the other spouse's wages (2024 +# AR1000F/AR1000NR instructions, p.12: +# https://www.dfa.arkansas.gov/wp-content/uploads/2024_AR1000F_and_AR1000NR_Instructions.pdf#page=12). +# 2024 values: joint standard deduction $4,820; personal credit $29 each; the +# joint low income table tops out at $28,300. + +- name: Married joint couple, spouse loss offsets wages, positive combined income on the regular table + absolute_error_margin: 0.01 + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 60_000 + person2: + age: 38 + partnership_s_corp_income: -20_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_agi_joint: [60_000, -20_000] + # Combined AGI = 60,000 - 20,000 = 40,000; taxable income = + # 40,000 - 4,820 = 35,180, held by the head. + ar_taxable_income_joint: [35_180, 0] + # 40,000 is above the low income table, so the regular table applies. + ar_uses_low_income_tax_tables: false + ar_net_taxable_income_joint: [35_180, 0] + # 35,180 x 3.9% - 409.86 = 1,372.02 - 409.86 = 962.16 + # The model uses the bracket formula. The 2024 tax table band + # 35,100-35,200 gives 961 (p.31), or 903 after credits; the gap between + # the formula and the table is at most about 2.45 below 100,000. + ar_income_tax_before_non_refundable_credits_joint: [962.16, 0] + # Separately, person1 alone: (60,000 - 2,410) x 3.9% - 409.86 = 1,836.15. + ar_files_separately: false + ar_income_tax_before_non_refundable_credits_unit: 962.16 + # Personal credits 2 x 29 = 58; additional credit + # 120 - ceil((35,180 - 25,800) / 100) x 5 x 2 = 120 - 940 -> 0. + ar_non_refundable_credits: 58 + # 962.16 - 58 = 904.16 + ar_income_tax: 904.16 + +- name: Married joint couple, spouse loss offsets wages, positive combined income on the low income table + absolute_error_margin: 0.01 + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 47_050 + person2: + age: 38 + partnership_s_corp_income: -21_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_agi_joint: [47_050, -21_000] + # Combined AGI = 47,050 - 21,000 = 26,050; taxable income = + # 26,050 - 4,820 = 21,230. + ar_taxable_income_joint: [21_230, 0] + # Low income table (joint, 0-1 dependents), 26,000 < 26,050 <= 26,100: 283. + ar_low_income_tax_joint: [283, 0] + # Regular table: 21,230 x 3.4% - 281.37 = 721.82 - 281.37 = 440.45 > 283. + ar_uses_low_income_tax_tables: true + # The low income table uses AGI rather than taxable income. + ar_net_taxable_income_joint: [26_050, 0] + ar_income_tax_before_non_refundable_credits_joint: [283, 0] + ar_files_separately: false + ar_income_tax_before_non_refundable_credits_unit: 283 + # Additional credit: 120 - ceil((26,050 - 25,800) / 100) x 5 x 2 = 120 - 30 = 90. + ar_additional_tax_credit_for_qualified_individuals: 90 + # Personal credits 2 x 29 = 58; 58 + 90 = 148. + ar_non_refundable_credits: 148 + # 283 - 148 = 135 + ar_income_tax: 135 + +- name: Married joint couple, spouse loss exactly cancels wages, zero combined income + absolute_error_margin: 0.01 + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 20_000 + person2: + age: 38 + partnership_s_corp_income: -20_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_agi_joint: [20_000, -20_000] + # Combined AGI = 20,000 - 20,000 = 0; max(0, 0 - 4,820) = 0. + ar_taxable_income_joint: [0, 0] + ar_low_income_tax_joint: [0, 0] + # Both tables give 0 tax, so the low income table is not selected. + ar_uses_low_income_tax_tables: false + ar_net_taxable_income_joint: [0, 0] + ar_income_tax_before_non_refundable_credits_joint: [0, 0] + # Separately, person1 alone: (20,000 - 2,410) x 3.4% - 281.37 = 316.69. + ar_files_separately: false + ar_income_tax_before_non_refundable_credits_unit: 0 + ar_income_tax: 0 + +- name: Married joint couple, spouse loss exceeds wages, negative combined income + absolute_error_margin: 0.01 + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 10_000 + person2: + age: 38 + partnership_s_corp_income: -25_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_agi_joint: [10_000, -25_000] + # Combined AGI = 10,000 - 25,000 = -15,000; max(0, -15,000 - 4,820) = 0. + ar_taxable_income_joint: [0, 0] + # The low income table is looked up at max(-15,000, 0) = 0, giving 0. + ar_low_income_tax_joint: [0, 0] + ar_uses_low_income_tax_tables: false + ar_net_taxable_income_joint: [0, 0] + ar_income_tax_before_non_refundable_credits_joint: [0, 0] + # Separately, person1 alone: (10,000 - 2,410) x 2% - 109.98 = 41.82. + ar_files_separately: false + ar_income_tax_before_non_refundable_credits_unit: 0 + ar_income_tax: 0 + +- name: Married joint couple, spouse loss exceeds wages that would be taxed under a per-spouse floor + absolute_error_margin: 0.01 + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 30_000 + person2: + age: 38 + partnership_s_corp_income: -45_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_agi_joint: [30_000, -45_000] + # Combined AGI = 30,000 - 45,000 = -15,000; max(0, -15,000 - 4,820) = 0. + ar_taxable_income_joint: [0, 0] + ar_low_income_tax_joint: [0, 0] + ar_net_taxable_income_joint: [0, 0] + ar_income_tax_before_non_refundable_credits_joint: [0, 0] + # Separately, person1 alone: (30,000 - 2,410) x 3.9% - 409.86 = 666.15. + ar_files_separately: false + ar_income_tax_before_non_refundable_credits_unit: 0 + # Flooring each spouse at zero would tax the 30,000 on its own: + # (30,000 - 4,820) x 3.4% - 281.37 = 574.75, less 58 personal and 120 + # additional credits = 396.75. + ar_income_tax: 0 + +- name: Married joint couple, head loss offsets spouse wages + absolute_error_margin: 0.01 + period: 2024 + input: + people: + person1: + age: 40 + partnership_s_corp_income: -20_000 + person2: + age: 38 + employment_income: 60_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_agi_joint: [-20_000, 60_000] + # Combined AGI = -20,000 + 60,000 = 40,000; taxable income = + # 40,000 - 4,820 = 35,180, held by the head. + ar_taxable_income_joint: [35_180, 0] + ar_uses_low_income_tax_tables: false + ar_net_taxable_income_joint: [35_180, 0] + # 35,180 x 3.9% - 409.86 = 962.16 + ar_income_tax_before_non_refundable_credits_joint: [962.16, 0] + # Separately, person2 alone: (60,000 - 2,410) x 3.9% - 409.86 = 1,836.15. + ar_files_separately: false + ar_income_tax_before_non_refundable_credits_unit: 962.16 + # Personal credits 2 x 29 = 58; the additional credit phases out to 0. + ar_non_refundable_credits: 58 + # 962.16 - 58 = 904.16 + ar_income_tax: 904.16 + +- name: Married joint couple in 2021, partnership loss is in the earlier gross income source list + absolute_error_margin: 0.01 + period: 2021 + input: + people: + person1: + age: 40 + employment_income: 60_000 + person2: + age: 38 + partnership_s_corp_income: -20_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + # The 2020-01-01 source list (which covers 2021) includes + # partnership_s_corp_income. + ar_gross_income_indiv: [60_000, -20_000] + ar_agi_joint: [60_000, -20_000] + # Combined AGI = 60,000 - 20,000 = 40,000; taxable income = + # 40,000 - 4,400 (2021 joint standard deduction) = 35,600. + ar_taxable_income_joint: [35_600, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/mt_capital_gain_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/mt_capital_gain_credit.yaml index 370c349f925..6f28a48eb44 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/mt_capital_gain_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/mt_capital_gain_credit.yaml @@ -13,3 +13,13 @@ state_code: MT output: mt_capital_gain_credit: 60 + +- name: A net capital loss produces no credit rather than a negative one + period: 2022 + input: + capital_gains: -5_000 + state_code: MT + output: + # 2% of net capital gains (Form 2 instructions, Line 1); a net loss is not + # a net capital gain, so the credit is 0, not -100. + mt_capital_gain_credit: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/exemptions/mt_dependent_exemptions_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/exemptions/mt_dependent_exemptions_person.yaml index 406960f7e07..9104def4ba4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/exemptions/mt_dependent_exemptions_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/exemptions/mt_dependent_exemptions_person.yaml @@ -6,6 +6,11 @@ is_qualifying_child_dependent: false is_disabled: false person3: + # Not a qualifying child, and gross income of $3,000 (wages) is above + # the $2,580 exemption amount, so not a Montana dependent. + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 3_000 is_qualifying_child_dependent: false is_disabled: false person4: @@ -71,9 +76,18 @@ person1: is_tax_unit_head: true person3: + # Not qualifying children, and gross income (wages of $5,000 and + # $2,711) above the $2,710 exemption amount, so neither is a Montana + # dependent. + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 5_000 is_qualifying_child_dependent: false is_disabled: false person4: + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 2_711 is_qualifying_child_dependent: false is_disabled: true tax_units: @@ -108,3 +122,626 @@ state_code: MT output: mt_dependent_exemptions_person: [0, 0, 0] + +- name: Adult dependent with no gross income is eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + person2: + # e.g. a parent who is not a qualifying child. Form 2 instructions: a + # dependent is an individual "who does not have gross income of more + # than $2,710, unless the dependent is a 'qualifying child'". + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 0 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + mt_dependent_exemptions_person: [0, 2_710] + +- name: Adult dependent with gross income exactly at the exemption amount is eligible + period: 2023 + input: + people: + person1: + is_tax_unit_head: true + person2: + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 2_960 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # "not ... more than" the $2,960 exemption amount + mt_dependent_exemptions_person: [0, 2_960] + +- name: Disabled adult dependent who is not the taxpayer's child (for example, a parent) gets one exemption, not two + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + person2: + # The additional exemption is "for a child who is disabled". This + # dependent is not the taxpayer's child (for example, a parent), so + # is_qualifying_child_dependent is false. + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 1_000 + is_qualifying_child_dependent: false + is_disabled: true + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + mt_dependent_exemptions_person: [0, 2_710] + +- name: Adult dependent with wages just below the 2022 exemption amount is eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + person2: + age: 20 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 2_709 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 2,709 of wages <= 2,710 exemption amount, so one + # exemption of 2,710. + mt_dependent_exemptions_person: [0, 2_710] + +- name: Adult dependent with wages exactly at the 2022 exemption amount is eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + person2: + age: 20 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 2_710 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 2,710 of wages, which is not "more than" the 2,710 + # exemption amount, so one exemption of 2,710. + mt_dependent_exemptions_person: [0, 2_710] + +- name: Adult dependent with wages above the 2022 exemption amount is not eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + person2: + age: 20 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 3_000 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 3,000 of wages > 2,710 exemption amount, so not a + # Montana dependent. + mt_dependent_exemptions_person: [0, 0] + +- name: Adult dependent whose wages and interest together exceed the 2022 exemption amount is not eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + person2: + age: 20 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 2_000 + taxable_interest_income: 1_000 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 2,000 wages + 1,000 interest = 3,000 > 2,710, so not a + # Montana dependent. + mt_dependent_exemptions_person: [0, 0] + +- name: Qualifying child with wages above the 2022 exemption amount is still eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + person2: + age: 17 + is_tax_unit_dependent: true + employment_income: 5_000 + is_qualifying_child_dependent: true + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # The gross income test does not apply to a qualifying child, so 5,000 of + # wages above the 2,710 exemption amount still gives one exemption of 2,710. + mt_dependent_exemptions_person: [0, 2_710] + +# The income test uses Montana gross income (MCA 15-30-2101(10), see +# mt_dependent_gross_income): federal gross income excluding unemployment +# compensation, only taxable Social Security, and gains but not losses. In +# these 2022 cases the taxpayer has 50,000 of wages, so one 2,710 exemption +# changes mt_income_tax by 2,710 x 6.75% = 182.925 (182.92 or 182.93 after +# rounding). + +- name: Adult dependent with only unemployment compensation is eligible because Montana excludes it + absolute_error_margin: 0.01 + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + unemployment_compensation: 3_000 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Montana gross income = 3,000 - 3,000 unemployment compensation = 0 + # <= 2,710, so one exemption of 2,710. + mt_dependent_exemptions_person: [0, 2_710] + # The dependent's unemployment compensation is not on the filer's return, + # so Montana AGI is 50,000 and the standard deduction is 20% of it, 10,000. + # Taxable income = 50,000 - 10,000 - 2 x 2,710 exemptions = 34,580. + # Without the dependent's exemption the tax is 1,914.58; + # 1,914.58 - 2,710 x 6.75% (182.93) = 1,731.65. + mt_income_tax: 1_731.65 + +- name: Adult dependent with unemployment compensation and wages exactly at the 2022 exemption amount is eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + unemployment_compensation: 3_000 + employment_income: 2_710 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Montana gross income = 2,710 wages (the 3,000 of unemployment + # compensation is excluded) <= 2,710, so one exemption of 2,710. + mt_dependent_exemptions_person: [0, 2_710] + +- name: Adult dependent with unemployment compensation and wages one dollar above the 2022 exemption amount is not eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + unemployment_compensation: 3_000 + employment_income: 2_711 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Montana gross income = 2,711 wages > 2,710, so not a Montana dependent. + mt_dependent_exemptions_person: [0, 0] + +- name: Dependent parent with Social Security below the taxable threshold is eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + social_security_retirement: 12_000 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Provisional income = 0.5 x 12,000 = 6,000 < 25,000, so no Social + # Security is taxable; Montana gross income = 0 <= 2,710. + mt_dependent_exemptions_person: [0, 2_710] + +- name: Dependent parent with taxable Social Security exactly at the 2022 exemption amount is eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + social_security_retirement: 60_840 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Provisional income = 0.5 x 60,840 = 30,420; taxable Social Security = + # min(30,420, 0.5 x (30,420 - 25,000)) = 2,710 <= 2,710. + mt_dependent_exemptions_person: [0, 2_710] + +- name: Dependent parent with taxable Social Security one dollar above the 2022 exemption amount is not eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + social_security_retirement: 60_844 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Provisional income = 0.5 x 60,844 = 30,422; taxable Social Security = + # min(30,422, 0.5 x (30,422 - 25,000)) = 2,711 > 2,710. + mt_dependent_exemptions_person: [0, 0] + +- name: Adult dependent whose long-term gain exceeds the exemption amount is not eligible despite a short-term loss + absolute_error_margin: 0.01 + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + long_term_capital_gains: 3_000 + short_term_capital_gains: -2_000 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income counts gains but not losses: 3,000 + 0 = 3,000 > 2,710 + # (the net gain is only 1,000), so not a Montana dependent. + mt_dependent_exemptions_person: [0, 0] + # With the exemption on the net 1,000 the tax was 1,711.65; + # 1,711.65 + 182.92 = 1,894.57. + mt_income_tax: 1_894.57 + +- name: Adult dependent whose short-term gain exceeds the exemption amount is not eligible despite a long-term loss + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + short_term_capital_gains: 2_711 + long_term_capital_gains: -3_000 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 2,711 + 0 = 2,711 > 2,710 (the net is a 289 loss), so + # not a Montana dependent. + mt_dependent_exemptions_person: [0, 0] + +- name: Adult dependent with wages exactly at the 2021 exemption amount is eligible + period: 2021 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 2_580 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 2,580 <= 2,580 exemption amount (2021 Form 2 + # instructions, p.13), so one exemption of 2,580. + mt_dependent_exemptions_person: [0, 2_580] + +- name: Adult dependent with wages one dollar above the 2021 exemption amount is not eligible + period: 2021 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 2_581 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 2,581 > 2,580, so not a Montana dependent. + mt_dependent_exemptions_person: [0, 0] + +- name: Adult dependent with wages one dollar above the 2023 exemption amount is not eligible + period: 2023 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + employment_income: 2_961 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 2,961 > 2,960 exemption amount (2023 Form 2 + # instructions, p.16), so not a Montana dependent. + mt_dependent_exemptions_person: [0, 0] + +- name: Full-time student aged 22 is a qualifying child with no gross income test + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + # is_qualifying_child_dependent is derived from age and student status. + age: 22 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + is_full_time_student: true + employment_income: 5_000 + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Age 22 < 24 student age limit, so a qualifying child; the 5,000 of wages + # is not tested, so one exemption of 2,710. + mt_dependent_exemptions_person: [0, 2_710] + +- name: Non-student aged 22 is not a qualifying child and fails the gross income test + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + # is_qualifying_child_dependent is derived from age and student status. + age: 22 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + is_full_time_student: false + employment_income: 5_000 + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Age 22 >= 19 non-student age limit, so not a qualifying child; gross + # income = 5,000 > 2,710, so not a Montana dependent. + mt_dependent_exemptions_person: [0, 0] + +- name: Permanently and totally disabled adult child is a qualifying child and gets two exemptions + absolute_error_margin: 0.01 + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + # IRC 152(c)(3)(B): the age test does not apply to a child who is + # permanently and totally disabled. + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + is_permanently_and_totally_disabled: true + is_disabled: true + employment_income: 5_000 + is_qualifying_child_dependent: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # A qualifying child skips the gross income test, and a disabled child + # gets an additional exemption: 2 x 2,710 = 5,420. + mt_dependent_exemptions_person: [0, 5_420] + # Without the exemptions the tax is 1,914.57; 1,914.57 - 2 x 182.925 + # = 1,548.72. + mt_income_tax: 1_548.72 + +- name: Adult dependent whose capital loss lowers taxable Social Security below the 2022 exemption amount is eligible + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false # Required, or the adult is inferred as the spouse and skips the income test. + unemployment_compensation: 26_000 + social_security_retirement: 10_000 + long_term_capital_gains: -3_000 + is_qualifying_child_dependent: false + is_disabled: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # IRC 86(b)(2) modified AGI = 26,000 unemployment compensation - 3,000 + # capital loss = 23,000; combined income = 23,000 + 0.5 x 10,000 = 28,000; + # taxable Social Security = min(5,000, 0.5 x (28,000 - 25,000)) = 1,500. + # Montana gross income = 1,500 (unemployment compensation is excluded and + # losses are not gross income) <= 2,710, so one exemption of 2,710. + mt_dependent_exemptions_person: [0, 2_710] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/exemptions/mt_dependent_gross_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/exemptions/mt_dependent_gross_income.yaml new file mode 100644 index 00000000000..612f06f645e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/exemptions/mt_dependent_gross_income.yaml @@ -0,0 +1,222 @@ +# Montana gross income (MCA 15-30-2101(10)) for the dependent income test in +# MCA 15-30-2114(5)(a): federal gross income excluding unemployment +# compensation, with only the IRC 86 taxable part of Social Security, and with +# gains but not losses (Pub. 501 (2022), p.2). Each case is 2022: the taxpayer +# (tax unit head) has $50,000 of wages, and the dependent is an adult who is +# not a qualifying child. is_tax_unit_spouse: false is required on each +# dependent; otherwise the adult is inferred as the spouse, whose income is +# not counted. 2022 IRC 86 single base amounts: $25,000 and $34,000. + +- name: Case 1, unemployment compensation is excluded. + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + is_qualifying_child_dependent: false + unemployment_compensation: 3_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 3,000 unemployment compensation - 3,000 excluded = 0. + mt_dependent_gross_income: [0, 0] + +- name: Case 2, wages still count when unemployment compensation is excluded. + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + is_qualifying_child_dependent: false + unemployment_compensation: 3_000 + employment_income: 2_711 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = 2,711 wages + 0 of the 3,000 unemployment compensation + # = 2,711. + mt_dependent_gross_income: [0, 2_711] + +- name: Case 3, Social Security below the base amount is not gross income. + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + is_qualifying_child_dependent: false + social_security_retirement: 12_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Provisional income = 0 other gross income + 0.5 x 12,000 = 6,000 + # < 25,000 base amount, so taxable Social Security = 0. + # Gross income = 0 + 0 = 0. + mt_dependent_gross_income: [0, 0] + +- name: Case 4, taxable Social Security exactly at the exemption amount. + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + is_qualifying_child_dependent: false + social_security_retirement: 60_840 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Provisional income = 0.5 x 60,840 = 30,420, between 25,000 and 34,000. + # Taxable = min(0.5 x 60,840, 0.5 x (30,420 - 25,000)) + # = min(30,420, 2,710) = 2,710. + mt_dependent_gross_income: [0, 2_710] + +- name: Case 5, taxable Social Security one dollar above the exemption amount. + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + is_qualifying_child_dependent: false + social_security_retirement: 60_844 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Provisional income = 0.5 x 60,844 = 30,422. + # Taxable = min(30,422, 0.5 x (30,422 - 25,000)) = min(30,422, 2,711) + # = 2,711. + mt_dependent_gross_income: [0, 2_711] + +- name: Case 6, a short-term loss does not offset a long-term gain. + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + is_qualifying_child_dependent: false + long_term_capital_gains: 3_000 + short_term_capital_gains: -2_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = max(0, 3,000) + max(0, -2,000) = 3,000 + 0 = 3,000, + # not the net gain of 1,000. + mt_dependent_gross_income: [0, 3_000] + +- name: Case 7, a long-term loss does not offset a short-term gain. + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + is_qualifying_child_dependent: false + short_term_capital_gains: 2_711 + long_term_capital_gains: -3_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Gross income = max(0, 2,711) + max(0, -3,000) = 2,711 + 0 = 2,711, + # not the net loss of 289. + mt_dependent_gross_income: [0, 2_711] + +- name: Case 8, a capital loss reduces the modified AGI that sets taxable Social Security. + period: 2022 + input: + people: + person1: + is_tax_unit_head: true + employment_income: 50_000 + person2: + age: 70 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + is_qualifying_child_dependent: false + unemployment_compensation: 26_000 + social_security_retirement: 10_000 + long_term_capital_gains: -3_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # IRC 86(b)(2) modified AGI = 26,000 unemployment compensation - 3,000 + # capital loss (within the IRC 1211(b) limit) = 23,000. + dependent_taxable_ss_magi: [0, 23_000] + # Combined income = 23,000 + 0.5 x 10,000 = 28,000, between 25,000 and + # 34,000. Taxable = min(0.5 x 10,000, 0.5 x (28,000 - 25,000)) + # = min(5,000, 1,500) = 1,500. + dependent_taxable_social_security: [0, 1_500] + # Gross income = 0 unemployment compensation (excluded) + 0 capital gains + # (losses are not gross income) + 1,500 taxable Social Security = 1,500. + mt_dependent_gross_income: [0, 1_500] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/mt_agi_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/mt_agi_joint.yaml new file mode 100644 index 00000000000..f1e3425ed94 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/mt_agi_joint.yaml @@ -0,0 +1,45 @@ +- name: A dependent's Montana subtraction stays off the filer's joint Montana AGI + period: 2022 + input: + people: + head: + is_tax_unit_head: true + employment_income: 50_000 + dependent: + age: 30 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + unemployment_compensation: 3_000 + tax_units: + tax_unit: + members: [head, dependent] + households: + household: + members: [head, dependent] + state_code: MT + output: + # The dependent's unemployment compensation is not in the filer's federal + # AGI, so its Montana subtraction does not reduce the filer's Montana AGI. + mt_agi_joint: 50_000 + +- name: A spouse's Montana subtraction still offsets the joint return's income + period: 2022 + input: + people: + head: + is_tax_unit_head: true + employment_income: 50_000 + spouse: + is_tax_unit_spouse: true + unemployment_compensation: 3_000 + tax_units: + tax_unit: + members: [head, spouse] + households: + household: + members: [head, spouse] + state_code: MT + output: + # Federal AGI 53,000 includes the spouse's 3,000 of unemployment + # compensation, which Montana subtracts: 53,000 - 3,000 = 50,000. + mt_agi_joint: 50_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/nm_net_capital_gains_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/nm_net_capital_gains_deduction.yaml index b7d6e6a7080..2ab1cd66842 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/nm_net_capital_gains_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/nm_net_capital_gains_deduction.yaml @@ -2,7 +2,7 @@ period: 2021 input: filing_status: SINGLE - capital_gains: 0 + long_term_capital_gains: 0 state_code: NM output: nm_net_capital_gains_deduction: 0 @@ -11,7 +11,7 @@ period: 2021 input: filing_status: SEPARATE - capital_gains: 10_000 + long_term_capital_gains: 10_000 state_code: NM output: nm_net_capital_gains_deduction: 2_000 @@ -20,7 +20,7 @@ period: 2021 input: filing_status: JOINT - capital_gains: 2_000 + long_term_capital_gains: 2_000 state_code: NM output: nm_net_capital_gains_deduction: 1_000 @@ -29,7 +29,7 @@ period: 2021 input: filing_status: SEPARATE - capital_gains: 1_000 + long_term_capital_gains: 1_000 state_code: NM output: nm_net_capital_gains_deduction: 500 @@ -42,7 +42,7 @@ period: 2025 input: filing_status: SINGLE - capital_gains: 500_000 + long_term_capital_gains: 500_000 state_code: NM output: nm_net_capital_gains_deduction: 2_500 @@ -51,7 +51,7 @@ period: 2025 input: filing_status: SINGLE - capital_gains: 3_000_000 + long_term_capital_gains: 3_000_000 state_code: NM output: nm_net_capital_gains_deduction: 2_500 @@ -60,7 +60,7 @@ period: 2025 input: filing_status: SEPARATE - capital_gains: 2_000_000 + long_term_capital_gains: 2_000_000 state_code: NM output: nm_net_capital_gains_deduction: 1_250 @@ -69,7 +69,212 @@ period: 2024 input: filing_status: SINGLE - capital_gains: 3_000_000 + long_term_capital_gains: 3_000_000 state_code: NM output: nm_net_capital_gains_deduction: 1_200_000 + +# "Net capital gains" follow IRC Section 1222(11): net long-term capital gain +# less any net short-term capital loss. NMSA 7-2-34 has adopted that +# definition since tax year 2019 (2019 HB6, section 14; applicability in +# section 59(A), p.105): in subsection (D) for 2019 through 2024 and in +# subsection (C) from 2025 (2024 HB252, section 8, p.30; section 42(B), +# p.147). PIT-1 line 15 instructions (2023 PIT instruction book, p.32): "that +# section defines 'net capital gains' as only net long-term capital gains +# less any net short-term capital losses." + +- name: Short-term gains are excluded from net capital gains + period: 2023 + input: + filing_status: SINGLE + long_term_capital_gains: 10_000 + short_term_capital_gains: 5_000 + state_code: NM + output: + # max(40% x 10,000, min(10,000, 1,000)) = 4,000; the 5,000 short-term gain + # is not part of net capital gains. + nm_net_capital_gains_deduction: 4_000 + +- name: A net short-term loss reduces the long-term gain + period: 2024 + input: + filing_status: SINGLE + long_term_capital_gains: 10_000 + short_term_capital_gains: -4_000 + state_code: NM + output: + # Net capital gains = 10,000 - 4,000 = 6,000; 40% = 2,400. + nm_net_capital_gains_deduction: 2_400 + +- name: Only short-term gains means no net capital gains + period: 2023 + input: + filing_status: JOINT + long_term_capital_gains: 0 + short_term_capital_gains: 10_000 + state_code: NM + output: + nm_net_capital_gains_deduction: 0 + +- name: A net long-term loss means no net capital gains + period: 2023 + input: + filing_status: SINGLE + long_term_capital_gains: -2_000 + short_term_capital_gains: 5_000 + state_code: NM + output: + nm_net_capital_gains_deduction: 0 + +- name: Short-term gains are also excluded before 2023 + period: 2022 + input: + filing_status: SINGLE + long_term_capital_gains: 10_000 + short_term_capital_gains: 5_000 + state_code: NM + output: + # NMSA 7-2-34(D) (2019 HB6, sections 14 and 59(A)) already used IRC + # 1222(11) in 2022. + # Net capital gains = 10,000 - max(0, -5,000) = 10,000 (the 5,000 + # short-term gain is excluded). + # max(40% x 10,000, min(10,000, 1,000)) = max(4,000, 1,000) = 4,000. + nm_net_capital_gains_deduction: 4_000 + +# Cross-spouse netting on a joint return: net capital gain is computed on the +# couple's combined long-term and short-term amounts, so one spouse's net +# short-term loss reduces the other spouse's long-term gain. + +- name: Joint couple, one spouse's short-term loss partially offsets the other's long-term gain + period: 2023 + input: + people: + person1: + long_term_capital_gains: 20_000 + person2: + short_term_capital_gains: -5_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: NM + output: + # Net capital gains = 20,000 - 5,000 = 15,000. + # max(40% x 15,000, min(15,000, 1,000)) = max(6,000, 1,000) = 6,000. + nm_net_capital_gains_deduction: 6_000 + +- name: Joint couple, one spouse's short-term loss exactly cancels the other's long-term gain + period: 2023 + input: + people: + person1: + long_term_capital_gains: 8_000 + person2: + short_term_capital_gains: -8_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: NM + output: + # Net capital gains = max(0, 8,000 - 8,000) = 0. + # max(40% x 0, min(0, 1,000)) = 0; the $1,000 element is limited to the + # net capital gain. + nm_net_capital_gains_deduction: 0 + +- name: Joint couple, one spouse's short-term loss exceeds the other's long-term gain + period: 2023 + input: + people: + person1: + long_term_capital_gains: 5_000 + person2: + short_term_capital_gains: -12_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: NM + output: + # Net capital gains = max(0, 5,000 - 12,000) = 0, so no deduction. + nm_net_capital_gains_deduction: 0 + +- name: Joint couple, short-term gain and loss net across spouses before offsetting the long-term gain + period: 2023 + input: + people: + person1: + long_term_capital_gains: 10_000 + short_term_capital_gains: 3_000 + person2: + short_term_capital_gains: -5_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: NM + output: + # Net short-term = 3,000 - 5,000 = -2,000, a net short-term loss of 2,000. + # Net capital gains = 10,000 - 2,000 = 8,000; 40% x 8,000 = 3,200. + nm_net_capital_gains_deduction: 3_200 + +- name: Short-term gains are also excluded in 2021 + period: 2021 + input: + filing_status: SINGLE + long_term_capital_gains: 10_000 + short_term_capital_gains: 5_000 + state_code: NM + output: + # 2019 HB6, section 59(A), p.105: the IRC 1222(11) definition applies + # from 2019. Net capital gains = 10,000 - max(0, -5,000) = 10,000. + # max(40% x 10,000, min(10,000, 1,000)) = max(4,000, 1,000) = 4,000 + # (counting the short-term gain would give 40% x 15,000 = 6,000). + nm_net_capital_gains_deduction: 4_000 + +- name: Only short-term gains in 2021 means no net capital gains + period: 2021 + input: + filing_status: SINGLE + short_term_capital_gains: 10_000 + state_code: NM + output: + # Net capital gains = max(0, 0 - max(0, -10,000)) = 0, so no deduction + # (counting the short-term gain would give 40% x 10,000 = 4,000). + nm_net_capital_gains_deduction: 0 + +- name: Short-term gains are excluded in 2024 + period: 2024 + input: + filing_status: SINGLE + long_term_capital_gains: 10_000 + short_term_capital_gains: 5_000 + state_code: NM + output: + # Net capital gains = 10,000 - max(0, -5,000) = 10,000. + # max(40% x 10,000, min(10,000, 1,000)) = max(4,000, 1,000) = 4,000. + nm_net_capital_gains_deduction: 4_000 + +- name: Capital gain distributions are long-term capital gains + period: 2023 + input: + filing_status: SINGLE + non_sch_d_capital_gains: 5_000 + state_code: NM + output: + # Capital gain distributions are long-term capital gains under IRC + # 852(b)(3)(B), so net capital gains = 5,000. + # max(40% x 5,000, min(5,000, 1,000)) = max(2,000, 1,000) = 2,000. + nm_net_capital_gains_deduction: 2_000 diff --git a/policyengine_us/variables/gov/states/ar/tax/income/ar_agi_joint.py b/policyengine_us/variables/gov/states/ar/tax/income/ar_agi_joint.py index 8ef5fe055a6..9a72c0822f1 100644 --- a/policyengine_us/variables/gov/states/ar/tax/income/ar_agi_joint.py +++ b/policyengine_us/variables/gov/states/ar/tax/income/ar_agi_joint.py @@ -13,9 +13,13 @@ class ar_agi_joint(Variable): def formula(person, period, parameters): gross_income = person("ar_gross_income_joint", period) income_exemptions = person("ar_exemptions", period) - net_income = max_(gross_income - income_exemptions, 0) - # allocate any dependent gross income to tax unit head + net_income = gross_income - income_exemptions + # On a return that is not married filing separately on the same + # return, all income goes in Column A, so one spouse's loss offsets + # the other's income; the tax unit total is floored at zero when it + # is used as a tax base. + # Allocate any dependent net income (floored at zero) to the head. is_dependent = person("is_tax_unit_dependent", period) - sum_dep_net_income = person.tax_unit.sum(is_dependent * net_income) + sum_dep_net_income = person.tax_unit.sum(is_dependent * max_(net_income, 0)) is_head = person("is_tax_unit_head", period) return ~is_dependent * net_income + is_head * sum_dep_net_income diff --git a/policyengine_us/variables/gov/states/ar/tax/income/ar_net_taxable_income_joint.py b/policyengine_us/variables/gov/states/ar/tax/income/ar_net_taxable_income_joint.py index 2993400bd3a..c02add92281 100644 --- a/policyengine_us/variables/gov/states/ar/tax/income/ar_net_taxable_income_joint.py +++ b/policyengine_us/variables/gov/states/ar/tax/income/ar_net_taxable_income_joint.py @@ -22,7 +22,9 @@ def formula(person, period, parameters): # is built in, so use AGI instead of taxable income. agi = person("ar_agi_joint", period) is_head = person("is_tax_unit_head", period) - total_agi = is_head * person.tax_unit.sum(agi) + # A spouse's loss can make the joint total negative; the tax base + # cannot be. + total_agi = is_head * max_(person.tax_unit.sum(agi), 0) return where( uses_low_income_tax_tables, total_agi, diff --git a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.py b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.py index 3224ce6f093..5116e6cfe8b 100644 --- a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.py +++ b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.py @@ -26,5 +26,7 @@ def formula(tax_unit, period, parameters): # casualty and the per-loss exclusion applies once. loss = add(tax_unit, period, ["casualty_loss"]) loss_after_exclusion = max_(0, loss - p.exclusion) - agi = add(tax_unit, period, ["ar_agi_joint"]) + # A spouse's loss can make the joint AGI total negative; floor it at + # zero so a negative AGI cannot enlarge the deduction. + agi = max_(add(tax_unit, period, ["ar_agi_joint"]), 0) return max_(0, loss_after_exclusion - p.income_floor * agi) diff --git a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.py b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.py index 06be959a004..3057595a610 100644 --- a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.py +++ b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.py @@ -11,7 +11,9 @@ class ar_medical_expense_deduction_joint(Variable): defined_for = StateCode.AR def formula(tax_unit, period, parameters): - agi = add(tax_unit, period, ["ar_agi_joint"]) + # A spouse's loss can make the joint AGI total negative; floor it at + # zero so a negative AGI cannot enlarge the deduction. + agi = max_(add(tax_unit, period, ["ar_agi_joint"]), 0) floor = tax_unit("ar_medical_expense_deduction_floor", period) medical_expenses = tax_unit("itemized_medical_expenses", period) return max_(0, medical_expenses - floor * agi) diff --git a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_misc_deduction_joint.py b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_misc_deduction_joint.py index a1ef9f0e8bf..95a4f17395c 100644 --- a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_misc_deduction_joint.py +++ b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_misc_deduction_joint.py @@ -21,5 +21,7 @@ def formula(tax_unit, period, parameters): # itemized deductions, so start from the expenses, not misc_deduction. p = parameters(period).gov.states.ar.tax.income.deductions.itemized.misc expenses = tax_unit("total_misc_deductions", period) - agi = add(tax_unit, period, ["ar_agi_joint"]) + # A spouse's loss can make the joint AGI total negative; floor it at + # zero so a negative AGI cannot enlarge the deduction. + agi = max_(add(tax_unit, period, ["ar_agi_joint"]), 0) return max_(0, expenses - p.income_floor * agi) diff --git a/policyengine_us/variables/gov/states/ar/tax/income/low_income/ar_low_income_tax_joint.py b/policyengine_us/variables/gov/states/ar/tax/income/low_income/ar_low_income_tax_joint.py index 0dad1967ab0..c2b175bdd91 100644 --- a/policyengine_us/variables/gov/states/ar/tax/income/low_income/ar_low_income_tax_joint.py +++ b/policyengine_us/variables/gov/states/ar/tax/income/low_income/ar_low_income_tax_joint.py @@ -11,7 +11,9 @@ class ar_low_income_tax_joint(Variable): defined_for = StateCode.AR def formula(person, period, parameters): - agi = add(person.tax_unit, period, ["ar_agi_joint"]) + # A spouse's loss can make the joint total negative; the tax base + # cannot be. + agi = max_(add(person.tax_unit, period, ["ar_agi_joint"]), 0) head = person("is_tax_unit_head", period) agi_attributed_to_head = agi * head p = parameters(period).gov.states.ar.tax.income.rates.low_income_tax_tables diff --git a/policyengine_us/variables/gov/states/mt/tax/income/base/mt_agi_joint.py b/policyengine_us/variables/gov/states/mt/tax/income/base/mt_agi_joint.py index 56cdef43d71..3a081d76218 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/base/mt_agi_joint.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/base/mt_agi_joint.py @@ -14,12 +14,15 @@ def formula(tax_unit, period, parameters): # Pool federal AGI at tax unit level agi = add(tax_unit, period, ["adjusted_gross_income_person"]) - # Pool Montana additions at tax unit level - additions = add(tax_unit, period, ["mt_additions"]) - - # Pool Montana subtractions at tax unit level - # This allows spouse's subtractions to offset head's income - subtractions = add(tax_unit, period, ["mt_subtractions"]) + # Pool Montana additions and subtractions over the head and spouse. + # This allows the spouse's subtractions to offset the head's income. + # A dependent's income is not on the return (adjusted_gross_income_person + # is zero for dependents), so neither are the dependent's Montana + # additions and subtractions. + person = tax_unit.members + on_return = person("is_tax_unit_head_or_spouse", period) + additions = tax_unit.sum(person("mt_additions", period) * on_return) + subtractions = tax_unit.sum(person("mt_subtractions", period) * on_return) # Apply pooled subtractions to pooled income reduced_agi = max_(agi + additions - subtractions, 0) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/capital_gain/mt_capital_gain_credit.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/capital_gain/mt_capital_gain_credit.py index 8226eaf09cb..03982ead3d3 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/capital_gain/mt_capital_gain_credit.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/capital_gain/mt_capital_gain_credit.py @@ -13,6 +13,7 @@ class mt_capital_gain_credit(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.mt.tax.income.credits.capital_gain - net_capital_gain = person("capital_gains", period) - # The net capital gain variable is capped at 0 + # The credit is 2% of net capital gains (Form 2 instructions, Line 1), + # so a net capital loss produces no credit rather than a negative one. + net_capital_gain = max_(person("capital_gains", period), 0) return p.percentage * net_capital_gain diff --git a/policyengine_us/variables/gov/states/mt/tax/income/exemptions/dependent/mt_dependent_exemptions_person.py b/policyengine_us/variables/gov/states/mt/tax/income/exemptions/dependent/mt_dependent_exemptions_person.py index ae6696424d4..4da963d92c3 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/exemptions/dependent/mt_dependent_exemptions_person.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/exemptions/dependent/mt_dependent_exemptions_person.py @@ -7,19 +7,46 @@ class mt_dependent_exemptions_person(Variable): label = "Montana dependent exemption for each dependent" unit = USD definition_period = YEAR - reference = "https://regulations.justia.com/states/montana/department-42/chapter-42-15/subchapter-42-15-4/rule-42-15-403/" + reference = ( + # MCA 15-30-2114(5)(a) (2021): the dependent exemption. + "http://web.archive.org/web/20220818141612/https://leg.mt.gov/bills/mca/title_0150/chapter_0300/part_0210/section_0140/0150-0300-0210-0140.html", + # MCA 15-30-2101(10) (2021): the definition of gross income. + "http://web.archive.org/web/20220127192023/http://leg.mt.gov/bills/mca/title_0150/chapter_0300/part_0210/section_0010/0150-0300-0210-0010.html", + "https://regulations.justia.com/states/montana/department-42/chapter-42-15/subchapter-42-15-4/rule-42-15-403/", + # Form 2 instructions, dependents: 2021 ($2,580), 2022 ($2,710) and + # 2023 ($2,960). + "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2021_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=13", + "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=14", + "https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2023_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=16", + ) defined_for = StateCode.MT def formula(person, period, parameters): p = parameters(period).gov.states.mt.tax.income.exemptions if p.applies: - # Qualifying child under IRC 152(c), which defines for the EITC - qualifying_child = person("is_qualifying_child_dependent", period) - # Disabled dependents get an additional exemption. + # A qualifying child under IRC 152(c) is a dependent regardless of + # income. Any other dependent counts only if their gross income + # does not exceed the exemption amount (Form 2 instructions: a + # dependent is an individual "who does not have gross income of + # more than" the exemption amount "unless the dependent is a + # 'qualifying child' according to the federal rules"). + dependent = person("is_tax_unit_dependent", period) + # A permanently and totally disabled child is a qualifying child + # at any age (IRC 152(c)(3)(B)), as in + # is_qualifying_relative_dependent. + qualifying_child = person("is_qualifying_child_dependent", period) | ( + dependent & person("is_permanently_and_totally_disabled", period) + ) + # MCA 15-30-2114(5)(a) tests the dependent's own gross income as + # defined in MCA 15-30-2101(10): federal gross income excluding + # unemployment compensation, with only taxable Social Security. + gross_income = person("mt_dependent_gross_income", period) + other_dependent = dependent & ~qualifying_child & (gross_income <= p.amount) + # Disabled children get an additional exemption. disabled = person("is_disabled", period) - eligible_dependent = qualifying_child * (1 + disabled) + eligible_dependent = qualifying_child * (1 + disabled) + other_dependent return eligible_dependent * p.amount return 0 diff --git a/policyengine_us/variables/gov/states/mt/tax/income/exemptions/dependent/mt_dependent_gross_income.py b/policyengine_us/variables/gov/states/mt/tax/income/exemptions/dependent/mt_dependent_gross_income.py new file mode 100644 index 00000000000..953cc44c33d --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/exemptions/dependent/mt_dependent_gross_income.py @@ -0,0 +1,43 @@ +from policyengine_us.model_api import * + + +class mt_dependent_gross_income(Variable): + value_type = float + entity = Person + label = "Montana gross income of a dependent for the dependent exemption" + unit = USD + documentation = """ + Montana gross income (MCA 15-30-2101(10)) is federal gross income under + IRC 61, excluding unemployment compensation. This starts from the federal + dependent_gross_income, which counts gains but not losses and only the + IRC 86 taxable part of Social Security (figured on the dependent's own + modified AGI, which includes unemployment compensation), and removes the + dependent's unemployment compensation. + """ + definition_period = YEAR + reference = ( + # MCA 15-30-2101(10) (2021): gross income is IRC 61 gross income + # excluding unemployment compensation. + "http://web.archive.org/web/20220127192023/http://leg.mt.gov/bills/mca/title_0150/chapter_0300/part_0210/section_0010/0150-0300-0210-0010.html", + # MCA 15-30-2114(5)(a) (2021): the dependent gross income test. + "http://web.archive.org/web/20220818141612/https://leg.mt.gov/bills/mca/title_0150/chapter_0300/part_0210/section_0140/0150-0300-0210-0140.html", + # ARM 42.15.403 restates the test; its subsection numbers are not + # verified because the rule text was not machine-readable. + "https://rules.mt.gov/gateway/ruleno.asp?RN=42.15.403", + # 2022 Form 2 instructions: "federal gross income, excluding + # unemployment compensation". + "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=7", + ) + defined_for = StateCode.MT + + def formula(person, period, parameters): + federal_gross_income = person("dependent_gross_income", period) + # dependent_gross_income counts a dependent's unemployment + # compensation in full whenever it is a federal gross income source. + sources = parameters(period).gov.irs.gross_income.sources + unemployment_compensation_counted = ( + "taxable_unemployment_compensation" in sources + ) * max_(0, person("unemployment_compensation", period)) + # dependent_gross_income is zero for the head and spouse. + is_dependent = ~person("is_tax_unit_head_or_spouse", period) + return federal_gross_income - is_dependent * unemployment_compensation_counted diff --git a/policyengine_us/variables/gov/states/nm/tax/income/deductions/nm_net_capital_gains_deduction.py b/policyengine_us/variables/gov/states/nm/tax/income/deductions/nm_net_capital_gains_deduction.py index ec018ac189e..7a67fc05a63 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/deductions/nm_net_capital_gains_deduction.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/deductions/nm_net_capital_gains_deduction.py @@ -7,16 +7,43 @@ class nm_net_capital_gains_deduction(Variable): label = "New Mexico net capital gain deduction" unit = USD definition_period = YEAR - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503882/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgAcwgEwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503882/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgAcwgEwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA", + # 2019 HB6, section 14: NMSA 7-2-34(D) adopts IRC 1222(11). + "https://www.nmlegis.gov/Sessions/19%20Regular/final/HB0006.pdf#page=41", + # 2019 HB6, section 59(A): section 14 applies from tax year 2019. + "https://www.nmlegis.gov/Sessions/19%20Regular/final/HB0006.pdf#page=105", + # 2024 HB252, section 8: from 2025 (section 42(B)) the same definition + # is in NMSA 7-2-34(C). + "https://www.nmlegis.gov/Sessions/24%20Regular/final/HB0252.pdf#page=30", + "https://www.law.cornell.edu/uscode/text/26/1222#11", + # Capital gain distributions are long-term capital gains. + "https://www.law.cornell.edu/uscode/text/26/852#b_3_B", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): p = parameters(period).gov.states.nm.tax.income.deductions.net_capital_gains - net_capital_gains = max_(0, add(tax_unit, period, ["capital_gains"])) + # Capital gain distributions reported without Schedule D are + # long-term capital gains under IRC 852(b)(3)(B). + long_term_gain = add( + tax_unit, period, ["long_term_capital_gains", "non_sch_d_capital_gains"] + ) + short_term_gain = add(tax_unit, period, ["short_term_capital_gains"]) + # NMSA 7-2-34 defines "net capital gain" by IRC Section 1222(11): net + # long-term capital gain less any net short-term capital loss, so + # short-term gains are excluded. The definition is in subsection (D) + # for 2019 through 2024 (2019 HB6, sections 14 and 59(A)) and in + # subsection (C) from 2025 (2024 HB252, sections 8 and 42(B)). + net_short_term_loss = max_(0, -short_term_gain) + net_capital_gains = max_(0, long_term_gain - net_short_term_loss) uncapped_element = p.uncapped_element_percent * net_capital_gains filing_status = tax_unit("filing_status", period) separate = filing_status == filing_status.possible_values.SEPARATE - # Halve the deduction if filing separately. + # Halve the deduction if filing separately. Limitation: the law + # (2019 HB6, section 14(B)) halves the deduction allowed on the joint + # return, which requires the couple's combined gains; each separate + # unit here uses only its own gains. denominator = where(separate, 2, 1) capped_element = p.capped_element.calc(net_capital_gains) numerator = max_(uncapped_element, capped_element)