PocketAccountant / src /engine /us_tax.py
eldinosaur's picture
English-default UI + bilingual agent + USA tax support (Schedule C/SE/federal) and expanded US+EN regulation corpus
56ed47e verified
Raw
History Blame Contribute Delete
5.56 kB
"""USA bonus mode — federal taxes for a self-employed Schedule-C filer.
Aimed at Mexican freelancers earning USD and US-based gig workers. Covers:
* Schedule-C net profit (gross − business expenses);
* Self-employment tax (Schedule SE): 15.3% on 92.35% of net profit, with the
Social-Security portion capped at the annual wage base;
* Federal income tax via the progressive single-filer brackets;
* A simple quarterly estimated-tax figure (Form 1040-ES).
Like the Mexican side, every number comes from versioned tables in ``tax_tables``.
"""
from __future__ import annotations
from decimal import Decimal
from .money import D, money
from .result import CalcResult
from .tax_tables import (
SE_MEDICARE_RATE,
SE_MINIMUM_NET_EARNINGS,
SE_NET_EARNINGS_FACTOR,
SE_SOCIAL_SECURITY_RATE,
SE_SOCIAL_SECURITY_WAGE_BASE_2024,
US_FEDERAL_INCOME_SINGLE_2024,
US_STANDARD_DEDUCTION_SINGLE_2024,
TaxTable,
)
def schedule_c_net_profit(gross_income, expenses) -> CalcResult:
gross, exp = D(gross_income), D(expenses)
net = gross - exp
return CalcResult(
amount=money(net),
label="Schedule C net profit",
breakdown=[("Gross income", money(gross)), ("Business expenses", money(exp))],
source="IRS Schedule C (Form 1040)",
)
def self_employment_tax(
net_profit, wage_base: Decimal = SE_SOCIAL_SECURITY_WAGE_BASE_2024
) -> CalcResult:
"""Schedule SE: 12.4% SS (capped) + 2.9% Medicare on 92.35% of net profit."""
net = D(net_profit)
net_earnings = net * SE_NET_EARNINGS_FACTOR
if net_earnings < SE_MINIMUM_NET_EARNINGS:
return CalcResult(
amount=money(0),
label="Self-employment tax",
breakdown=[("Net earnings from SE", money(net_earnings))],
source="IRS Schedule SE",
notes=[f"Below ${SE_MINIMUM_NET_EARNINGS} — no SE tax due."],
)
ss_base = min(net_earnings, wage_base)
social_security = ss_base * SE_SOCIAL_SECURITY_RATE
medicare = net_earnings * SE_MEDICARE_RATE
total = social_security + medicare
return CalcResult(
amount=money(total),
label="Self-employment tax",
breakdown=[
("Net earnings (92.35% of profit)", money(net_earnings)),
("Social Security base (capped)", money(ss_base)),
("Social Security (12.4%)", money(social_security)),
("Medicare (2.9%)", money(medicare)),
],
source="IRS Schedule SE",
notes=["Half of this is deductible against income tax."],
)
def federal_income_tax(
taxable_income, table: TaxTable = US_FEDERAL_INCOME_SINGLE_2024
) -> CalcResult:
"""Progressive federal income tax for a single filer."""
base = D(taxable_income)
if base <= 0:
return CalcResult(
amount=money(0),
label="Federal income tax (single)",
breakdown=[("Taxable income", money(base))],
source=table.source,
effective_year=table.effective_year,
)
bracket = next(b for b in table.brackets if b.contains(base))
excess = base - bracket.lower
tax = bracket.fixed_fee + excess * bracket.rate
return CalcResult(
amount=money(tax),
label="Federal income tax (single)",
breakdown=[
("Taxable income", money(base)),
("Bracket floor", money(bracket.lower)),
("Excess over floor", money(excess)),
("Marginal rate", bracket.rate),
("Tax at lower brackets", money(bracket.fixed_fee)),
],
source=table.source,
effective_year=table.effective_year,
)
def us_annual_estimate(gross_income, expenses,
standard_deduction=US_STANDARD_DEDUCTION_SINGLE_2024) -> dict:
"""Full self-employed estimate for a single filer, in the right order.
net profit → SE tax → taxable income (net − ½ SE tax − standard deduction)
→ federal income tax → quarterly estimate. Simplified (ignores QBI/state); a
realistic ballpark, not a filing. Returns the component CalcResults plus the
derived taxable income and the combined annual total.
"""
net = schedule_c_net_profit(gross_income, expenses)
se = self_employment_tax(net.amount)
half_se = money(se.amount / 2)
taxable = net.amount - half_se - D(standard_deduction)
if taxable < 0:
taxable = D(0)
fed = federal_income_tax(taxable)
quarterly = quarterly_estimated_tax(fed.amount, se.amount)
total = money(se.amount + fed.amount)
return {
"net_profit": net,
"self_employment_tax": se,
"half_se_deduction": half_se,
"standard_deduction": money(standard_deduction),
"taxable_income": money(taxable),
"federal_income_tax": fed,
"quarterly_estimated_tax": quarterly,
"total_annual_tax": total,
}
def quarterly_estimated_tax(annual_income_tax, annual_se_tax) -> CalcResult:
"""Form 1040-ES: split the projected annual liability into four payments."""
total = D(annual_income_tax) + D(annual_se_tax)
quarter = total / D(4)
return CalcResult(
amount=money(quarter),
label="Quarterly estimated tax (1040-ES)",
breakdown=[
("Projected income tax", money(D(annual_income_tax))),
("Projected SE tax", money(D(annual_se_tax))),
("Annual total", money(total)),
],
source="IRS Form 1040-ES",
notes=["Four equal payments; due quarterly (Apr, Jun, Sep, Jan)."],
)