Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/add-sstb-self-employment-income.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `sstb_self_employment_income` and split QBID into non-SSTB and SSTB components per IRC §199A(d). Mixed SSTB/non-SSTB wage-limited cases can also provide `sstb_w2_wages_from_qualified_business` and `sstb_unadjusted_basis_qualified_property` to match Form 8995-A's separate SSTB wage/UBIA inputs.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ values:
0000-01-01:
- employment_income
- self_employment_income
- sstb_self_employment_income
- partnership_s_corp_income
- gi_cash_assistance
- farm_income
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ values:
2010-01-01:
- irs_employment_income
- self_employment_income
- sstb_self_employment_income
- partnership_s_corp_income
- farm_income
- farm_rent_income
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,102 @@
# REIT/PTP component = 0.20 * 25k = $5,000.
# Total = $15,000.
qbid_amount: 15_000

# Mixed SSTB / non-SSTB tests (Form 8995-A, columns A vs B)
- name: Mixed SSTB and non-SSTB above threshold - SSTB phased out, non-SSTB capped
period: 2024
input:
qualified_business_income: 50_000
sstb_qualified_business_income: 50_000
w2_wages_from_qualified_business: 100_000
unadjusted_basis_qualified_property: 0
taxable_income_less_qbid: 300_000
qualified_reit_and_ptp_income: 0
business_is_sstb: false
filing_status: SINGLE
output:
# Single 2024 threshold $191,950, length $50,000.
# Reduction rate = min(1, (300k - 191.95k)/50k) = 1 → applicable rate = 0.
# Non-SSTB component:
# qbid_max = 0.20 * 50k = $10,000
# wage_cap = 0.50 * 100k = $50,000
# min($10k, $50k) = $10,000.
# SSTB component: 0 (applicable rate = 0).
# Total = $10,000.
qbid_amount: 10_000

- name: Mixed SSTB and non-SSTB below threshold - both get full 20% deduction
period: 2024
input:
qualified_business_income: 50_000
sstb_qualified_business_income: 50_000
w2_wages_from_qualified_business: 0
unadjusted_basis_qualified_property: 0
taxable_income_less_qbid: 100_000
qualified_reit_and_ptp_income: 0
business_is_sstb: false
filing_status: SINGLE
output:
# Below threshold, so SSTB phaseout does not apply and W-2/UBIA limits do not bind.
# Non-SSTB: 0.20 * 50k = $10,000.
# SSTB: 0.20 * 50k = $10,000.
# Total = $20,000.
qbid_amount: 20_000

- name: Mixed SSTB and non-SSTB in phase-in range with separate allocable wages
absolute_error_margin: 0.01
period: 2024
input:
qualified_business_income: 100_000
sstb_qualified_business_income: 100_000
w2_wages_from_qualified_business: 20_000
sstb_w2_wages_from_qualified_business: 10_000
unadjusted_basis_qualified_property: 0
sstb_unadjusted_basis_qualified_property: 0
taxable_income_less_qbid: 200_000
qualified_reit_and_ptp_income: 0
business_is_sstb: false
filing_status: SINGLE
output:
# Single 2024 threshold $191,950, length $50,000.
# Reduction rate = (200k - 191.95k) / 50k = 0.161; applicable rate = 0.839.
# Non-SSTB W-2 wages = 10k => cap = 5k.
# Non-SSTB deduction = 20k - 0.161 * (20k - 5k) = 17,585.00.
# SSTB W-2 wages = 10k => applicable-percentage cap = 0.839 * 5k = 4,195.
# SSTB deduction = 16,780 - 0.161 * (16,780 - 4,195) = 14,753.82.
# Total = 32,338.82.
qbid_amount: 32_338.82

- name: Only SSTB QBI fully phased out above threshold
period: 2024
input:
qualified_business_income: 0
sstb_qualified_business_income: 100_000
w2_wages_from_qualified_business: 0
unadjusted_basis_qualified_property: 0
taxable_income_less_qbid: 300_000
qualified_reit_and_ptp_income: 0
business_is_sstb: false
filing_status: SINGLE
output:
# Above threshold; SSTB applicable rate = 0; non-SSTB QBI = 0.
qbid_amount: 0

