diff --git a/changelog.d/statute-bugs-mt-disability-ehrc-elderly.fixed.md b/changelog.d/statute-bugs-mt-disability-ehrc-elderly.fixed.md new file mode 100644 index 00000000000..beaedfdedcd --- /dev/null +++ b/changelog.d/statute-bugs-mt-disability-ehrc-elderly.fixed.md @@ -0,0 +1 @@ +End Montana's disability income exclusion with its 2024 repeal, count only the federal refundable credits a household actually received in the elderly homeowner/renter credit's gross household income, and require that credit's claimant to meet the six-month owner, renter or lessee occupancy and nine-month residence tests (MCA 15-30-2338(1)(b)-(c)). diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/minimum_occupancy_months.yaml b/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/minimum_occupancy_months.yaml new file mode 100644 index 00000000000..803a15294f8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/minimum_occupancy_months.yaml @@ -0,0 +1,14 @@ +description: Montana requires a claimant of the elderly homeowner or renter credit to occupy one or more Montana dwellings as an owner, renter, or lessee for at least this many months of the claim period. +values: + 2009-01-01: 6 +metadata: + unit: month + period: year + label: Montana elderly homeowner or renter credit minimum qualifying occupancy months + reference: + - title: MCA 15-30-2338(1)(c) + href: https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0380/0150-0300-0230-0380.html + - title: MCA 15-30-2338(1)(c) (2009) + href: https://mca.legmt.gov/bills/2009/mca/15/30/15-30-2338.htm + - title: 2025 Montana Form 2 instructions, Elderly Homeowner/Renter Credit, "You occupied a Montana residence as a renter, owner, or lessee for at least six months during the tax year" + href: https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2025_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=44 diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/minimum_residency_months.yaml b/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/minimum_residency_months.yaml new file mode 100644 index 00000000000..436e8e7e89d --- /dev/null +++ b/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/minimum_residency_months.yaml @@ -0,0 +1,14 @@ +description: Montana requires a claimant of the elderly homeowner or renter credit to reside in Montana for at least this many months of the claim period. +values: + 2009-01-01: 9 +metadata: + unit: month + period: year + label: Montana elderly homeowner or renter credit minimum residency months + reference: + - title: MCA 15-30-2338(1)(b) + href: https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0380/0150-0300-0230-0380.html + - title: MCA 15-30-2338(1)(b) (2009) + href: https://mca.legmt.gov/bills/2009/mca/15/30/15-30-2338.htm + - title: 2025 Montana Form 2 instructions, Elderly Homeowner/Renter Credit, "You lived in Montana for at least nine months during the tax year" + href: https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2025_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=44 diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/subtractions/subtractions.yaml b/policyengine_us/parameters/gov/states/mt/tax/income/subtractions/subtractions.yaml index b65aa2ced80..1d9453d6d31 100644 --- a/policyengine_us/parameters/gov/states/mt/tax/income/subtractions/subtractions.yaml +++ b/policyengine_us/parameters/gov/states/mt/tax/income/subtractions/subtractions.yaml @@ -19,7 +19,9 @@ values: - mt_interest_exemption_person - mt_tuition_subtraction_person - mt_old_age_subtraction - - mt_disability_income_exclusion_person + # 2021 Mont. Laws ch. 503 (SB 399) section 65 repealed 15-30-2110, MCA, + # and with it the disability income exclusion, for tax years beginning + # after December 31, 2023 (section 70(1)). - salt_refund_income # MCA 15-30-2120 / Form 2 Subtractions Schedule 2025-01-01: # Section 15-30-2120 starts from federal taxable income, so federal @@ -29,7 +31,6 @@ values: - mt_interest_exemption_person - mt_tuition_subtraction_person - mt_old_age_subtraction - - mt_disability_income_exclusion_person # TODO: Remove this subtraction starting in 2029 because the federal # Schedule 1-A deductions expire after 2028. - mt_federal_obbba_subtraction @@ -49,3 +50,7 @@ metadata: href: https://leg.mt.gov/bills/mca/title_0150/chapter_0300/part_0210/section_0100/0150-0300-0210-0100.html - title: 2025 Montana Form 2 Instructions href: https://revenuefiles.mt.gov/files/Forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2025_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=21 + - title: "2021 Montana Session Laws, chapter 503 (SB 399), section 65 (repealer) and section 70 (effective dates) #page 68,70" + href: https://archive.legmt.gov/content/Publications/sales/2021SessionLaws_V3_ERRATA-VERSION.pdf#page=68 + - title: 2024 Montana Form 2 instructions, repealed deductions + 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=5 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 a9f54d8324d..c11b75bca95 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 @@ -216,6 +216,8 @@ age: 63 employment_income: 20_892.60 real_estate_taxes: 863.08 + # The third Economic Impact Payment, received during 2021. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 1_400 tax_units: tax_unit: members: [person1] @@ -227,13 +229,14 @@ # (863.08 - (gross_hh - 6,300) x 0.05) x 1.0, capped at $1,000. # 2021 instructions, line 7: "Refundable credits include the federal and # Montana Earned Income Tax Credit, the federal Child Tax Credits, - # Economic Impact Payments". Federal EITC (ARPA, no qualifying child) - # 1_502 - 15.3% x (20_892.60 - 11_610) = 81.76; Montana EITC 3% = 2.45; - # Economic Impact Payment 1_400. Line 10 = 20_892.60 + 1_484.21 = - # 22_376.81; line 12 = 16_076.81; line 14 = 803.84; line 19 = 863.08 - - # 803.84 = 59.24. The earlier expected value, 133.33, counted only the - # Montana EITC. - mt_elderly_homeowner_or_renter_credit: 59.24 + # Economic Impact Payments". Received in 2021: the 1_400 Economic Impact + # Payment. The 2021 federal EITC (ARPA, no qualifying child), 1_502 - + # 15.3% x (20_892.60 - 11_610) = 81.76, is paid in 2022, so it is not; + # the Montana EITC on the 2021 return, 3% = 2.45, counts as the model's + # Montana refundable credits. Line 10 = 20_892.60 + 1_400 + 2.45 = + # 22_295.05; line 12 = 15_995.05; line 14 = 799.75; line 19 = 863.08 - + # 799.75 = 63.33. + mt_elderly_homeowner_or_renter_credit: 63.33 - name: MT EHRC uses the $12,600 exclusion from 2022 (HB 191) period: 2022 @@ -937,6 +940,8 @@ person2: age: 40 employment_income: 10_000 + # Federal EITC refund received during 2024. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 632 tax_units: tax_unit1: members: [person1] @@ -949,9 +954,9 @@ output: # The claimant's adult son lives in the household and files his own # return. Line 5 pensions 20_000. Line 8, refundable credits received by - # all household members: his federal EITC 632 (Rev. Proc. 2023-34, no - # qualifying child, wages between 8_260 and 10_330) and Montana EITC - # 10% x 632 = 63.20, 695.20 in all. Line 17 his wages 10_000. Line 18 + # all household members: the 632 federal EITC refund he received in 2024 + # and Montana EITC 10% x 632 = 63.20 (Rev. Proc. 2023-34, no qualifying + # child, wages between 8_260 and 10_330), 695.20 in all. Line 17 his wages 10_000. Line 18 # gross household income 30_695.20; line 20 = 30_695.20 - 12_600 = # 18_095.20; line 21 = 0.05; line 22 = 904.76; line 27 = 2_000 - 904.76 # = 1_095.24; line 28 = 1_095.24 (under 1_150); line 29 = 100%; line 30 = @@ -971,6 +976,8 @@ person2: age: 30 employment_income: 10_000 + # Federal EITC and refundable CTC received during 2024. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 4_525 person3: age: 5 tax_units: @@ -984,8 +991,9 @@ state_name: MT output: # The claimant's daughter and grandchild live in the household; the - # daughter files her own return. Line 8: federal EITC 34% x 10_000 = - # 3_400, refundable part of the federal child tax credit + # daughter files her own return. Line 8, received during 2024: federal + # EITC 34% x 10_000 = 3_400, refundable part of the federal child tax + # credit # min(1_700, 15% x (10_000 - 2_500)) = 1_125, Montana EITC 340; 4_865 in # all. Line 17 her wages 10_000. Line 18 = 20_000 + 4_865 + 10_000 = # 34_865; line 20 = 22_265; line 22 = 22_265 x 0.05 = 1_113.25; line 27 = @@ -1007,6 +1015,8 @@ person2: age: 30 employment_income: 12_000 + # Federal EITC and refundable CTC received during 2024. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 5_505 person3: age: 5 tax_units: @@ -1019,7 +1029,7 @@ members: [person1, person2, person3] state_name: MT output: - # Line 8: federal EITC 34% x 12_000 = 4_080 (under the 12_390 earned + # Line 8, received during 2024: federal EITC 34% x 12_000 = 4_080 (under the 12_390 earned # income amount), refundable child tax credit # min(1_700, 15% x 9_500) = 1_425, Montana EITC 408; 5_913 in all. # Line 18 = 20_000 + 5_913 + 12_000 = 37_913; line 20 = 25_313; @@ -1075,6 +1085,8 @@ person2: age: 40 employment_income: 10_000 + # Federal EITC refund received during 2023. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 584.70 tax_units: tax_unit1: members: [person1] @@ -1109,26 +1121,26 @@ rent: 4_800 mt_elderly_homeowner_or_renter_credit_received: 60 mt_elderly_homeowner_or_renter_credit_property_tax_rebate_received: 20 + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 500 person2: age: 70 taxable_pension_income: 15_000 rent: 7_200 mt_elderly_homeowner_or_renter_credit_received: 40 mt_elderly_homeowner_or_renter_credit_property_tax_rebate_received: 80 + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 300 tax_units: tax_unit1: members: [person1] - income_tax_refundable_credits: 500 tax_unit2: members: [person2] - income_tax_refundable_credits: 300 households: household: members: [person1, person2] state_code: MT output: - # Schedule 2EC line 8 counts each return's federal refundable credits - # once, plus actual elderly-credit and rebate receipts. Person amounts: + # Schedule 2EC line 8 counts the federal refundable credits each person + # received, plus actual elderly-credit and rebate receipts. Person amounts: # 10_000 + 500 + 60 + 20 = 10_580; 15_000 + 300 + 40 + 80 = 15_420. # Line 18 = 26_000; line 22 = (26_000 - 12_600) * .05 = 670. # Line 25 rent equivalents = [4_800, 7_200] * .15 = [720, 1_080]. @@ -1297,7 +1309,7 @@ # Line 18 = 20_000 + 10_000 = 30_000; line 22 = 870; line 30 = 1_130. mt_elderly_homeowner_or_renter_credit: [1_130, 0] -- name: 2024 Schedule 2EC, a parent living in an adult child's home claims the child's property tax as rent +- name: 2024 Schedule 2EC, a parent without owner, renter or lessee status in an adult child's home cannot claim period: 2024 absolute_error_margin: 0.01 input: @@ -1327,6 +1339,51 @@ household: members: [person1, person2] state_name: MT + output: + # MCA 15-30-2338(1)(c): a claimant "must have occupied one or more + # dwellings in Montana as an owner, renter, or lessee for at least 6 + # months". The parent pays no rent and is billed no property tax, and + # the child's bill does not establish the parent's status. ARM + # 42.4.302(2)(b) lets only an eligible claimant use another's bill as + # rent. The child is 45 (§ 15-30-2338(1)(a)). Neither may claim; before + # this test the parent's credit was 341. + mt_elderly_homeowner_or_renter_credit_eligible: [false, false] + mt_elderly_homeowner_or_renter_credit: [0, 0] + mt_refundable_credits: [0, 0] + +- name: 2024 Schedule 2EC, a parent who leases an adult child's home rent-free claims the child's property tax as rent + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 14_000 + rent: 0 + ssi: 0 + # A documented lessee for the whole year. + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 + person2: + age: 45 + taxable_interest_income: 6_000 + rent: 0 + real_estate_taxes: 4_000 + ssi: 0 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_name: MT output: # The home is in the child's name. "If the property occupied by you is # in a name other than your own, the property taxes billed for that @@ -1336,8 +1393,7 @@ # line 21 = 0.035; line 22 = 259. # Parent: line 23 = 0; line 24 = 4_000 (the child's bill, as rent); # line 25 = 600; line 26 = 600; line 27 = 600 - 259 = 341; line 28 = - # 341; line 29 = 100% (under 35_000); line 30 = 341. Before this rule - # the parent's line 24 was 0 and the credit 0. + # 341; line 29 = 100% (under 35_000); line 30 = 341. # The child is 45, so not a claimant (§ 15-30-2338(1)(a)). mt_elderly_homeowner_or_renter_credit_net_household_income: [259, 0] mt_elderly_homeowner_or_renter_credit_gross_rent: [4_000, 0] @@ -1453,12 +1509,15 @@ output: # SSI is pinned at 0 to isolate the credit's arithmetic. Line 18 = # 20_000; line 20 = 7_400; line 21 = 0.035; line 22 = 259. - # person1 (home in person2's name): line 24 = 2_000; line 25 = 300; - # line 27 = 300 - 259 = 41. + # person1 pays no rent and is billed nothing, so nothing shows that they + # occupy the home as an owner, renter or lessee (MCA 15-30-2338(1)(c)): + # not eligible. As a lessee they would have line 24 = 2_000, line 25 = + # 300 and line 27 = 300 - 259 = 41. # person2: line 23 = 2_000; line 27 = 2_000 - 259 = 1_741; line 28 = # 1_150 cap. # One claimant per household (§ 15-30-2341(1)): person2 claims 1_150. - mt_elderly_homeowner_or_renter_credit_pre_one_claimant: [41, 1_150] + mt_elderly_homeowner_or_renter_credit_eligible: [false, true] + mt_elderly_homeowner_or_renter_credit_pre_one_claimant: [0, 1_150] mt_elderly_homeowner_or_renter_credit_selected_claimant: [false, true] mt_elderly_homeowner_or_renter_credit: [0, 1_150] @@ -1585,15 +1644,20 @@ taxable_pension_income: 14_000 rent: 0 ssi: 0 + # A rent-free lessee. An input for one person gives the others the + # input default, not the formula, so record everyone's months. + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 person2: age: 45 rent: 0 ssi: 0 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 person3: age: 43 rent: 0 real_estate_taxes: 4_000 ssi: 0 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 tax_units: tax_unit1: members: [person1] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_disability_and_unemployment.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_disability_and_unemployment.yaml index 9acc7082943..2774d85213e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_disability_and_unemployment.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_disability_and_unemployment.yaml @@ -188,6 +188,8 @@ unemployment_compensation: 9_000 real_estate_taxes: 1_500 ssi: 0 + # Economic Impact Payments received during 2020. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 1_800 tax_units: tax_unit: members: [person1] @@ -198,7 +200,8 @@ output: # IRC 85(c) excludes the 9_000 from 2020 federal AGI (AGI without it is # 16_000, under 150_000). Line 1 federal AGI 16_000; line 7 refundable - # credits received, the 2020 recovery rebate credit 1_200 + 600 = 1_800; + # credits received, the 2020 Economic Impact Payments 1_200 + 600 = + # 1_800; # line 8 other income not listed above, the excluded 9_000; line 10 = # 26_800. adjusted_gross_income_person: 16_000 @@ -221,10 +224,13 @@ taxable_pension_income: 14_000 rent: 12_000 ssi: 0 + # Economic Impact Payments received during 2020. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 1_800 person2: age: 40 unemployment_compensation: 14_000 ssi: 0 + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 1_800 tax_units: tax_unit1: members: [person1] @@ -237,8 +243,8 @@ output: # The claimant's daughter files her own return. Of her 14_000, 10_200 is # excluded and 14_000 - 10_200 = 3_800 is in her federal AGI. Line 1 - # federal AGI 14_000 + 3_800 = 17_800; line 7 each return's 2020 - # recovery rebate credit, 1_800 + 1_800 = 3_600; line 8 her excluded + # federal AGI 14_000 + 3_800 = 17_800; line 7 the 2020 Economic Impact + # Payments each received, 1_800 + 1_800 = 3_600; line 8 her excluded # 10_200; line 10 = 31_600. adjusted_gross_income_person: [14_000, 3_800] mt_elderly_homeowner_or_renter_credit_gross_household_income: [15_800, 15_800] @@ -260,6 +266,8 @@ taxable_pension_income: 15_000 real_estate_taxes: 1_400 ssi: 0 + # Economic Impact Payments received during 2020. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 1_800 person2: age: 20 is_full_time_student: true @@ -277,7 +285,7 @@ # The claimant's grandson, a student, is her dependent. All of his 4_000 # is excluded from federal AGI, and his own gross income counts it in # full, so nothing more is added for it. Line 1 federal AGI 15_000; line - # 7 the recovery rebate credit 1_800; line 8 his 4_000; line 10 = 20_800. + # 7 the Economic Impact Payments received, 1_800; line 8 his 4_000; line 10 = 20_800. mt_elderly_homeowner_or_renter_credit_unemployment_compensation_addback: [0, 0] mt_elderly_homeowner_or_renter_credit_gross_household_income: [16_800, 4_000] # Line 12 = 14_500; line 13 = 0.05; line 14 = 725. @@ -296,6 +304,8 @@ unemployment_compensation: 9_000 real_estate_taxes: 1_500 ssi: 0 + # Economic Impact Payment received during 2021. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 1_400 tax_units: tax_unit: members: [person1] @@ -305,7 +315,7 @@ state_name: MT output: # No exclusion in 2021. Line 1 federal AGI 25_000; line 7 the 2021 - # recovery rebate credit 1_400; line 10 = 26_400. + # Economic Impact Payment received, 1_400; line 10 = 26_400. mt_elderly_homeowner_or_renter_credit_unemployment_compensation_addback: 0 mt_elderly_homeowner_or_renter_credit_gross_household_income: 26_400 # Line 12 = 20_100; line 13 = 0.05; line 14 = 1_005. diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_eligible.yaml index 97841644257..4151ced40fc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_eligible.yaml @@ -1,32 +1,197 @@ - name: Ineligible -age period: 2022 input: - greater_age_head_spouse: 60 + age: 60 + rent: 6_000 state_code: MT output: mt_elderly_homeowner_or_renter_credit_eligible: false -- name: Eligible +- name: Eligible renter period: 2022 input: - greater_age_head_spouse: 63 + age: 63 + rent: 6_000 state_code: MT output: + # Rent paid shows the filer occupies the home as a renter; a Montana + # household is a full-year resident. + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 + mt_elderly_homeowner_or_renter_credit_mt_residency_months: 12 mt_elderly_homeowner_or_renter_credit_eligible: true -- name: If one person is old enough, everybody is eligible +- name: Eligible owner billed property tax period: 2022 + input: + age: 63 + real_estate_taxes: 2_000 + state_code: MT + output: + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 + mt_elderly_homeowner_or_renter_credit_eligible: true + +- name: If one spouse qualifies, every member of the return is eligible + period: 2022 + input: + people: + person1: + age: 60 + rent: 6_000 + person2: + age: 70 + person3: + age: 10 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # The joint return's rent is "the rent that you paid" (Schedule 2EC line + # 24), so both spouses rent the home; only one must meet the age + # requirement (2025 instructions, PDF page 44). + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: [12, 12, 0] + mt_elderly_homeowner_or_renter_credit_eligible: [true, true, true] + +- name: A parent without owner, renter or lessee status cannot qualify through another member's bill + period: 2024 + input: + people: + parent: + age: 80 + rent: 0 + child: + age: 45 + rent: 0 + real_estate_taxes: 4_000 + tax_units: + parent_return: + members: [parent] + child_return: + members: [child] + households: + home: + members: [parent, child] + state_code: MT + output: + # MCA 15-30-2338(1)(c): the claimant "must have occupied one or more + # dwellings in Montana as an owner, renter, or lessee for at least 6 + # months". The parent pays no rent and is billed no property tax, so + # nothing shows that status; the child's bill does not establish it. + # The child owns the home but is 45 (§ 15-30-2338(1)(a)). + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: [0, 12] + mt_elderly_homeowner_or_renter_credit_eligible: [false, false] + +- name: A parent with documented lessee status in a child's home qualifies + period: 2024 + input: + people: + parent: + age: 80 + rent: 0 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 + child: + age: 45 + rent: 0 + real_estate_taxes: 4_000 + # An input for one person gives the others the input default, not + # the formula, so record everyone's months. + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 + tax_units: + parent_return: + members: [parent] + child_return: + members: [child] + households: + home: + members: [parent, child] + state_code: MT + output: + # Zero cash rent does not by itself rule out lessee status; an input + # that records it establishes the occupancy test. + mt_elderly_homeowner_or_renter_credit_eligible: [true, false] + +- name: A renter meeting both month thresholds exactly is eligible + period: 2024 + input: + age: 80 + rent: 6_000 + state_code: MT + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 6 + mt_elderly_homeowner_or_renter_credit_mt_residency_months: 9 + output: + # § 15-30-2338(1)(b)-(c): at least 9 months of residence and at least + # 6 months of occupancy as an owner, renter or lessee. + mt_elderly_homeowner_or_renter_credit_eligible: true + +- name: Five months of qualifying occupancy fails + period: 2024 + input: + age: 80 + rent: 6_000 + state_code: MT + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 5 + mt_elderly_homeowner_or_renter_credit_mt_residency_months: 12 + output: + mt_elderly_homeowner_or_renter_credit_eligible: false + +- name: Eight months of Montana residence fails + period: 2024 + input: + age: 80 + rent: 6_000 + state_code: MT + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 + mt_elderly_homeowner_or_renter_credit_mt_residency_months: 8 + output: + mt_elderly_homeowner_or_renter_credit_eligible: false + +- name: The occupancy test applies from 2009 + period: 2009 + input: + people: + parent: + age: 80 + rent: 0 + child: + age: 45 + rent: 0 + real_estate_taxes: 4_000 + tax_units: + parent_return: + members: [parent] + child_return: + members: [child] + households: + home: + members: [parent, child] + state_code: MT + output: + # MCA 15-30-2338(1)(c) (2009) is unchanged since its 2009 recodification. + mt_elderly_homeowner_or_renter_credit_eligible: [false, false] + +- name: The tests must be met by the same spouse + period: 2024 input: people: - person1: {} - person2: {} + person1: + age: 60 + rent: 6_000 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 + person2: + age: 70 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 0 tax_units: tax_unit: members: [person1, person2] - greater_age_head_spouse: 70 households: household: members: [person1, person2] state_code: MT output: - mt_elderly_homeowner_or_renter_credit_eligible: [true, true] + # § 15-30-2338(1) requires "an individual" to meet the age, residence + # and occupancy tests. The renter is 60; the 70-year-old spouse is + # recorded as not renting, owning or leasing the home. + mt_elderly_homeowner_or_renter_credit_eligible: [false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.yaml index 5f2f32ff9fe..abf0b202d75 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.yaml @@ -1,4 +1,4 @@ -- name: Case 1, a single parent's federal EITC and refundable CTC are counted once, on the head. +- name: Case 1, a federal EITC and refundable CTC claimed on this year's return are not received this year. period: 2024 absolute_error_margin: 0.01 input: @@ -16,49 +16,71 @@ members: [person1, person2] state_code: MT output: - # Rev. Proc. 2023-34, one qualifying child: 34% x 10_000 = 3_400 (under - # the 12_390 earned income amount). Refundable CTC: no tax before credits - # (10_000 is under the standard deduction), so - # min(1_700, 15% x (10_000 - 2_500)) = 1_125. + # Rev. Proc. 2023-34, one qualifying child: 34% x 10_000 = 3_400. + # Refundable CTC: min(1_700, 15% x (10_000 - 2_500)) = 1_125. eitc: 3_400 refundable_ctc: 1_125 - # 3_400 + 1_125 = 4_525, on the head only. - mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: [4_525, 0] + # Gross household income counts "all income received" during the year + # (MCA 15-30-2337(4)); the 2023 instructions, line 7, combine "all the + # refundable credits received by the members of the household in + # 2023". This return's credits are paid after the year ends, so no + # receipt is supplied and none counts. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: [0, 0] -- name: Case 2, a joint return's federal refundable credits go to the head, not the spouse or child. +- name: Case 2, a current-return entitlement adds nothing to gross household income. period: 2024 absolute_error_margin: 0.01 input: people: person1: - age: 35 - employment_income: 15_000 - person2: - age: 33 - person3: - age: 4 + age: 70 + taxable_pension_income: 20_000 tax_units: tax_unit: - members: [person1, person2, person3] + members: [person1] + income_tax_refundable_credits: 5_000 + households: + household: + members: [person1] + state_code: MT + output: + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 0 + mt_elderly_homeowner_or_renter_credit_gross_household_income: 20_000 + +- name: Case 3, federal refundable credits received count once, on the person who received them. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + taxable_pension_income: 20_000 + person2: + age: 40 + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 632 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] households: household: - members: [person1, person2, person3] + members: [person1, person2] state_code: MT output: - # Rev. Proc. 2023-34, one child: 15_000 is above the 12_390 earned income - # amount and under the 29_640 joint phaseout threshold, so the maximum - # 4_213. Refundable CTC: min(1_700, 15% x (15_000 - 2_500) = 1_875) - # = 1_700. Total 5_913. - mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: [5_913, 0, 0] + # 2024 Schedule 2EC line 8: refundable credits received by all household + # members. The son received a 632 federal EITC refund during 2024. + mt_elderly_homeowner_or_renter_credit_gross_household_income: [20_000, 632] -- name: Case 3, the 2021 Economic Impact Payment counts with the federal EITC. +- name: Case 4, the 2021 Economic Impact Payment received in 2021 counts. period: 2021 absolute_error_margin: 0.01 input: people: person1: age: 63 - employment_income: 20_892.60 + taxable_pension_income: 20_000 + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 1_400 tax_units: tax_unit: members: [person1] @@ -69,13 +91,11 @@ output: # 2021 Elderly Homeowner/Renter Credit Schedule instructions, line 7: # "Refundable credits include the federal and Montana Earned Income Tax - # Credit, the federal Child Tax Credits, Economic Impact Payments". - # 2021 childless EITC (ARPA): 1_502 - 15.3% x (20_892.60 - 11_610) - # = 81.76. Recovery rebate credit (third-round payment): 1_400. - eitc: 81.76 - mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 1_481.76 + # Credit, the federal Child Tax Credits, Economic Impact Payments". The + # third-round payment of 1_400 was received in 2021: 20_000 + 1_400. + mt_elderly_homeowner_or_renter_credit_gross_household_income: 21_400 -- name: Case 4, zero outside Montana. +- name: Case 5, zero by default outside Montana. period: 2024 input: people: 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 63408d7c55c..158c5386cbf 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 @@ -72,10 +72,13 @@ age: 70 taxable_pension_income: 20_000 mt_refundable_credits_before_renter_credit: 0 + # Net household income is computed for eligible claimants. + mt_elderly_homeowner_or_renter_credit_eligible: true person2: age: 68 self_employment_income: -5_000 mt_refundable_credits_before_renter_credit: 0 + mt_elderly_homeowner_or_renter_credit_eligible: true tax_units: tax_unit: members: [person1, person2] @@ -202,6 +205,8 @@ person2: age: 40 employment_income: 10_000 + # Federal EITC refund received during 2024. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 632 tax_units: tax_unit1: members: [person1] @@ -214,11 +219,12 @@ output: # 2024 Schedule 2EC line 8: "Combine all the refundable credits received # by all household members in 2024. Refundable credits include the - # federal and Montana earned income tax credits". Rev. Proc. 2023-34, no - # qualifying child: 10_000 is above the 8_260 earned income amount and - # under the 10_330 phaseout threshold, so the maximum 632; the Montana - # EITC is 10% of it, 63.20. The member's 10_000 + 632 + 63.20. - mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: [0, 632] + # federal and Montana earned income tax credits". The member received a + # 632 federal EITC refund. Rev. Proc. 2023-34, no qualifying child: + # 10_000 is above the 8_260 earned income amount and under the 10_330 + # phaseout threshold, so this year's federal EITC is the maximum 632 and + # the Montana EITC is 10% of it, 63.20. The member's 10_000 + 632 + + # 63.20. mt_elderly_homeowner_or_renter_credit_gross_household_income: [20_000, 10_695.20] - name: A parent's federal EITC and refundable child tax credit count in gross household income @@ -232,6 +238,8 @@ person2: age: 30 employment_income: 10_000 + # Federal EITC and refundable CTC received during 2024. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 4_525 person3: age: 5 tax_units: @@ -331,6 +339,8 @@ age: 40 employment_income: 10_000 mt_refundable_credits_before_renter_credit: 0 + # Federal EITC refund received during 2017. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 383.01 tax_units: tax_unit: members: [person1] @@ -354,6 +364,8 @@ age: 40 employment_income: 10_000 mt_refundable_credits_before_renter_credit: 0 + # Federal EITC refund received during 2016. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 383.01 tax_units: tax_unit: members: [person1] @@ -517,6 +529,8 @@ person2: age: 35 employment_income: 25_000 + # Federal EITC and refundable CTC received during 2024. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 9_854.83 person3: age: 5 person4: diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_pre_one_claimant.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_pre_one_claimant.yaml index 98ed9ddbb9c..85cfb0be0c9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_pre_one_claimant.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_pre_one_claimant.yaml @@ -46,17 +46,22 @@ taxable_pension_income: 14_000 rent: 0 ssi: 0 + # A rent-free lessee. An input for one person gives the others the + # input default, not the formula, so record everyone's months. + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 person2: age: 72 taxable_pension_income: 4_000 rent: 0 ssi: 0 real_estate_taxes: 900 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 person3: age: 45 taxable_interest_income: 2_000 rent: 0 ssi: 0 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 0 tax_units: tax_unit1: members: [person1] @@ -79,8 +84,8 @@ # SSI is pinned at 0 to isolate the credit's arithmetic. # 2024 Schedule 2EC. Line 18 = 14_000 + 4_000 + 2_000 = 20_000; line 20 # = 7_400; line 21 = 0.035; line 22 = 259. - # person1 (home in person2's name): line 24 = 900; line 25 = 135; line - # 27 = max(135 - 259, 0) = 0. + # person1 (a lessee of a home in person2's name): line 24 = 900; line + # 25 = 135; line 27 = max(135 - 259, 0) = 0. # person2: line 23 = 900; line 27 = 900 - 259 = 641. # person3 is billed nothing either, so their line 24 is also 900, but # they are under 62 and not a claimant. @@ -97,12 +102,15 @@ taxable_pension_income: 9_000 rent: 0 ssi: 0 + # A rent-free lessee for the whole year. + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 person2: age: 60 taxable_pension_income: 3_000 rent: 0 ssi: 0 real_estate_taxes: 2_500 + mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months: 12 tax_units: tax_unit1: members: [person1] @@ -124,3 +132,41 @@ # person2 is 60, so not a claimant, though the home is in their name. mt_elderly_homeowner_or_renter_credit_pre_one_claimant: [375, 0] mt_elderly_homeowner_or_renter_credit: [375, 0] + +- name: Case 4, without owner, renter or lessee status the other member's bill gives no credit. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 64 + taxable_pension_income: 9_000 + rent: 0 + ssi: 0 + person2: + age: 60 + taxable_pension_income: 3_000 + rent: 0 + ssi: 0 + real_estate_taxes: 2_500 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_name: MT + output: + # Case 3 without the lessee input: person1 pays no rent and is billed no + # property tax, so nothing shows the occupancy MCA 15-30-2338(1)(c) + # requires, and person2's bill cannot establish it. + mt_elderly_homeowner_or_renter_credit_eligible: [false, false] + mt_elderly_homeowner_or_renter_credit_pre_one_claimant: [0, 0] + mt_elderly_homeowner_or_renter_credit: [0, 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_unemployment_compensation_addback.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_unemployment_compensation_addback.yaml index 21e4ee2e4f4..671354ab063 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_unemployment_compensation_addback.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_unemployment_compensation_addback.yaml @@ -140,6 +140,8 @@ age: 68 taxable_pension_income: 20_000 taxable_unemployment_compensation: 0 + # The couple's Economic Impact Payments received during 2020. + mt_elderly_homeowner_or_renter_credit_federal_refundable_credits: 3_600 person2: age: 64 unemployment_compensation: 8_000 @@ -167,8 +169,8 @@ adjusted_gross_income_person: [20_000, 1_200, 0] dependent_gross_income: [0, 0, 4_000] mt_elderly_homeowner_or_renter_credit_unemployment_compensation_addback: [0, 6_800, 0] - # Each person's compensation once. The head also carries the joint - # return's 2020 recovery rebate credit, 1_200 x 2 + 600 x 2 = 3_600. + # Each person's compensation once. The head also carries the couple's + # 2020 Economic Impact Payments, 1_200 x 2 + 600 x 2 = 3_600. mt_elderly_homeowner_or_renter_credit_gross_household_income: [23_600, 8_000, 4_000] - name: Case 8, a person recorded as both a dependent and the head. diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_eligible_person.yaml index 88e0ae31968..dd2af65b976 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_eligible_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_eligible_person.yaml @@ -17,3 +17,14 @@ state_code: MT output: mt_disability_income_exclusion_eligible_person: 1 + +- name: No one is eligible after the 2024 repeal + period: 2024 + input: + is_tax_unit_head: true + retired_on_total_disability: true + age: 64 + state_code: MT + output: + # 2021 Mont. Laws ch. 503, sections 65 and 70(1). + mt_disability_income_exclusion_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_person.yaml index 8dfa12b9d19..1974d9f1a20 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_person.yaml @@ -36,3 +36,52 @@ output: # 5,000 - 2,000 = 3,000, under the 5,200 cap. mt_disability_income_exclusion_person: 3_000 + +- name: Before its repeal, the exclusion is available in 2023. + period: 2023 + input: + state_code: MT + age: 60 + retired_on_total_disability: true + disability_benefits: 5_200 + output: + # min(5_200 cap, 5_200 taxable disability benefits) = 5_200. + mt_disability_income_exclusion_person: 5_200 + +- name: The exclusion ends in 2024, the first year after its repeal. + period: 2024 + input: + state_code: MT + age: 60 + retired_on_total_disability: true + disability_benefits: 5_200 + output: + # 2021 Mont. Laws ch. 503 (SB 399) section 65 repeals 15-30-2110, MCA, + # which held the exclusion, for tax years beginning after December 31, + # 2023 (section 70(1)). The 2024 Form 2 instructions list the "partial + # retirement disability deduction for taxpayers under age 65" among the + # repealed deductions. + mt_disability_income_exclusion_eligible_person: false + mt_disability_income_exclusion_person: 0 + mt_disability_income_exclusion: 0 + mt_subtractions: 0 + +- name: The repeal continues in 2025. + period: 2025 + input: + state_code: MT + age: 60 + retired_on_total_disability: true + disability_benefits: 5_200 + output: + mt_disability_income_exclusion_person: 0 + mt_subtractions: 0 + +- name: After the repeal, even an eligibility input gives no exclusion. + period: 2024 + input: + state_code: MT + disability_benefits: 15_000 + mt_disability_income_exclusion_eligible_person: true + output: + mt_disability_income_exclusion_person: 0 diff --git a/policyengine_us/tests/test_mt_elderly_credit_nontaxable_income.py b/policyengine_us/tests/test_mt_elderly_credit_nontaxable_income.py index 3090ca71bfc..7886f258162 100644 --- a/policyengine_us/tests/test_mt_elderly_credit_nontaxable_income.py +++ b/policyengine_us/tests/test_mt_elderly_credit_nontaxable_income.py @@ -28,7 +28,7 @@ 1. The household's gross household income is the pension plus every member's unemployment compensation and disability benefits, each once, plus the refundable credits the household received (read from the model; - no one has earnings, so these are the recovery rebate credits). + no one has earnings or a supplied federal receipt, so these are zero). 2. The credit equals an independent reading of the schedule (standard exclusion, Household Income Reduction Table, cap, Credit Multiplier Table), lies between zero and the cap, and is zero at 45_000 or more. @@ -319,10 +319,10 @@ def test_worked_example(results): """2020 Elderly Homeowner/Renter Credit Schedule, own_return arrangement: the claimant's pension 12_000 and unemployment compensation 6_000, all excluded from federal AGI; the other adult's 12_000 of compensation, - 1_800 of it in federal AGI; each return's recovery rebate credit 1_800. - Line 1 = 12_000 + 1_800; line 7 = 3_600; line 8 = 6_000 + 10_200; line - 10 = 33_600; line 12 = 27_300; line 14 = 1_365; line 19 = 135; line 22 = - 135 at the 100% multiplier.""" + 1_800 of it in federal AGI. No Economic Impact Payment receipt is + supplied, so line 7 = 0. Line 1 = 12_000 + 1_800; line 8 = 6_000 + + 10_200; line 10 = 30_000; line 12 = 23_700; line 14 = 1_185; line 19 = + 315; line 22 = 315 at the 100% multiplier.""" i = CASES.index( dict( arrangement="own_return", @@ -334,6 +334,6 @@ def test_worked_example(results): ) ) r = results[2020] - assert r["refundable_credits"][i] == pytest.approx(3_600, abs=TOLERANCE) - assert r["gross_household_income"][i] == pytest.approx(33_600, abs=TOLERANCE) - assert r["credit"][i] == pytest.approx(135, abs=TOLERANCE) + assert r["refundable_credits"][i] == pytest.approx(0, abs=TOLERANCE) + assert r["gross_household_income"][i] == pytest.approx(30_000, abs=TOLERANCE) + assert r["credit"][i] == pytest.approx(315, abs=TOLERANCE) diff --git a/policyengine_us/tests/test_mt_elderly_credit_one_claimant.py b/policyengine_us/tests/test_mt_elderly_credit_one_claimant.py index 782b76873c6..99de26eee3e 100644 --- a/policyengine_us/tests/test_mt_elderly_credit_one_claimant.py +++ b/policyengine_us/tests/test_mt_elderly_credit_one_claimant.py @@ -12,8 +12,12 @@ property tax is treated as living in a home in another member's name, whose property tax "can qualify as rent only" (ARM 42.4.302(2)(b)): its line 24 is the larger of the rent it paid and the property tax billed to the -household's other members. The model pays the tax unit whose credit is -largest. +household's other members. That bill does not make it eligible: its head or +spouse must have occupied the home as an owner, renter, or lessee (MCA +15-30-2338(1)(c)). By default a tax unit that pays rent or is billed property +tax meets that test and one with neither does not; a tax unit marked as a +lessee here meets it through the qualifying-occupancy input. The model pays +the tax unit whose credit is largest. A reference written here from the schedule's lines is compared with the model for random Montana households of one to three tax units (single or @@ -59,13 +63,34 @@ YEAR = 2024 TOLERANCE = 0.01 P = system.parameters(YEAR).gov.states.mt.tax.income.credits.elderly_homeowner_or_renter +OCCUPANCY = "mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months" + + +def occupies(unit): + """Whether the tax unit's head and spouse occupy the home as owners, + renters, or lessees: they pay rent, are billed property tax, or are + marked as lessees.""" + return unit.get("lessee", False) or unit["property_tax"] > 0 or unit["rent"] > 0 + + +def eligible(unit): + """MCA 15-30-2338(1)(a) and (c); every household here is a full-year + Montana resident.""" + oldest = max(adult["age"] for adult in unit["adults"]) + return oldest >= P.age_threshold and occupies(unit) def build_situation(households): """Each household is a list of tax units; each tax unit is a dict with "adults" (a list of dicts with age, pension, interest and social security) and the head's property tax and rent. Every household is built - twice: as given, and with its tax units in reverse order.""" + twice: as given, and with its tax units in reverse order. When any tax + unit is marked as a lessee, every adult's qualifying occupancy is an + input: an input for some people gives the others its default, not its + formula.""" + any_lessee = any( + unit.get("lessee", False) for units in households for unit in units + ) people, tax_units, marital_units, spm_units, families, situation_households = ( {}, {}, @@ -100,6 +125,10 @@ def build_situation(households): head = unit_members[0] people[head]["real_estate_taxes"] = {YEAR: unit["property_tax"]} people[head]["rent"] = {YEAR: unit["rent"]} + if any_lessee: + months = 12 if occupies(unit) else 0 + for person in unit_members: + people[person][OCCUPANCY] = {YEAR: months} tax_units[unit_key] = {"members": unit_members} marital_units[unit_key] = {"members": unit_members} members += unit_members @@ -137,7 +166,6 @@ def reference(units): household_property_tax = sum(unit["property_tax"] for unit in units) credits = [] for unit in units: - eligible = max(adult["age"] for adult in unit["adults"]) >= P.age_threshold # Line 24: a tax unit billed no property tax may use the property tax # billed to the household's other members as rent, in place of the # rent it paid if that is larger (ARM 42.4.302(2)(b)). @@ -147,7 +175,7 @@ def reference(units): # Lines 23-28. housing = unit["property_tax"] + rent * P.rent_equivalent_tax_rate capped = min(max(housing - net, 0), P.cap) - credits.append(eligible * capped * multiplier) + credits.append(eligible(unit) * capped * multiplier) return gross, credits @@ -198,10 +226,7 @@ def assert_properties(households): # 3. At most one payment; one selection where any tax unit is # eligible. assert (credit > tol).sum() <= 1, units - any_eligible = any( - max(adult["age"] for adult in unit["adults"]) >= P.age_threshold - for unit in units - ) + any_eligible = any(eligible(unit) for unit in units) assert selected.sum() == int(any_eligible), units # 4. Nothing or the whole credit; the selected unit gets it all. assert np.all((np.abs(credit) <= tol) | (np.abs(credit - pre) <= tol)), ( @@ -247,17 +272,22 @@ def test_worked_example(): {"adults": [adult(80, pension=14_000)], "property_tax": 0, "rent": 0}, {"adults": [adult(45, interest=6_000)], "property_tax": 4_000, "rent": 0}, ] +# The same parent holding the home as a rent-free lessee. +LESSEE_IN_CHILDS_HOME = [ + {**PARENT_IN_CHILDS_HOME[0], "lessee": True}, + PARENT_IN_CHILDS_HOME[1], +] def test_property_tax_in_another_name_worked_example(): - """2024 Schedule 2EC: a parent, 80, with a 14,000 pension lives in the - home of an adult child, 45, who has 6,000 of interest and is billed 4,000 - of property tax; each files their own return. Line 18 = 20,000; line 22 - = 7,400 x 0.035 = 259. The home is in the child's name, so its property - tax "can qualify as rent only" on the parent's schedule (ARM - 42.4.302(2)(b)): line 24 = 4,000, line 25 = 600, line 27 = 341. The child - is under 62 and cannot claim.""" - households = [PARENT_IN_CHILDS_HOME] + """2024 Schedule 2EC: a parent, 80, with a 14,000 pension lives rent-free + as a lessee in the home of an adult child, 45, who has 6,000 of interest + and is billed 4,000 of property tax; each files their own return. Line + 18 = 20,000; line 22 = 7,400 x 0.035 = 259. The home is in the child's + name, so its property tax "can qualify as rent only" on the parent's + schedule (ARM 42.4.302(2)(b)): line 24 = 4,000, line 25 = 600, line 27 = + 341. The child is under 62 and cannot claim.""" + households = [LESSEE_IN_CHILDS_HOME] result = calculate(households) assert result["pre_one_claimant"] == pytest.approx([341, 0, 0, 341], abs=TOLERANCE) assert result["selected"].tolist() == [True, False, False, True] @@ -265,6 +295,19 @@ def test_property_tax_in_another_name_worked_example(): assert_properties(households) +def test_another_members_bill_does_not_establish_occupancy(): + """The same parent without owner, renter, or lessee status: no rent paid + and no property tax billed, so nothing shows the six months of + qualifying occupancy MCA 15-30-2338(1)(c) requires, and the child's bill + cannot. Neither tax unit is eligible, so no one is selected or paid.""" + households = [PARENT_IN_CHILDS_HOME] + result = calculate(households) + assert result["pre_one_claimant"] == pytest.approx([0, 0, 0, 0], abs=TOLERANCE) + assert result["selected"].tolist() == [False, False, False, False] + assert result["credit"] == pytest.approx([0, 0, 0, 0], abs=TOLERANCE) + assert_properties(households) + + def raise_property_tax(units, index, increase): """The household with `increase` more property tax billed to the head of tax unit `index`.""" @@ -297,15 +340,15 @@ def assert_raising_a_bill(units, index, increase): def test_newly_billed_tax_unit_can_lose_credit(): """The exception in invariant 6, which follows the form's reading of line - 23 ("the property tax you were billed"). Billing the parent 100 of + 23 ("the property tax you were billed"). Billing the lessee parent 100 of property tax makes the home theirs too: line 23 = 100 and line 24 = 0, so line 27 = max(100 - 259, 0) = 0 instead of 341. Line 22 is unchanged at 259. The child's bill still counts for no one but the child.""" result = calculate( - [PARENT_IN_CHILDS_HOME, raise_property_tax(PARENT_IN_CHILDS_HOME, 0, 100)] + [LESSEE_IN_CHILDS_HOME, raise_property_tax(LESSEE_IN_CHILDS_HOME, 0, 100)] ) assert result["pre_one_claimant"][[0, 4]] == pytest.approx([341, 0], abs=TOLERANCE) - assert_raising_a_bill(PARENT_IN_CHILDS_HOME, 1, 500) + assert_raising_a_bill(LESSEE_IN_CHILDS_HOME, 1, 500) try: @@ -391,8 +434,10 @@ def tax_unit(draw): ] ] ) - # A parent in an adult child's home: the child's bill is the parent's - # rent (line 24 = 4,000; line 27 = 600 - 259 = 341). + # A lessee parent in an adult child's home: the child's bill is the + # parent's rent (line 24 = 4,000; line 27 = 600 - 259 = 341). + @hypothesis.example([LESSEE_IN_CHILDS_HOME]) + # Without owner, renter, or lessee status the parent is not eligible. @hypothesis.example([PARENT_IN_CHILDS_HOME]) # The same parent paying the child 2,400 of rent: line 24 is the larger # bill, 4,000, not 2,400 + 4,000. @@ -418,7 +463,7 @@ def raised_bill(draw): max_examples=10, deadline=None, derandomize=True, suppress_health_check=SLOW ) @hypothesis.given(raised_bill()) - # Raising the child's bill raises the parent's rent and credit. - @hypothesis.example((PARENT_IN_CHILDS_HOME, 1, 500)) + # Raising the child's bill raises the lessee parent's rent and credit. + @hypothesis.example((LESSEE_IN_CHILDS_HOME, 1, 500)) def test_raising_a_bill(case): assert_raising_a_bill(*case) diff --git a/policyengine_us/tests/test_mt_elderly_credit_refundable_credits.py b/policyengine_us/tests/test_mt_elderly_credit_refundable_credits.py index a946da6f053..f5226dca080 100644 --- a/policyengine_us/tests/test_mt_elderly_credit_refundable_credits.py +++ b/policyengine_us/tests/test_mt_elderly_credit_refundable_credits.py @@ -1,26 +1,27 @@ -"""Property tests: refundable credits in the Montana elderly homeowner/renter -credit's gross household income. - -ARM 42.4.301(2)(b)-(c) counts "federal refundable tax credits received" and -"any state refundable tax credits received" in gross household income, and -the 2024 Schedule 2EC line 8 combines "all the refundable credits received by -all household members". The model sums a person-level gross household income -over the household, so each tax unit's federal refundable credits are put on -its head once. These tests check that allocation for households of a claimant -aged 62 or older and a younger member who files their own return with up to -two children, so that the member can have a federal EITC and a refundable -child tax credit. +"""Property tests: federal refundable credits received in the Montana elderly +homeowner/renter credit's gross household income. + +MCA 15-30-2337(4) defines gross household income as "all income received by +all individuals of a household", ARM 42.4.301(2)(b) counts "federal +refundable tax credits received", and the 2024 Schedule 2EC line 8 combines +"all the refundable credits received by all household members". The credits +claimed on a return are paid after its year ends, so the model takes the +federal refundable credits each person received during the year as an input +(mt_elderly_homeowner_or_renter_credit_federal_refundable_credits), not the +current return's entitlement. These tests check that input for households of +a claimant aged 62 or older and a younger member who files their own return +with up to two children, so that the member's return has a federal EITC and +a refundable child tax credit. YAML cases cannot compare two simulations or draw household structures, so -this file does both. Each example runs the households twice: as given (W) and -with the federal refundable credits in gross household income set to zero +this file does both. Each example runs the households twice: with the +federal refundable credits each person received (W) and with none received (Z). Properties, for every household: -1. Counted once: the household sum of the person-level federal credits - equals the sum of income_tax_refundable_credits over its tax units, read - from the tax-unit array. -2. Accounting: gross household income in W exceeds Z by exactly those - credits. +1. An entitlement is not a receipt: in Z the input is zero for everyone, + whatever the federal refundable credits on this year's returns. +2. Accounting: gross household income in W exceeds Z by exactly the credits + received, each counted once. 3. More income never raises the credit: the credit in W is at most Z's. 4. The credit is between zero and the cap, and zero when gross household income is $45,000 or more. @@ -46,10 +47,11 @@ CREDIT = "mt_elderly_homeowner_or_renter_credit" -def build_situation(cases, zero_federal_credits): +def build_situation(cases, received): """One Montana household per case: the claimant files alone; the member - files with their children. Also returns each person's and tax unit's - case index.""" + files with their children. With `received`, each adult received the + case's federal refundable credits during the year. Also returns each + person's and tax unit's case index.""" people, tax_units, households, case_of = {}, {}, {}, {} for i, c in enumerate(cases): claimant, member = f"claimant_{i}", f"member_{i}" @@ -59,10 +61,12 @@ def build_situation(cases, zero_federal_credits): "taxable_pension_income": {YEAR: c["pension"]}, "real_estate_taxes": {YEAR: c["property_tax"]}, "rent": {YEAR: c["rent"]}, + FEDERAL: {YEAR: c["claimant_received"] if received else 0}, } people[member] = { "age": {YEAR: c["member_age"]}, "employment_income": {YEAR: c["wages"]}, + FEDERAL: {YEAR: c["member_received"] if received else 0}, } for child, age in zip(children, c["child_ages"]): people[child] = {"age": {YEAR: age}} @@ -74,19 +78,14 @@ def build_situation(cases, zero_federal_credits): "members": [claimant, member, *children], "state_code": {YEAR: "MT"}, } - if zero_federal_credits: - # Set for everyone: an input for some people gives the others its - # default, not its formula. - for person in people.values(): - person[FEDERAL] = {YEAR: 0} situation = {"people": people, "tax_units": tax_units, "households": households} return situation, case_of -def calculate(cases, zero_federal_credits): +def calculate(cases, received): """Household totals of person- and tax-unit-level variables, summed by entity id rather than array position.""" - situation, case_of = build_situation(cases, zero_federal_credits) + situation, case_of = build_situation(cases, received) simulation = Simulation(situation=situation) def by_household(variable, entity): @@ -113,16 +112,17 @@ def tolerance(amount): def assert_properties(cases): - w = calculate(cases, zero_federal_credits=False) - z = calculate(cases, zero_federal_credits=True) + w = calculate(cases, received=True) + z = calculate(cases, received=False) for i, c in enumerate(cases): tol = tolerance(w["gross"][i]) - federal = w["federal_tax_unit"][i] - # 1. Each tax unit's federal refundable credits count once. - assert w["federal_person"][i] == pytest.approx(federal, abs=tol), c + received = c["claimant_received"] + c["member_received"] + # 1. This year's federal refundable credits are not a receipt. assert z["federal_person"][i] == 0, c - # 2. They are the whole difference in gross household income. - assert w["gross"][i] - z["gross"][i] == pytest.approx(federal, abs=tol), c + assert w["federal_person"][i] == pytest.approx(received, abs=tol), c + # 2. The credits received are the whole difference in gross + # household income, counted once. + assert w["gross"][i] - z["gross"][i] == pytest.approx(received, abs=tol), c # 3. More income never raises the credit. assert w["credit"][i] <= z["credit"][i] + tol, c for result in (w, z): @@ -141,24 +141,29 @@ def assert_properties(cases): def test_worked_example(): """2024 Schedule 2EC: the claimant's line 5 pension 20,000; the - daughter's wages 10,000 (line 17) and her line 8 credits: federal EITC - 34% x 10,000 = 3,400, refundable child tax credit min(1,700, 15% x - 7,500) = 1,125 and Montana EITC 340. Line 18 = 34,865; line 22 = - (34,865 - 12,600) x 0.05 = 1,113.25; line 27 = 2,000 - 1,113.25 = - 886.75; line 30 = 886.75. Without the federal credits, line 18 = - 30,340, line 22 = 887 and line 30 = 1,113.""" + daughter's wages 10,000 (line 17). Her 2024 return has a federal EITC of + 34% x 10,000 = 3,400 and a refundable child tax credit of min(1,700, 15% + x 7,500) = 1,125, paid in 2025, so they are not received in 2024. Line 8 + counts the 4,525 of federal credits she received during 2024 and her + Montana EITC of 340. Line 18 = 34,865; line 22 = (34,865 - 12,600) x + 0.05 = 1,113.25; line 27 = 2,000 - 1,113.25 = 886.75; line 30 = 886.75. + With nothing received, line 18 = 30,340, line 22 = 887 and line 30 = + 1,113.""" case = { "claimant_age": 70, "pension": 20_000, "property_tax": 2_000, "rent": 0, + "claimant_received": 0, "member_age": 30, "wages": 10_000, "child_ages": [5], + "member_received": 4_525, } - w = calculate([case], zero_federal_credits=False) - z = calculate([case], zero_federal_credits=True) - assert w["federal_tax_unit"][0] == pytest.approx(4_525, abs=TOLERANCE) + w = calculate([case], received=True) + z = calculate([case], received=False) + assert z["federal_tax_unit"][0] == pytest.approx(4_525, abs=TOLERANCE) + assert z["federal_person"][0] == 0 assert w["gross"][0] == pytest.approx(34_865, abs=TOLERANCE) assert w["credit"][0] == pytest.approx(886.75, abs=TOLERANCE) assert z["gross"][0] == pytest.approx(30_340, abs=TOLERANCE) @@ -188,11 +193,13 @@ def case(draw): "pension": draw(amount(40_000)), "property_tax": draw(st.integers(min_value=0, max_value=4_000)), "rent": draw(amount(12_000)), + "claimant_received": draw(amount(2_000)), "member_age": draw(st.integers(min_value=19, max_value=61)), "wages": draw(amount(30_000)), "child_ages": draw( st.lists(st.integers(min_value=0, max_value=16), max_size=2) ), + "member_received": draw(amount(10_000)), } @hypothesis.settings(max_examples=10, deadline=None, suppress_health_check=SLOW) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_eligible.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_eligible.py index 64c06f91e30..4cdb7d7823e 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_eligible.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_eligible.py @@ -7,13 +7,40 @@ class mt_elderly_homeowner_or_renter_credit_eligible(Variable): label = "Eligible for the Montana Elderly Homeowner/Renter Credit" definition_period = YEAR defined_for = StateCode.MT + reference = ( + # MCA 15-30-2338(1)(a)-(c): age 62, 9 months of residence and 6 months + # of occupancy as an owner, renter, or lessee + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0380/0150-0300-0230-0380.html", + "https://mca.legmt.gov/bills/2009/mca/15/30/15-30-2338.htm", + # 2025 instructions: the tests the claimant attests to, and "If you are + # married filing jointly and both spouses own or rent the residence, + # only one of you must meet the age requirement" + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2025_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=44", + ) def formula(person, period, parameters): p = parameters( period ).gov.states.mt.tax.income.credits.elderly_homeowner_or_renter - # If the filer is married and both spouses owned or rent the residence - # Only one of them must meet the age requierments - # reference: 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=47 - greater_age_head_spouse = person.tax_unit("greater_age_head_spouse", period) - return greater_age_head_spouse >= p.age_threshold + # Section 15-30-2338(1) sets the tests for "an individual", so one head + # or spouse must meet all of them. Another member's property tax, + # which ARM 42.4.302(2)(b) lets an eligible claimant use as rent, + # cannot establish the occupancy test. + age_eligible = person("age", period) >= p.age_threshold + residency_months = person( + "mt_elderly_homeowner_or_renter_credit_mt_residency_months", period + ) + occupancy_months = person( + "mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months", + period, + ) + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + qualifies = ( + head_or_spouse + & age_eligible + & (residency_months >= p.minimum_residency_months) + & (occupancy_months >= p.minimum_occupancy_months) + ) + # Every member of the return shares the result, so the credit stays + # on the head when the qualifying claimant is the spouse. + return person.tax_unit.any(qualifies) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.py index 25342808b61..8eeffa562de 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.py @@ -4,24 +4,36 @@ class mt_elderly_homeowner_or_renter_credit_federal_refundable_credits(Variable): value_type = float entity = Person - label = "Federal refundable credits in Montana elderly homeowner/renter credit gross household income" + label = "Federal refundable credits received, in Montana elderly homeowner/renter credit gross household income" + documentation = ( + "Federal refundable tax credit cash this person received during the " + "year, such as an earned income or child tax credit refund from the " + "prior year's return or an Economic Impact Payment. Defaults to zero: " + "the credits claimed on this year's return are paid after the year " + "ends, so they do not establish a receipt." + ) unit = USD definition_period = YEAR defined_for = StateCode.MT reference = ( + # MCA 15-30-2337(4): gross household income is "all income received + # by all individuals of a household" + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0370/0150-0300-0230-0370.html", # ARM 42.4.301(2)(b): "federal refundable tax credits received" "https://rules.mt.gov/api/policy-library-public/collections/aec52c46-128e-4279-9068-8af5d5432d74/policies/c90ea93a-03a2-4605-a0f8-f2f3760198bf/document/768c8344-24ee-4950-9d5e-9d8fc97ec0f7", - # 2023 instructions, line 7: "the federal and Montana Earned Income Tax - # Credit, the federal Child Tax Credits" + # 2023 instructions, line 7: "Combine all the refundable credits + # received by the members of the household in 2023", including "the + # federal and Montana Earned Income Tax Credit, the federal Child Tax + # Credits" "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=51", # 2024 Schedule 2EC, line 8: "the federal and Montana earned income tax # credits, the refundable portion of the federal child tax credit" "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=47", ) - def formula(person, period, parameters): - # Federal refundable credits are claimed on the tax unit's return. - # Gross household income sums this person-level amount over the - # household, so count each return's credits once, on its head. - head = person("is_tax_unit_head", period) - return head * person.tax_unit("income_tax_refundable_credits", period) + # An actual-receipt input, like mt_elderly_homeowner_or_renter_credit_received. + # The refundable credits on this year's return, income_tax_refundable_credits, + # are an entitlement paid in a later year, not a receipt during this one. + # Reading last year's return instead would rerun the whole prior-year + # federal tax computation for each record, and it reads 0 whenever the + # inputs cover only one year. diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_rent.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_rent.py index a33e3c26ea1..ed3531c0fd9 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_rent.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_rent.py @@ -40,6 +40,11 @@ def formula(tax_unit, period, parameters): # line 25 counts 15% of it. With the tax unit billed nothing, "the # property taxes billed for that property" are the household's whole # property tax. + # The rule lets an eligible claimant use the bill. The claimant must + # still have occupied the home as an owner, renter, or lessee (MCA + # 15-30-2338(1)(c)), which another member's bill does not show; + # mt_elderly_homeowner_or_renter_credit_eligible applies that test, + # and the credit is computed only for eligible claimants. # The rule says the claimant "may use" the bill. The model reads that # as a choice between two measures of what it costs to occupy one # home, not an addition to the rent paid, and takes the larger. Using diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_mt_residency_months.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_mt_residency_months.py new file mode 100644 index 00000000000..7a5982f9af0 --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_mt_residency_months.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class mt_elderly_homeowner_or_renter_credit_mt_residency_months(Variable): + value_type = int + entity = Person + label = ( + "Months of Montana residence, for the Montana elderly homeowner/renter credit" + ) + documentation = ( + "Months of the year, from 0 to 12, this person resided in Montana. " + "Defaults to 12 for members of a Montana household, whose state the " + "model treats as their residence for the whole year." + ) + unit = "month" + definition_period = YEAR + defined_for = StateCode.MT + reference = ( + # MCA 15-30-2338(1)(b): resided in Montana "for at least 9 months" + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0380/0150-0300-0230-0380.html", + "https://mca.legmt.gov/bills/2009/mca/15/30/15-30-2338.htm", + # 2025 instructions: the claimant attests "You lived in Montana for at + # least nine months during the tax year" + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2025_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=44", + ) + + def formula(person, period, parameters): + return MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months.py new file mode 100644 index 00000000000..0d09e6b9e8c --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months.py @@ -0,0 +1,46 @@ +from policyengine_us.model_api import * + + +class mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months(Variable): + value_type = int + entity = Person + label = "Months occupying a Montana dwelling as an owner, renter, or lessee, for the Montana elderly homeowner/renter credit" + documentation = ( + "Months of the year, from 0 to 12, this person occupied one or more " + "Montana dwellings as an owner, renter, or lessee. Another household " + "member's property tax bill does not establish that status. Defaults " + "to 12 for the head and spouse of a tax unit that pays rent or is " + "billed property tax, and to 0 otherwise." + ) + unit = "month" + definition_period = YEAR + defined_for = StateCode.MT + reference = ( + # MCA 15-30-2338(1)(c), (2): occupied one or more dwellings in Montana + # "as an owner, renter, or lessee for at least 6 months" + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0380/0150-0300-0230-0380.html", + "https://mca.legmt.gov/bills/2009/mca/15/30/15-30-2338.htm", + # 2025 instructions: the claimant attests "You occupied a Montana + # residence as a renter, owner, or lessee for at least six months + # during the tax year" + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2-Instructions/2025_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=44", + ) + + def formula(person, period, parameters): + # Rent paid and property tax billed are the return's (Schedule 2EC + # lines 23 and 24, "the property tax you were billed" and "the rent + # that you paid"), so they show that the head and spouse occupy the + # home as renters or owners. Annual amounts carry no months; like + # the household's state, they are taken to cover the whole year. + # A tax unit with neither shows no such status: the household's bill + # in another member's name can count as rent only for a claimant + # who is otherwise eligible (ARM 42.4.302(2)(b)), so it cannot + # establish the status here. Supply this input for an occupant who + # holds the home as a lessee or owner without either amount. + rent = add(person.tax_unit, period, ["rent"]) + property_tax = person.tax_unit( + "mt_elderly_homeowner_or_renter_credit_property_tax_billed", period + ) + documented = (rent > 0) | (property_tax > 0) + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + return where(head_or_spouse & documented, MONTHS_IN_YEAR, 0) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_eligible_person.py b/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_eligible_person.py index 30f6653eaed..4dd28b58c37 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_eligible_person.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_eligible_person.py @@ -7,7 +7,17 @@ class mt_disability_income_exclusion_eligible_person(Variable): label = "Montana disability income exclusion eligible person" defined_for = StateCode.MT definition_period = YEAR - reference = "https://rules.mt.gov/gateway/RuleNo.asp?RN=42%2E15%2E217" + reference = ( + "https://rules.mt.gov/gateway/RuleNo.asp?RN=42%2E15%2E217", + # 2021 Mont. Laws ch. 503 (SB 399): section 65 repeals 15-30-2110, + # MCA, which held the exclusion; section 70(1) applies the repeal to + # tax years beginning after December 31, 2023. + # PDF pages 68, 70 + "https://archive.legmt.gov/content/Publications/sales/2021SessionLaws_V3_ERRATA-VERSION.pdf#page=68", + # 2024 Form 2 instructions, repealed deductions: "Partial retirement + # disability deduction for taxpayers under age 65" + "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=5", + ) def formula(person, period, parameters): # first select head and spouse with ages below the specific threshold, and @@ -18,3 +28,8 @@ def formula(person, period, parameters): eligible_retiree = age_eligible & is_retired_on_disability head_or_spouse = person("is_tax_unit_head_or_spouse", period) return eligible_retiree & head_or_spouse + + def formula_2024(person, period, parameters): + # The exclusion is repealed for tax years beginning after December 31, + # 2023 (2021 Mont. Laws ch. 503, sections 65 and 70(1)). + return False diff --git a/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_person.py b/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_person.py index f4a3bfb1ea7..c35d3c97470 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_person.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_person.py @@ -8,8 +8,20 @@ class mt_disability_income_exclusion_person(Variable): defined_for = "mt_disability_income_exclusion_eligible_person" unit = USD definition_period = YEAR - reference = "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=31" + reference = ( + "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=31", + # 2021 Mont. Laws ch. 503 (SB 399): section 65 repeals 15-30-2110, + # MCA, which held the exclusion; section 70(1) applies the repeal to + # tax years beginning after December 31, 2023. + # PDF pages 68, 70 + "https://archive.legmt.gov/content/Publications/sales/2021SessionLaws_V3_ERRATA-VERSION.pdf#page=68", + ) def formula(person, period, parameters): p = parameters(period).gov.states.mt.tax.income.subtractions.disability_income return min_(p.cap, person("taxable_disability_benefits", period)) + + def formula_2024(person, period, parameters): + # Repealed from 2024 (2021 Mont. Laws ch. 503, sections 65 and 70(1)), + # even for a person whose eligibility is supplied as an input. + return 0