@@ -381,7 +381,33 @@ def preprocess_puf(puf: pd.DataFrame) -> pd.DataFrame:
381381 puf ["unreported_payroll_tax" ] = puf .E09800
382382 # Ignore f2441 (AMT form attached)
383383 # Ignore cmbtp (estimate of AMT income not in AGI)
384- # Ignore k1bx14s and k1bx14p (partner self-employment income included in partnership and S-corp income)
384+
385+ # Partnership self-employment income from Schedule K-1 Box 14
386+ # This is the portion of partnership income subject to SE tax (general partners)
387+ # Derived from total SE income minus Schedule C and Schedule F income
388+ # Based on Yale Budget Lab's Tax-Data process_puf.R approach:
389+ # E30400 = taxpayer's TAXABLE SE income (already * 0.9235)
390+ # E30500 = spouse's TAXABLE SE income (already * 0.9235)
391+ # E00900 = Schedule C net profit/loss (gross)
392+ # E02100 = Schedule F farm income (gross)
393+ # Since E30400/E30500 are post-deduction (taxable), we gross them up
394+ # by dividing by 0.9235 before subtracting Sch C/F.
395+ # PolicyEngine applies the 0.9235 factor itself in taxable_self_employment_income.
396+ SE_DEDUCTION_FACTOR = 0.9235 # 1 - 0.5 * 0.153 (half of SE tax rate)
397+ taxable_se = puf ["E30400" ].fillna (0 ) + puf ["E30500" ].fillna (0 )
398+ gross_se = taxable_se / SE_DEDUCTION_FACTOR
399+ schedule_c_f_income = puf ["E00900" ].fillna (0 ) + puf ["E02100" ].fillna (0 )
400+ # Only compute when there's partnership activity (net partnership income != 0)
401+ has_partnership = (
402+ puf ["E25940" ].fillna (0 )
403+ + puf ["E25980" ].fillna (0 )
404+ - puf ["E25920" ].fillna (0 )
405+ - puf ["E25960" ].fillna (0 )
406+ ) != 0
407+ partnership_se = np .where (
408+ has_partnership , gross_se - schedule_c_f_income , 0
409+ )
410+ puf ["partnership_se_income" ] = partnership_se
385411
386412 # --- Qualified Business Income Deduction (QBID) simulation ---
387413 w2 , ubia = simulate_w2_and_ubia_from_puf (puf , seed = 42 )
@@ -491,6 +517,7 @@ def preprocess_puf(puf: pd.DataFrame) -> pd.DataFrame:
491517 "business_is_sstb" ,
492518 "deductible_mortgage_interest" ,
493519 "partnership_s_corp_income" ,
520+ "partnership_se_income" ,
494521 "qualified_reit_and_ptp_income" ,
495522 "qualified_bdc_income" ,
496523]
@@ -544,6 +571,13 @@ def generate(self):
544571 for variable in system .variables
545572 }
546573
574+ # Filter FINANCIAL_SUBSET to only include variables defined in
575+ # policyengine-us. This allows us-data to be updated before or after
576+ # policyengine-us without breaking.
577+ self .available_financial_vars = [
578+ v for v in FINANCIAL_SUBSET if v in self .variable_to_entity
579+ ]
580+
547581 VARIABLES = [
548582 "person_id" ,
549583 "tax_unit_id" ,
@@ -563,7 +597,7 @@ def generate(self):
563597 "is_tax_unit_head" ,
564598 "is_tax_unit_spouse" ,
565599 "is_tax_unit_dependent" ,
566- ] + FINANCIAL_SUBSET
600+ ] + self . available_financial_vars
567601
568602 self .holder = {variable : [] for variable in VARIABLES }
569603
@@ -607,7 +641,7 @@ def generate(self):
607641 def add_tax_unit (self , row , tax_unit_id ):
608642 self .holder ["tax_unit_id" ].append (tax_unit_id )
609643
610- for key in FINANCIAL_SUBSET :
644+ for key in self . available_financial_vars :
611645 if self .variable_to_entity [key ] == "tax_unit" :
612646 self .holder [key ].append (row [key ])
613647
@@ -649,7 +683,7 @@ def add_filer(self, row, tax_unit_id):
649683 row ["interest_deduction" ]
650684 )
651685
652- for key in FINANCIAL_SUBSET :
686+ for key in self . available_financial_vars :
653687 if key == "deductible_mortgage_interest" :
654688 # Skip this one- we are adding it artificially at the filer level.
655689 continue
@@ -682,7 +716,7 @@ def add_spouse(self, row, tax_unit_id):
682716
683717 self .holder ["deductible_mortgage_interest" ].append (0 )
684718
685- for key in FINANCIAL_SUBSET :
719+ for key in self . available_financial_vars :
686720 if key == "deductible_mortgage_interest" :
687721 # Skip this one- we are adding it artificially at the filer level.
688722 continue
@@ -706,7 +740,7 @@ def add_dependent(self, row, tax_unit_id, dependent_id):
706740
707741 self .holder ["deductible_mortgage_interest" ].append (0 )
708742
709- for key in FINANCIAL_SUBSET :
743+ for key in self . available_financial_vars :
710744 if key == "deductible_mortgage_interest" :
711745 # Skip this one- we are adding it artificially at the filer level.
712746 continue
0 commit comments