- name: Only SSTB QBI in phase-in range
period: 2024
input:
qualified_business_income: 0
sstb_qualified_business_income: 100_000
w2_wages_from_qualified_business: 50_000
unadjusted_basis_qualified_property: 0
taxable_income_less_qbid: 216_950
qualified_reit_and_ptp_income: 0
business_is_sstb: false
filing_status: SINGLE
output:
# Reduction rate = (216_950 - 191_950) / 50_000 = 0.5 → applicable rate = 0.5
# Reduced QBI = 50_000; reduced W-2 = 25_000.
# qbid_max (reduced) = 0.20 * 50_000 = 10_000.
# wage_cap (reduced) = 0.50 * 25_000 = 12_500.
# min(10_000, 12_500) = 10_000.
qbid_amount: 10_000
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,26 @@
self_employed_pension_contribution_ald_person: 0
output:
qualified_business_income: 9_000

- name: SSTB SE income excluded; deductions pro-rated to non-SSTB
period: 2026
input:
self_employment_income: 30_000
sstb_self_employment_income: 70_000
self_employment_tax_ald_person: 1_000
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
output:
# Non-SSTB share = 30_000 / 100_000 = 0.3
# Non-SSTB QBI = 30_000 - 0.3 * 1_000 = 29_700
qualified_business_income: 29_700

- name: Only SSTB SE income, non-SSTB QBI is zero
period: 2026
input:
sstb_self_employment_income: 100_000
self_employment_tax_ald_person: 1_000
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
output:
qualified_business_income: 0
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,105 @@
qualified_business_income: 1_000
output:
qualified_business_income_deduction: 2_000

- name: Deduction floor in effect with SSTB-only income
absolute_error_margin: 0.01
period: 2026
input:
people:
person1:
sstb_self_employment_income: 1_000
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
qbid_amount: 200
is_tax_unit_head: true
tax_units:
tax_unit:
members: [person1]
taxable_income_less_qbid: 600
adjusted_net_capital_gain: 0
families:
family:
members: [person1]
spm_units:
spm_unit:
members: [person1]
households:
household:
members: [person1]
state_fips: 6
output:
qualified_business_income_deduction: 400

# Integration test: doctor (SSTB) with rental property (non-SSTB) above threshold.
# Demonstrates the §199A(d)(3) phaseout reaching only the SSTB component
# while the non-SSTB business still receives the W-2 capped deduction.
- name: Mixed SSTB and non-SSTB above threshold
absolute_error_margin: 1
period: 2025
input:
people:
person1:
employment_income: 400_000
self_employment_income: 50_000
sstb_self_employment_income: 50_000
w2_wages_from_qualified_business: 100_000
# Zero out QBI deductions so the test isolates SSTB / non-SSTB routing
# rather than SE-tax / health-insurance / pension ALD pro-rating.
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
is_tax_unit_head: true
tax_units:
tax_unit:
members: [person1]
families:
family:
members: [person1]
spm_units:
spm_unit:
members: [person1]
households:
household:
members: [person1]
state_fips: 6
output:
# Single 2025 threshold $197,300, length $50,000.
# Taxable income is far above the phaseout, so applicable rate = 0.
# Non-SSTB QBI = $50,000; W-2 cap = 0.50 * $100,000 = $50,000.
# Non-SSTB component = min(20% * $50k, $50k) = $10,000.
# SSTB QBI = $50,000; SSTB component fully phased out = $0.
qualified_business_income_deduction: 10_000

