diff --git a/changelog.d/state-choice-bugs-nj-ne.fixed.md b/changelog.d/state-choice-bugs-nj-ne.fixed.md new file mode 100644 index 00000000000..2dce3bf13e7 --- /dev/null +++ b/changelog.d/state-choice-bugs-nj-ne.fixed.md @@ -0,0 +1 @@ +New Jersey now weighs the change in its refundable child tax credit and child and dependent care credit when choosing between the property tax deduction and the $50 credit, and Nebraska itemized deductions now subtract the full state and local income taxes on Schedule A line 5a from federal itemized deductions, before the federal SALT cap, under Neb. Rev. Stat. 77-2716.01(4). diff --git a/policyengine_us/tests/policy/baseline/gov/states/ne/tax/income/deductions/ne_itemized_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/states/ne/tax/income/deductions/ne_itemized_deductions.yaml index e11a586976d..6a8908e8b26 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ne/tax/income/deductions/ne_itemized_deductions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ne/tax/income/deductions/ne_itemized_deductions.yaml @@ -1,4 +1,11 @@ +# Neb. Rev. Stat. 77-2716.01(4) and Form 1040N lines 7-9: federal itemized +# deductions (Schedule A line 17) minus the income taxes on Schedule A line 5a, +# in full, before the federal SALT cap. Nothing is removed when line 5a holds +# sales taxes. + - name: Unit test 1 + # Federal: 2,000 + 24,000 + 10,000 capped SALT = 36,000. Income taxes (5,000) + # exceed sales taxes (0), so all 5,000 is removed: 36,000 - 5,000 = 31,000. period: 2021 input: filing_status: JOINT @@ -6,11 +13,17 @@ deductible_interest_expense: 24_000 salt_deduction: 10_000 real_estate_taxes: 9_000 + state_withheld_income_tax: 5_000 + local_income_tax: 0 + state_sales_tax: 0 + local_sales_tax: 0 state_code: NE output: - ne_itemized_deductions: 2_000 + 24_000 + 9_000 + ne_itemized_deductions: 31_000 - name: Unit test 2 + # Federal: 3,000 + 7,000 + 10,000 capped SALT = 20,000. Income taxes (5,000) + # exceed sales taxes (0): 20,000 - 5,000 = 15,000. period: 2022 input: filing_status: JOINT @@ -18,6 +31,129 @@ deductible_interest_expense: 7_000 salt_deduction: 10_000 real_estate_taxes: 6_000 + state_withheld_income_tax: 5_000 + local_income_tax: 0 + state_sales_tax: 0 + local_sales_tax: 0 + state_code: NE + output: + ne_itemized_deductions: 15_000 + +- name: Sales taxes on Schedule A line 5a stay in the Nebraska deduction + # Federal: 15,000 interest + 8,000 SALT = 23,000. Sales taxes (3,000) exceed + # income taxes (1,000), so line 5a holds sales taxes and Nebraska removes + # nothing: 23,000. + period: 2023 + input: + filing_status: SINGLE + deductible_interest_expense: 15_000 + salt_deduction: 8_000 + real_estate_taxes: 5_000 + state_withheld_income_tax: 1_000 + local_income_tax: 0 + state_sales_tax: 3_000 + local_sales_tax: 0 + state_code: NE + output: + ne_itemized_deductions: 23_000 + +- name: Income taxes on Schedule A line 5a are removed when the cap does not bind + # Federal: 15,000 interest + 7,000 SALT (2,000 income taxes + 5,000 real + # estate taxes) = 22,000. Nebraska: 22,000 - 2,000 = 20,000. + period: 2023 + input: + filing_status: SINGLE + deductible_interest_expense: 15_000 + salt_deduction: 7_000 + real_estate_taxes: 5_000 + state_withheld_income_tax: 2_000 + local_income_tax: 0 + state_sales_tax: 500 + local_sales_tax: 0 + state_code: NE + output: + ne_itemized_deductions: 20_000 + +- name: Income taxes above the federal SALT cap are removed in full, floored at zero + # 2025, single, AGI 700,000. Federal SALT cap: 40,000 - 30% x (700,000 - + # 500,000) = -20,000, floored at 10,000. Schedule A line 5a: 35,000 income + # taxes; SALT deduction min(35,000 + 30,000, 10,000) = 10,000. Federal + # itemized: 10,000 + 20,000 mortgage interest = 30,000 (above the 15,750 + # federal standard deduction, so the filer itemizes). + # Nebraska: 30,000 - 35,000 = -5,000, floored at 0. Taxable income takes the + # larger 8,600 standard deduction: 700,000 - 8,600 = 691,400. + period: 2025 + input: + filing_status: SINGLE + employment_income: 700_000 + real_estate_taxes: 30_000 + deductible_mortgage_interest: 20_000 + state_withheld_income_tax: 35_000 + local_income_tax: 0 + state_sales_tax: 0 + local_sales_tax: 0 + state_code: NE + output: + salt_deduction: 10_000 + itemized_taxable_income_deductions: 30_000 + ne_itemized_deductions: 0 + ne_taxable_income: 691_400 + +- name: A binding SALT cap does not shield income taxes below the cap + # 2024, single. SALT: min(8,000 income taxes + 5,000 real estate taxes, + # 10,000) = 10,000. Federal itemized: 10,000 + 15,000 mortgage interest = + # 25,000. Nebraska removes all 8,000 of income taxes: 25,000 - 8,000 = + # 17,000. + period: 2024 + input: + filing_status: SINGLE + employment_income: 100_000 + real_estate_taxes: 5_000 + deductible_mortgage_interest: 15_000 + state_withheld_income_tax: 8_000 + local_income_tax: 0 + state_sales_tax: 0 + local_sales_tax: 0 + state_code: NE + output: + salt_deduction: 10_000 + itemized_taxable_income_deductions: 25_000 + ne_itemized_deductions: 17_000 + +- name: Income taxes above the cap and above real estate taxes are removed in full + # Federal: 15,000 interest + 10,000 capped SALT = 25,000. Income taxes + # (12,000) exceed sales taxes (1,000): 25,000 - 12,000 = 13,000. + period: 2023 + input: + filing_status: SINGLE + deductible_interest_expense: 15_000 + salt_deduction: 10_000 + real_estate_taxes: 4_000 + state_withheld_income_tax: 12_000 + local_income_tax: 0 + state_sales_tax: 1_000 + local_sales_tax: 0 + state_code: NE + output: + ne_itemized_deductions: 13_000 + +- name: Income taxes equal to sales taxes count as sales taxes, so nothing is removed + # Income taxes 3,000 = sales taxes 2,000 + 1,000. Line 5a holds 3,000 either + # way; a tie counts as sales taxes. SALT: 3,000 + 5,000 real estate taxes = + # 8,000. Federal itemized: 8,000 + 15,000 mortgage interest = 23,000. + # Nebraska removes nothing: 23,000. + period: 2023 + input: + filing_status: SINGLE + employment_income: 100_000 + real_estate_taxes: 5_000 + deductible_mortgage_interest: 15_000 + state_withheld_income_tax: 3_000 + local_income_tax: 0 + state_sales_tax: 2_000 + local_sales_tax: 1_000 state_code: NE output: - ne_itemized_deductions: 3_000 + 7_000 + 6_000 + salt_deduction: 8_000 + itemized_taxable_income_deductions: 23_000 + ne_itemized_deductions: 23_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/tax/income/deductions/property_tax/nj_taking_property_tax_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/tax/income/deductions/property_tax/nj_taking_property_tax_deduction.yaml index 5615c00bc86..9e30951de47 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/tax/income/deductions/property_tax/nj_taking_property_tax_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/tax/income/deductions/property_tax/nj_taking_property_tax_deduction.yaml @@ -33,3 +33,174 @@ state_code: NJ output: nj_taking_property_tax_deduction: false + +- name: Deduction that moves taxable income into a higher NJ child tax credit bracket beats the $50 credit + # 2023 single rates: 1.4% to $20,000, 1.75% from $20,000 to $35,000. + # Tax on $30,500 = 280 + 10,500 x 1.75% = 463.75; on $27,800 = 280 + + # 7,800 x 1.75% = 416.50; saving 47.25 is below the $50 credit. + # The NJ child tax credit rises from $800 (over $30,000) to $1,000 (up to + # $30,000) for the one child: 47.25 + 200 = 247.25 > 50. + period: 2023 + absolute_error_margin: 0 + input: + people: + parent: + age: 35 + child: + age: 3 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child] + filing_status: SINGLE + nj_property_tax_deduction_eligible: true + nj_potential_property_tax_deduction: 2_700 + nj_taxable_income_before_property_tax_deduction: 30_500 + cdcc: 0 + households: + household: + members: [parent, child] + state_code: NJ + output: + nj_ctc_qualifying_children: 1 + nj_taking_property_tax_deduction: true + +- name: Same tax saving without a qualifying child keeps the $50 credit + period: 2023 + absolute_error_margin: 0 + input: + nj_property_tax_deduction_eligible: true + nj_potential_property_tax_deduction: 2_700 + nj_taxable_income_before_property_tax_deduction: 30_500 + filing_status: SINGLE + cdcc: 0 + state_code: NJ + output: + nj_taking_property_tax_deduction: false + +- name: Separate filer with a child gets no NJ child tax credit gain, so keeps the $50 credit + # Tax saving 463.75 - 416.50 = 47.25 < 50; a separate filer cannot claim the + # NJ child tax credit, so its bracket change adds nothing. + period: 2023 + absolute_error_margin: 0 + input: + people: + parent: + age: 35 + child: + age: 3 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child] + filing_status: SEPARATE + cohabitating_spouses: false + nj_property_tax_deduction_eligible: true + nj_potential_property_tax_deduction: 2_700 + nj_taxable_income_before_property_tax_deduction: 30_500 + cdcc: 0 + households: + household: + members: [parent, child] + state_code: NJ + output: + nj_ctc_qualifying_children: 1 + nj_ctc_eligible: false + nj_taking_property_tax_deduction: false + +- name: Deduction that raises the NJ child and dependent care credit rate beats the $50 credit + # Tax saving: (30,500 - 28,500) x 1.75% = 35. The NJ CDCC match rate rises + # from 40% (over $30,000) to 50% (up to $30,000) of the $600 federal + # credit: 35 + 60 = 95 > 50. + period: 2023 + absolute_error_margin: 0 + input: + nj_property_tax_deduction_eligible: true + nj_potential_property_tax_deduction: 2_000 + nj_taxable_income_before_property_tax_deduction: 30_500 + filing_status: SINGLE + cdcc: 600 + state_code: NJ + output: + nj_taking_property_tax_deduction: true + +- name: A small NJ child and dependent care credit gain does not beat the $50 credit + # 35 tax saving + 10% x $100 federal credit = 45 < 50. + period: 2023 + absolute_error_margin: 0 + input: + nj_property_tax_deduction_eligible: true + nj_potential_property_tax_deduction: 2_000 + nj_taxable_income_before_property_tax_deduction: 30_500 + filing_status: SINGLE + cdcc: 100 + state_code: NJ + output: + nj_taking_property_tax_deduction: false + +- name: Deduction that lands NJ taxable income exactly on $30,000 gets the 50% NJ CDCC rate + # Tax saving: 500 x 1.75% = 8.75. At $30,000 the NJ CDCC rate is 50%, not + # 40%: 8.75 + 10% x $600 = 68.75 > 50. + period: 2023 + absolute_error_margin: 0 + input: + nj_property_tax_deduction_eligible: true + nj_potential_property_tax_deduction: 500 + nj_taxable_income_before_property_tax_deduction: 30_500 + filing_status: SINGLE + cdcc: 600 + state_code: NJ + output: + nj_taking_property_tax_deduction: true + +- name: Renter with one child takes the deduction and gets the higher NJ child tax credit + # Wages $33,000 less $2,500 exemptions (1,000 personal + 1,500 dependent) + # = $30,500. Property tax: 18% x $15,000 rent = $2,700. Taking the + # deduction gives $27,800 taxable income, $416.50 tax and a $1,000 NJ + # child tax credit; the credit route gives $463.75 tax, an $800 child tax + # credit and the $50 property tax credit. + period: 2023 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 35 + employment_income: 33_000 + rent: 15_000 + child: + age: 3 + tax_units: + tax_unit: + members: [parent, child] + spm_units: + spm_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NJ + output: + nj_taxable_income_before_property_tax_deduction: 30_500 + nj_potential_property_tax_deduction: 2_700 + nj_taking_property_tax_deduction: true + nj_taxable_income: 27_800 + nj_main_income_tax: 416.50 + nj_ctc: 1_000 + nj_property_tax_credit: 0 + +- name: Cohabiting separate filer weighs the deduction against a $25 credit + # Tax saving 463.75 - 416.50 = 47.25. A separate filer who lives with + # the spouse gets half the $50 credit, $25, so the filer takes the + # deduction: 47.25 exceeds 25. + period: 2023 + absolute_error_margin: 0 + input: + nj_property_tax_deduction_eligible: true + nj_potential_property_tax_deduction: 2_700 + nj_taxable_income_before_property_tax_deduction: 30_500 + filing_status: SEPARATE + cohabitating_spouses: true + cdcc: 0 + state_code: NJ + output: + nj_taking_property_tax_deduction: true diff --git a/policyengine_us/variables/gov/states/ne/tax/income/deductions/ne_itemized_deductions.py b/policyengine_us/variables/gov/states/ne/tax/income/deductions/ne_itemized_deductions.py index 6205c08b1d3..2b974a7fca9 100644 --- a/policyengine_us/variables/gov/states/ne/tax/income/deductions/ne_itemized_deductions.py +++ b/policyengine_us/variables/gov/states/ne/tax/income/deductions/ne_itemized_deductions.py @@ -8,12 +8,30 @@ class ne_itemized_deductions(Variable): unit = USD definition_period = YEAR reference = ( + "https://nebraskalegislature.gov/laws/statutes.php?statute=77-2716.01", "https://revenue.nebraska.gov/files/doc/tax-forms/2021/f_1040n_booklet.pdf", "https://revenue.nebraska.gov/files/doc/2022_Ne_Individual_Income_Tax_Booklet_8-307-2022_final_5.pdf", ) defined_for = StateCode.NE def formula(tax_unit, period, parameters): - itm_deds_less_salt = tax_unit("itemized_deductions_less_salt", period) - capped_property_taxes = tax_unit("capped_property_taxes", period) - return itm_deds_less_salt + capped_property_taxes + # Neb. Rev. Stat. 77-2716.01(4): federal itemized deductions "except + # for the amount for state or local income taxes included in federal + # itemized deductions before any federal disallowance". + # Form 1040N line 7: federal Schedule A line 17. + federal_itemized = tax_unit("itemized_taxable_income_deductions", period) + # Form 1040N line 8: the income taxes on Schedule A line 5a, even when + # the federal SALT cap limits line 5e, so they are removed in full. + # Line 5a holds income taxes or general sales taxes, whichever is + # larger (state_and_local_sales_or_income_tax); a tie counts as sales + # taxes, and then nothing is removed. + income_taxes = add( + tax_unit, period, ["state_withheld_income_tax", "local_income_tax"] + ) + sales_taxes = add(tax_unit, period, ["state_sales_tax", "local_sales_tax"]) + claims_income_taxes = income_taxes > sales_taxes + income_taxes_removed = where(claims_income_taxes, income_taxes, 0) + # Form 1040N line 9 (line 7 minus line 8) can be negative, but line 10 + # takes the larger of it and the standard deduction, so the floor + # changes no tax. + return max_(0, federal_itemized - income_taxes_removed) diff --git a/policyengine_us/variables/gov/states/nj/tax/income/credits/ctc/nj_ctc.py b/policyengine_us/variables/gov/states/nj/tax/income/credits/ctc/nj_ctc.py index ad5080093f3..f700c038d1a 100644 --- a/policyengine_us/variables/gov/states/nj/tax/income/credits/ctc/nj_ctc.py +++ b/policyengine_us/variables/gov/states/nj/tax/income/credits/ctc/nj_ctc.py @@ -22,12 +22,7 @@ def formula(tax_unit, period, parameters): taxable_income = tax_unit("nj_taxable_income", period) amount_per_qualifying_child = p.amount.calc(taxable_income) - # Get the number of eligible children dependents - person = tax_unit.members - age_eligible = person("age", period) < p.age_limit - dependent = person("is_tax_unit_dependent", period) - age_eligible_dependent = age_eligible & dependent - count_eligible = tax_unit.sum(age_eligible_dependent) + count_eligible = tax_unit("nj_ctc_qualifying_children", period) # Calculate total child tax credit return count_eligible * amount_per_qualifying_child diff --git a/policyengine_us/variables/gov/states/nj/tax/income/credits/ctc/nj_ctc_qualifying_children.py b/policyengine_us/variables/gov/states/nj/tax/income/credits/ctc/nj_ctc_qualifying_children.py new file mode 100644 index 00000000000..272566104ab --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/tax/income/credits/ctc/nj_ctc_qualifying_children.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class nj_ctc_qualifying_children(Variable): + value_type = int + entity = TaxUnit + label = "New Jersey child tax credit qualifying children" + unit = "child" + definition_period = YEAR + reference = ( + "https://law.justia.com/codes/new-jersey/2022/title-54a/section-54a-4-17-1/", + "https://www.state.nj.us/treasury/taxation/pdf/current/1040i.pdf#page=46", + ) + defined_for = StateCode.NJ + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.nj.tax.income.credits.ctc + person = tax_unit.members + age_eligible = person("age", period) < p.age_limit + dependent = person("is_tax_unit_dependent", period) + return tax_unit.sum(age_eligible & dependent) diff --git a/policyengine_us/variables/gov/states/nj/tax/income/property_tax/nj_taking_property_tax_deduction.py b/policyengine_us/variables/gov/states/nj/tax/income/property_tax/nj_taking_property_tax_deduction.py index 9bda5c4618b..5193d04a5da 100644 --- a/policyengine_us/variables/gov/states/nj/tax/income/property_tax/nj_taking_property_tax_deduction.py +++ b/policyengine_us/variables/gov/states/nj/tax/income/property_tax/nj_taking_property_tax_deduction.py @@ -8,14 +8,19 @@ class nj_taking_property_tax_deduction(Variable): unit = USD definition_period = YEAR reference = ( - "https://law.justia.com/codes/new-jersey/2022/title-54a/section-54a-3a-17/" + "https://law.justia.com/codes/new-jersey/2022/title-54a/section-54a-3a-17/", + "https://law.justia.com/codes/new-jersey/2022/title-54a/section-54a-3a-20/", + # The NJ child tax credit and the NJ child and dependent care credit + # are refundable and both depend on NJ taxable income. + "https://law.justia.com/codes/new-jersey/2022/title-54a/section-54a-4-17-1/", + "https://www.state.nj.us/treasury/taxation/pdf/current/1040i.pdf#page=46", ) defined_for = "nj_property_tax_deduction_eligible" def formula(tax_unit, period, parameters): p = parameters(period).gov.states.nj.tax.income.main - # follows NJ-1040 form Worksheet H + # Worksheet H compares the tax saving with the credit; this also counts the change in the refundable NJ CTC and CDCC (below). deduction = tax_unit("nj_potential_property_tax_deduction", period) # calculate taxes without deduction @@ -70,5 +75,25 @@ def formula(tax_unit, period, parameters): cohabitating = tax_unit("cohabitating_spouses", period) credit_amount = credit_amount / (1 + separate * cohabitating) + # The deduction also lowers NJ taxable income for the refundable NJ + # child tax credit and NJ child and dependent care credit, whose + # amounts depend on it, so its benefit includes their change. + p_credits = parameters(period).gov.states.nj.tax.income.credits + ctc_children = tax_unit("nj_ctc_qualifying_children", period) * tax_unit( + "nj_ctc_eligible", period + ) + ctc_gain = ctc_children * ( + p_credits.ctc.amount.calc(taxable_income_after_deduction) + - p_credits.ctc.amount.calc(taxable_income_before_deduction) + ) + federal_cdcc = tax_unit("cdcc", period) + cdcc_gain = federal_cdcc * ( + p_credits.cdcc.rate.calc(taxable_income_after_deduction, right=True) + - p_credits.cdcc.rate.calc(taxable_income_before_deduction, right=True) + ) + deduction_benefit = ( + taxes_without_deduction - taxes_with_deduction + ctc_gain + cdcc_gain + ) + # choose between taxable income deduction and refundable credit - return (taxes_without_deduction - taxes_with_deduction) > credit_amount + return deduction_benefit > credit_amount