diff --git a/changelog.d/fix-mt-ehrc-property-in-others-name.fixed.md b/changelog.d/fix-mt-ehrc-property-in-others-name.fixed.md new file mode 100644 index 00000000000..5e94dd1e034 --- /dev/null +++ b/changelog.d/fix-mt-ehrc-property-in-others-name.fixed.md @@ -0,0 +1 @@ +Count the property tax billed to other household members as rent, at 15%, for a Montana elderly homeowner/renter credit claimant whose tax unit is billed none (ARM 42.4.302(2)(b)). 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 8ce46d3ddea..a9f54d8324d 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 @@ -1296,3 +1296,321 @@ output: # 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 + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 14_000 + rent: 0 + ssi: 0 + person2: + age: 45 + taxable_interest_income: 6_000 + rent: 0 + real_estate_taxes: 4_000 + ssi: 0 + 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 + # property can qualify as rent only" (2025 instructions, line 23; ARM + # 42.4.302(2)(b)). + # Line 18 = 14_000 + 6_000 = 20_000; line 20 = 20_000 - 12_600 = 7_400; + # 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. + # 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] + mt_elderly_homeowner_or_renter_credit_pre_one_claimant: [341, 0] + mt_elderly_homeowner_or_renter_credit_selected_claimant: [true, false] + mt_elderly_homeowner_or_renter_credit: [341, 0] + mt_refundable_credits: [341, 0] + +- name: 2024 Schedule 2EC, a parent who pays the child less rent than the child's bill counts the bill + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 14_000 + rent: 2_400 + ssi: 0 + person2: + age: 45 + taxable_interest_income: 6_000 + rent: 0 + real_estate_taxes: 4_000 + ssi: 0 + 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: + # Line 22 = 259 as above. Line 24 = the larger of the rent paid + # (2_400) and the child's bill (4_000) = 4_000; line 25 = 600; line 27 = + # 341. Counting rent paid alone would give 360 - 259 = 101. + mt_elderly_homeowner_or_renter_credit_gross_rent: [4_000, 0] + mt_elderly_homeowner_or_renter_credit: [341, 0] + +- name: 2024 Schedule 2EC, a parent who pays the child more rent than the child's bill counts the rent, not both + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 14_000 + rent: 6_000 + ssi: 0 + person2: + age: 45 + taxable_interest_income: 6_000 + rent: 0 + real_estate_taxes: 4_000 + ssi: 0 + 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: + # Line 22 = 259. Line 24 = max(6_000, 4_000) = 6_000; line 25 = 900; + # line 27 = 900 - 259 = 641. Adding the bill to the rent (10_000) would + # give 1_500 - 259 = 1_241, capped at 1_150. + mt_elderly_homeowner_or_renter_credit_gross_rent: [6_000, 0] + mt_elderly_homeowner_or_renter_credit: [641, 0] + +- name: 2024 Schedule 2EC, two elderly siblings and one owns; the owner's larger credit is the one claim + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 66 + taxable_pension_income: 10_000 + rent: 0 + ssi: 0 + person2: + age: 70 + taxable_pension_income: 10_000 + rent: 0 + real_estate_taxes: 2_000 + ssi: 0 + 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: + # 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. + # 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_selected_claimant: [false, true] + mt_elderly_homeowner_or_renter_credit: [0, 1_150] + +- name: 2024 Schedule 2EC, a dependent's bill stays on the claimant's line 23 + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 14_000 + rent: 0 + is_tax_unit_dependent: false + ssi: 0 + person2: + age: 50 + rent: 0 + is_tax_unit_dependent: true + real_estate_taxes: 4_000 + ssi: 0 + tax_units: + tax_unit: + members: [person1, person2] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_name: MT + output: + # real_estate_taxes does not show whose name is on the title, so the + # tax unit's bill, the dependent's included, is line 23 and ARM + # 42.4.302(2)(b) does not apply. Line 18 = 14_000; line 20 = 1_400; + # line 21 = 0; line 22 = 0. Line 23 = 4_000; line 24 = 0; line 27 = + # 4_000; line 28 = 1_150 cap; line 30 = 1_150. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 4_000 + mt_elderly_homeowner_or_renter_credit_gross_rent: 0 + mt_elderly_homeowner_or_renter_credit: [1_150, 0] + +- name: 2024 Schedule 2EC, a home co-owned with a dependent keeps both bills on line 23 + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 14_000 + rent: 0 + is_tax_unit_dependent: false + real_estate_taxes: 500 + ssi: 0 + person2: + age: 50 + rent: 0 + is_tax_unit_dependent: true + real_estate_taxes: 2_000 + ssi: 0 + tax_units: + tax_unit: + members: [person1, person2] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_name: MT + output: + # Line 18 = 14_000; line 20 = 1_400; line 21 = 0; line 22 = 0. Line 23 + # = 500 + 2_000 = 2_500; line 24 = 0; line 27 = 2_500; line 28 = 1_150 + # cap; line 30 = 1_150. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 2_500 + mt_elderly_homeowner_or_renter_credit_gross_rent: 0 + mt_elderly_homeowner_or_renter_credit: [1_150, 0] + +- name: 2024 Schedule 2EC, a dependent pays the rent and no one in the household is billed + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + taxable_pension_income: 14_000 + rent: 0 + is_tax_unit_dependent: false + ssi: 0 + person2: + age: 50 + rent: 6_000 + is_tax_unit_dependent: true + ssi: 0 + tax_units: + tax_unit: + members: [person1, person2] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_name: MT + output: + # Line 18 = 14_000; line 20 = 1_400; line 21 = 0; line 22 = 0. Line 23 + # = 0. Line 24 = the tax unit's rent, the dependent's included, 6_000, + # against a household bill of 0; line 25 = 900; line 27 = 900; line 30 + # = 900. + mt_elderly_homeowner_or_renter_credit_gross_rent: 6_000 + mt_elderly_homeowner_or_renter_credit: [900, 0] + +- name: 2024 Schedule 2EC, a parent in the home of a child's joint return billed through the spouse + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 14_000 + rent: 0 + ssi: 0 + person2: + age: 45 + rent: 0 + ssi: 0 + person3: + age: 43 + rent: 0 + real_estate_taxes: 4_000 + ssi: 0 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2, person3] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2, person3] + households: + household: + members: [person1, person2, person3] + state_name: MT + output: + # Line 18 = 14_000; line 20 = 1_400; line 21 = 0; line 22 = 0. Parent: + # line 23 = 0; line 24 = the household's bill, 4_000, held by the + # child's spouse; line 25 = 600; line 27 = 600; line 30 = 600. + mt_elderly_homeowner_or_renter_credit_gross_rent: [4_000, 0] + mt_elderly_homeowner_or_renter_credit: [600, 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_gross_rent.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_rent.yaml new file mode 100644 index 00000000000..b798eff4b6a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_rent.yaml @@ -0,0 +1,378 @@ +- name: Case 1, rent paid, with no property tax billed in the household. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + rent: 6_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MT + output: + # Schedule 2EC line 24: "the rent that you paid". + mt_elderly_homeowner_or_renter_credit_gross_rent: 6_000 + +- name: Case 2, a parent living in an adult child's home counts the child's property tax as rent. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + rent: 0 + person2: + age: 45 + rent: 0 + real_estate_taxes: 3_000 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # The parent is billed nothing: the home is "in a name other than the + # claimant", so the child's 3_000 bill goes on the parent's line 24 as + # rent (ARM 42.4.302(2)(b)). The child is billed their own property tax + # (line 23) and pays no rent. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: [0, 3_000] + mt_elderly_homeowner_or_renter_credit_gross_rent: [3_000, 0] + +- name: Case 3, a claimant billed their own property tax does not count another member's bill. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + rent: 0 + real_estate_taxes: 500 + person2: + age: 45 + rent: 0 + real_estate_taxes: 3_000 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # The home is in person1's name too, so ARM 42.4.302(2)(b) does not + # apply: line 23 = 500 and line 24 = 0. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: [500, 3_000] + mt_elderly_homeowner_or_renter_credit_gross_rent: [0, 0] + +- name: Case 4, rent paid below the other member's bill; the bill counts. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + rent: 2_400 + person2: + age: 50 + rent: 0 + real_estate_taxes: 3_000 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Line 24 = max(2_400, 3_000): the bill is an alternative measure of the + # rent for the same home, not an addition to it. + mt_elderly_homeowner_or_renter_credit_gross_rent: [3_000, 0] + +- name: Case 5, rent paid above the other member's bill; the rent counts. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + rent: 4_800 + person2: + age: 50 + rent: 0 + real_estate_taxes: 3_000 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Line 24 = max(4_800, 3_000), not 4_800 + 3_000. + mt_elderly_homeowner_or_renter_credit_gross_rent: [4_800, 0] + +- name: Case 6, a dependent's bill stays on line 23, not rent. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + rent: 0 + is_tax_unit_dependent: false + person2: + age: 50 + rent: 0 + is_tax_unit_dependent: true + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # The tax unit is billed, through the dependent, so ARM 42.4.302(2)(b) + # does not apply: line 23 = 2_000 and line 24 = 0. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 2_000 + mt_elderly_homeowner_or_renter_credit_gross_rent: 0 + +- name: Case 7, a home co-owned by two other members counts the whole bill. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + rent: 0 + person2: + age: 45 + rent: 0 + real_estate_taxes: 1_000 + person3: + age: 48 + rent: 0 + real_estate_taxes: 1_500 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # "The property taxes billed for that property": 1_000 + 1_500. + mt_elderly_homeowner_or_renter_credit_gross_rent: [2_500, 0, 0] + +- name: Case 8, a joint couple billed through the spouse does not count another member's bill. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + rent: 0 + person2: + age: 66 + rent: 0 + real_estate_taxes: 1_800 + person3: + age: 40 + rent: 0 + real_estate_taxes: 2_000 + tax_units: + tax_unit1: + members: [person1, person2] + tax_unit2: + members: [person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # A joint return is one claimant, billed 1_800 through the spouse. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: [1_800, 2_000] + mt_elderly_homeowner_or_renter_credit_gross_rent: [0, 0] + +- name: Case 9, in 2009 ARM 42.4.302(5) already counted property in another's name as rent. + period: 2009 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + rent: 0 + person2: + age: 45 + rent: 0 + real_estate_taxes: 3_000 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # ARM 42.4.302(5), effective 8/20/2004 to 11/10/2017: "Property taxes + # billed are allowable as rent if the property occupied by an eligible + # claimant is in a name other than the claimant." It became (2)(b) in + # 2017. + mt_elderly_homeowner_or_renter_credit_gross_rent: [3_000, 0] + +- name: Case 10, outside Montana. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + rent: 0 + person2: + age: 45 + rent: 0 + real_estate_taxes: 3_000 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: ID + output: + mt_elderly_homeowner_or_renter_credit_gross_rent: [0, 0] + +- name: Case 11, a joint couple billed nothing counts the other member's bill once. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + rent: 0 + person2: + age: 66 + rent: 0 + person3: + age: 45 + rent: 0 + real_estate_taxes: 3_000 + tax_units: + tax_unit1: + members: [person1, person2] + tax_unit2: + members: [person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # One claim for the joint return: line 24 = 3_000, not 6_000. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: [0, 3_000] + mt_elderly_homeowner_or_renter_credit_gross_rent: [3_000, 0] + +- name: Case 12, a home co-owned with a dependent stays on line 23. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + rent: 0 + is_tax_unit_dependent: false + real_estate_taxes: 500 + person2: + age: 50 + rent: 0 + is_tax_unit_dependent: true + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # The tax unit is billed, so ARM 42.4.302(2)(b) does not apply: the tax + # unit's bills, 500 + 2_000, are line 23, and line 24 is 0. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 2_500 + mt_elderly_homeowner_or_renter_credit_gross_rent: 0 + +- name: Case 13, a dependent pays the rent and no one in the household is billed. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + rent: 0 + is_tax_unit_dependent: false + person2: + age: 50 + rent: 6_000 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Line 24 counts the tax unit's rent, a dependent's included: 6_000. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 0 + mt_elderly_homeowner_or_renter_credit_gross_rent: 6_000 + +- name: Case 14, a bill on another tax unit's spouse counts in the household's bill. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + rent: 0 + person2: + age: 45 + rent: 0 + person3: + age: 43 + rent: 0 + real_estate_taxes: 4_000 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # The child's joint return is billed through the spouse; the parent's + # line 24 is the household's whole bill, 4_000. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: [0, 4_000] + mt_elderly_homeowner_or_renter_credit_gross_rent: [4_000, 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_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 533e31da039..98ed9ddbb9c 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 @@ -35,3 +35,92 @@ mt_elderly_homeowner_or_renter_credit_pre_one_claimant: [0, 210, 0] mt_elderly_homeowner_or_renter_credit_selected_claimant: [false, true, false] mt_elderly_homeowner_or_renter_credit: [0, 210, 0] + +- name: Case 2, a tax unit billed no property tax counts another member's bill as rent. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 14_000 + rent: 0 + ssi: 0 + person2: + age: 72 + taxable_pension_income: 4_000 + rent: 0 + ssi: 0 + real_estate_taxes: 900 + person3: + age: 45 + taxable_interest_income: 2_000 + rent: 0 + ssi: 0 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + households: + household: + members: [person1, person2, person3] + state_name: MT + output: + # 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. + # 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. + mt_elderly_homeowner_or_renter_credit_gross_rent: [900, 0, 900] + mt_elderly_homeowner_or_renter_credit_pre_one_claimant: [0, 641, 0] + +- name: Case 3, the home's bill as rent makes the only eligible tax unit's credit positive. + 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: + # SSI is pinned at 0. Line 18 = 12_000; line 20 = max(12_000 - 12_600, + # 0) = 0; line 22 = 0. + # person1: line 24 = 2_500; line 25 = 375; line 27 = 375. + # 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] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_property_tax_billed.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_property_tax_billed.yaml new file mode 100644 index 00000000000..ebe0315cdf0 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_property_tax_billed.yaml @@ -0,0 +1,150 @@ +- name: Case 1, a single owner's property tax billed. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MT + output: + # Schedule 2EC line 23. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 2_000 + +- name: Case 2, a joint couple's bills are one claimant's. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + real_estate_taxes: 1_200 + person2: + age: 66 + real_estate_taxes: 800 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # A joint return makes one claim: line 23 = 1_200 + 800. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 2_000 + +- name: Case 3, a dependent's bill counts as the tax unit's. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + is_tax_unit_dependent: false + person2: + age: 50 + is_tax_unit_dependent: true + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # real_estate_taxes is an expense amount, not a record of title, so a + # dependent's bill stays on the claimant's line 23. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 2_000 + +- name: Case 4, each tax unit counts only the bill in its own name. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + person2: + age: 45 + real_estate_taxes: 3_000 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + mt_elderly_homeowner_or_renter_credit_property_tax_billed: [0, 3_000] + +- name: Case 5, outside Montana. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: ID + output: + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 0 + +- name: Case 6, a home co-owned with a dependent counts both bills. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + is_tax_unit_dependent: false + real_estate_taxes: 500 + person2: + age: 50 + is_tax_unit_dependent: true + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # The tax unit's bills are line 23: 500 + 2_000. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 2_500 + +- name: Case 7, fractional bills are summed exactly. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + real_estate_taxes: 1_200.50 + person2: + age: 66 + real_estate_taxes: 799.25 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # 1_200.50 + 799.25. + mt_elderly_homeowner_or_renter_credit_property_tax_billed: 1_999.75 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 ae224c8dea5..782b76873c6 100644 --- a/policyengine_us/tests/test_mt_elderly_credit_one_claimant.py +++ b/policyengine_us/tests/test_mt_elderly_credit_one_claimant.py @@ -7,14 +7,20 @@ household claiming this credit". Gross household income (line 18) covers everyone in the household, so every tax unit in a household with a member aged 62 or older computes its credit on the same net household income (line -22) and multiplier (line 29); the credits differ only by each tax unit's own -property tax (line 23) and rent (line 24). The model pays the tax unit whose -credit is largest. +22) and multiplier (line 29); the credits differ only by each tax unit's +property tax billed (line 23) and rent (line 24). A tax unit billed no +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. 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 joint, any mix of ages, pension, interest, Social Security, property tax and -rent; no earned income, so no refundable credit enters line 8): +rent; no earned income, so no refundable credit enters line 8). The +generator has no dependents; the YAML tests cover a dependent's bill and +rent: 1. Each tax unit's credit before the limit matches the reference. 2. The household's credit is the largest of its tax units' credits, so it @@ -26,6 +32,20 @@ 5. Reversing the order of the tax units in a household does not change the household's credit. +A second test raises the property tax billed to one tax unit and checks the +two properties below. They hold with household income fixed, as it is here: +no one has earned income or other deductions, so a larger bill changes no +refundable credit. In general a larger property tax deduction can change a +refundable credit and so gross household income (line 8), which moves every +tax unit's line 22. + +6. No other tax unit's credit before the limit falls, and neither does that + tax unit's own credit if it was already billed property tax. (A tax unit + newly billed property tax can lose credit: it stops counting the other + members' bill as rent and counts only its own bill.) +7. The household's credit does not fall unless the raised tax unit was billed + nothing before. + The model computes in single precision, so comparisons allow one cent or eight float32 spacings at the household's total income, whichever is larger. """ @@ -114,11 +134,18 @@ def reference(units): net = reduced * float(P.net_household_income.reduction_rate.calc(reduced)) # Line 29. multiplier = float(P.multiplier.calc(gross)) + 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)). + rent = unit["rent"] + if unit["property_tax"] == 0: + rent = max(rent, household_property_tax) # Lines 23-28. - housing = unit["property_tax"] + unit["rent"] * P.rent_equivalent_tax_rate + housing = unit["property_tax"] + rent * P.rent_equivalent_tax_rate capped = min(max(housing - net, 0), P.cap) credits.append(eligible * capped * multiplier) return gross, credits @@ -216,6 +243,71 @@ def test_worked_example(): assert_properties(households) +PARENT_IN_CHILDS_HOME = [ + {"adults": [adult(80, pension=14_000)], "property_tax": 0, "rent": 0}, + {"adults": [adult(45, interest=6_000)], "property_tax": 4_000, "rent": 0}, +] + + +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] + result = calculate(households) + assert result["pre_one_claimant"] == pytest.approx([341, 0, 0, 341], abs=TOLERANCE) + assert result["selected"].tolist() == [True, False, False, True] + assert result["credit"] == pytest.approx([341, 0, 0, 341], 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`.""" + raised = list(units) + raised[index] = { + **units[index], + "property_tax": units[index]["property_tax"] + increase, + } + return raised + + +def assert_raising_a_bill(units, index, increase): + """Invariants 6 and 7.""" + result = calculate([units, raise_property_tax(units, index, increase)]) + n = len(units) + tol = tolerance(reference(units)[0]) + # build_situation lays out each household forward, then reversed; compare + # the forward copies. + before = result["pre_one_claimant"][:n] + after = result["pre_one_claimant"][2 * n : 3 * n] + already_billed = units[index]["property_tax"] > 0 + for j in range(n): + if j != index or already_billed: + assert after[j] >= before[j] - tol, (units, index, increase) + if already_billed: + household_before = result["credit"][:n].sum() + household_after = result["credit"][2 * n : 3 * n].sum() + assert household_after >= household_before - tol, (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 + 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)] + ) + assert result["pre_one_claimant"][[0, 4]] == pytest.approx([341, 0], abs=TOLERANCE) + assert_raising_a_bill(PARENT_IN_CHILDS_HOME, 1, 500) + + try: import hypothesis import hypothesis.strategies as st @@ -299,5 +391,34 @@ 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). + @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. + @hypothesis.example( + [ + [ + {**PARENT_IN_CHILDS_HOME[0], "rent": 2_400}, + PARENT_IN_CHILDS_HOME[1], + ] + ] + ) def test_properties(households): assert_properties(households) + + @st.composite + def raised_bill(draw): + units = draw(st.lists(tax_unit(), min_size=1, max_size=3)) + index = draw(st.integers(min_value=0, max_value=len(units) - 1)) + increase = draw(st.integers(min_value=1, max_value=4_000)) + return units, index, increase + + @hypothesis.settings( + 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)) + def test_raising_a_bill(case): + assert_raising_a_bill(*case) 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 new file mode 100644 index 00000000000..a33e3c26ea1 --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_gross_rent.py @@ -0,0 +1,64 @@ +from policyengine_us.model_api import * + + +class mt_elderly_homeowner_or_renter_credit_gross_rent(Variable): + value_type = float + entity = TaxUnit + label = "Montana gross rent for the elderly homeowner/renter credit" + unit = USD + definition_period = YEAR + defined_for = StateCode.MT + reference = ( + # § 15-30-2337(5): gross rent; § 15-30-2340(2): a claimant who rents + # the homestead + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0370/0150-0300-0230-0370.html", + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0400/0150-0300-0230-0400.html", + # ARM 42.4.302(2)(b): property taxes billed may be used "as rent if + # the property occupied by the claimant is in a name other than the + # claimant" + "https://www.law.cornell.edu/regulations/montana/Mont-Admin-r-42.4.302", + # ARM 42.4.302(5) before its 2017 restructuring, in force from + # 8/20/2004: "Property taxes billed are allowable as rent if the + # property occupied by an eligible claimant is in a name other than + # the claimant." + "https://web.archive.org/web/20080624004125/http://www.mtrules.org/gateway/RuleNo.asp?RN=42.4.302", + # 2025 Schedule 2EC lines 24 and 25 + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2/2025_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=10", + # 2025 instructions, lines 23 and 24: "If the property occupied by + # you is in a name other than your own, the property taxes billed for + # that property can qualify as rent only." + "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=47", + ) + + def formula(tax_unit, period, parameters): + # Schedule 2EC line 24: "the rent that you paid". + rent = add(tax_unit, period, ["rent"]) + # The model treats a tax unit billed no property tax, dependents + # included, as living in a home in another household member's name. + # Its property tax "can qualify as rent only" (2025 instructions, + # line 23; ARM 42.4.302(2)(b)): it goes on line 24, not line 23, so + # 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 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 + # the bill only when no rent is paid, since gross rent is rent + # "actually paid" (§ 15-30-2337(5)), is another defensible reading; + # the two differ only when a claimant pays a household member less + # rent than that member's bill. + # Owners outside the household, such as a landlord, are not visible + # here, and real_estate_taxes is not limited to the residence and + # one acre. + claimant_property_tax = tax_unit( + "mt_elderly_homeowner_or_renter_credit_property_tax_billed", period + ) + person = tax_unit.members + head = person("is_tax_unit_head", period) + household_property_tax = tax_unit.sum( + add(person.household, period, ["real_estate_taxes"]) * head + ) + property_tax_as_rent = where( + claimant_property_tax <= 0, household_property_tax, 0 + ) + return max_(rent, property_tax_as_rent) diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_pre_one_claimant.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_pre_one_claimant.py index aa8cd4ba1ff..04e7d41e713 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_pre_one_claimant.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_pre_one_claimant.py @@ -11,6 +11,9 @@ class mt_elderly_homeowner_or_renter_credit_pre_one_claimant(Variable): reference = ( "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0370/0150-0300-0230-0370.html", "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0400/0150-0300-0230-0400.html", + # ARM 42.4.302(1): property tax billed on the owned part plus the + # rent-equivalent tax on the rented part + "https://www.law.cornell.edu/regulations/montana/Mont-Admin-r-42.4.302", # 2024 Form 2, Schedule 2EC "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2/2024_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=10", # 2024 instructions, line 29 Credit Multiplier Table @@ -38,9 +41,13 @@ def formula(person, period, parameters): period, ["mt_elderly_homeowner_or_renter_credit_net_household_income"], ) - # Credit Computation - property_tax = add(person.tax_unit, period, ["real_estate_taxes"]) - rent = add(person.tax_unit, period, ["rent"]) + # Credit Computation: Schedule 2EC lines 23 to 26 + property_tax = person.tax_unit( + "mt_elderly_homeowner_or_renter_credit_property_tax_billed", period + ) + rent = person.tax_unit( + "mt_elderly_homeowner_or_renter_credit_gross_rent", period + ) countable_rent = rent * p.rent_equivalent_tax_rate countable_rent_and_property_tax = property_tax + countable_rent uncapped_credit_unit = max_( diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_property_tax_billed.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_property_tax_billed.py new file mode 100644 index 00000000000..029db2d1661 --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_property_tax_billed.py @@ -0,0 +1,36 @@ +from policyengine_us.model_api import * + + +class mt_elderly_homeowner_or_renter_credit_property_tax_billed(Variable): + value_type = float + entity = TaxUnit + label = "Montana property tax billed for the elderly homeowner/renter credit" + unit = USD + definition_period = YEAR + defined_for = StateCode.MT + reference = ( + # § 15-30-2337(10): property tax billed; § 15-30-2340(1): a claimant + # who owns the homestead + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0370/0150-0300-0230-0370.html", + "https://mca.legmt.gov/bills/mca/title_0150/chapter_0300/part_0230/section_0400/0150-0300-0230-0400.html", + # ARM 42.4.302(2)(b): property in a name other than the claimant + "https://www.law.cornell.edu/regulations/montana/Mont-Admin-r-42.4.302", + # 2025 Schedule 2EC line 23: "the property tax you were billed" + "https://revenue.mt.gov/files/forms/Montana-Individual-Income-Tax-Return-Form-2/2025_Montana_Individual_Income_Tax_Return_Form_2.pdf#page=10", + # PDF pages 46-47: line 23, and property "in a name other than your + # own" + "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=46", + ) + + # Schedule 2EC line 23 is "the property tax you were billed". The + # model counts the real_estate_taxes of everyone in the tax unit, + # dependents included. real_estate_taxes is an expense amount, not a + # record of whose name is on the title: the microdata mostly put a + # household's bill on its reference person, who can be a tax unit + # dependent. So it cannot show a home wholly in a dependent's name, + # and a dependent's bill stays the claimant's. + # When no one in the tax unit is billed, the home is treated as in + # another household member's name, whose property tax "can qualify + # as rent only" (ARM 42.4.302(2)(b)); see + # mt_elderly_homeowner_or_renter_credit_gross_rent. + adds = ["real_estate_taxes"] diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_selected_claimant.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_selected_claimant.py index c28c01f485d..f4712678fa1 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_selected_claimant.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_selected_claimant.py @@ -38,18 +38,22 @@ def formula(tax_unit, period, parameters): # only by Schedule 2EC line 26: property tax billed plus 15% of rent, # before the $1,150 cap. The model counts each tax unit's own # property tax and rent, following Schedule 2EC's line labels ("the - # property tax you were billed", "the rent that you paid") and its - # instructions (property in another's name "can qualify as rent - # only"). The statute instead - # defines both for the homestead (§ 15-30-2337(5), (10)), which would - # give the one claimant the household's whole property tax and rent; - # that reading is not modeled. We select the tax unit whose credit is - # largest, the claim a household would choose. get_rank ranks the - # candidates in each household 0, 1, 2, ..., so a household with any - # candidate has exactly one at rank 0; its stable sort gives a tie to the first in member order. A - # joint return is one tax unit and one claim; the 2025 instructions - # name the spouse listed as the taxpayer as the claimant when both - # qualify, and the model holds that credit on the tax unit head. + # property tax you were billed", "the rent that you paid"). A tax + # unit billed no property tax is treated as living in a home in + # another member's name, whose property tax "can qualify as rent + # only" (2025 instructions; ARM 42.4.302(2)(b)): it counts the + # household's property tax as rent, if that is larger (see + # mt_elderly_homeowner_or_renter_credit_gross_rent). The statute + # instead defines both for the homestead (§ 15-30-2337(5), (10)), + # which would give the one claimant the household's whole property + # tax and rent; that reading is not modeled. We select the tax unit + # whose credit is largest, the claim a household would choose. + # get_rank ranks the candidates in each household 0, 1, 2, ..., so a + # household with any candidate has exactly one at rank 0; its stable + # sort gives a tie to the first in member order. A joint return is one + # tax unit and one claim; the 2025 instructions name the spouse listed + # as the taxpayer as the claimant when both qualify, and the model + # holds that credit on the tax unit head. # ARM 42.4.302(3)(a) also allows married couples living apart only # one credit a year; a separated spouse in another tax unit is not # linked to the other spouse, so that limit is not modeled.