- name: Pure SSTB below threshold gets full 20 percent deduction
absolute_error_margin: 1
period: 2025
input:
people:
person1:
employment_income: 50_000
business_is_qualified: false
sstb_self_employment_income: 30_000
# Zero out QBI deductions to isolate SSTB routing.
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
is_tax_unit_head: true
tax_units:
tax_unit:
members: [person1]
families:
family:
members: [person1]
spm_units:
spm_unit:
members: [person1]
households:
household:
members: [person1]
state_fips: 6
output:
# Below the $197,300 single threshold so the SSTB phaseout does not apply.
# SSTB QBI component = 0.20 * $30,000 = $6,000.
qualified_business_income_deduction: 6_000
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
- name: SSTB SE income only, no deductions
period: 2026
input:
sstb_self_employment_income: 100_000
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
output:
sstb_qualified_business_income: 100_000

- name: SSTB SE income with would_be_qualified flag false
period: 2026
input:
sstb_self_employment_income: 100_000
sstb_self_employment_income_would_be_qualified: false
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
output:
sstb_qualified_business_income: 0

- name: SSTB SE income still counts when business_is_qualified is false
period: 2026
input:
business_is_qualified: false
sstb_self_employment_income: 100_000
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
output:
sstb_qualified_business_income: 100_000

- name: Mixed SSTB and non-SSTB SE income, deductions pro-rated by gross share
period: 2026
input:
self_employment_income: 30_000
sstb_self_employment_income: 70_000
self_employment_tax_ald_person: 1_000
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
output:
# SSTB share = 70_000 / 100_000 = 0.7
# SSTB QBI = 70_000 - 0.7 * 1_000 = 69_300
sstb_qualified_business_income: 69_300

- name: No SSTB SE income returns zero
period: 2026
input:
self_employment_income: 50_000
self_employment_tax_ald_person: 1_000
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
output:
sstb_qualified_business_income: 0
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,13 @@
# Both Schedule C ($50k) and K-1 Box 14 ($30k) are subject to SE tax.
# 80_000 * (1 - 0.5 * 0.153) = 80_000 * 0.9235 = 73_880
taxable_self_employment_income: 73_880

- name: SSTB self-employment income is subject to SE tax.
period: 2024
input:
self_employment_income: 50_000
sstb_self_employment_income: 30_000
output:
# Both non-SSTB ($50k) and SSTB ($30k) Schedule C income are subject to SE tax.
# 80_000 * (1 - 0.5 * 0.153) = 80_000 * 0.9235 = 73_880
taxable_self_employment_income: 73_880
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,14 @@
state_code: MO
output:
mo_business_income_deduction: 0

- name: 2023 SSTB-only qualified business income
period: 2023
input:
sstb_self_employment_income: 10_000
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
state_code: MO
output:
mo_business_income_deduction: 2_000
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@
output:
household_market_income: 50_000

- name: SSTB self-employment income is market income
period: 2026
input:
people:
person:
sstb_self_employment_income: 50_000
households:
household:
members: [person]
output:
household_market_income: 50_000

- name: Employment income plus UC does not double count
period: 2026
input:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,32 @@
taxsim_sbusinc: 50000
taxsim_scorp: 150000

- name: SSTB self-employment income contributes to TAXSIM QBI outputs
period: 2024
input:
people:
head:
age: 50
sstb_self_employment_income: 100000
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
is_tax_unit_head: true
spouse:
age: 48
sstb_self_employment_income: 50000
self_employment_tax_ald_person: 0
self_employed_health_insurance_ald_person: 0
self_employed_pension_contribution_ald_person: 0
is_tax_unit_spouse: true
tax_units:
tax_unit:
members: [head, spouse]
filing_status: JOINT
output:
taxsim_pbusinc: 100000
taxsim_sbusinc: 50000

- name: State code NY - TAXSIM outputs
period: 2024
input:
Expand Down
4 changes: 3 additions & 1 deletion policyengine_us/variables/contrib/taxsim/taxsim_pbusinc.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class taxsim_pbusinc(Variable):

def formula(tax_unit, period, parameters):
person = tax_unit.members
qbi = person("qualified_business_income", period)
qbi = person("qualified_business_income", period) + person(
"sstb_qualified_business_income", period
)
is_head = person("is_tax_unit_head", period)
return tax_unit.sum(qbi * is_head)
Loading
Loading