diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..54467f508ea 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: minor + changes: + added: + - Trump tip income tax exempt. diff --git a/policyengine_us/parameters/gov/contrib/tax_exempt/in_effect.yaml b/policyengine_us/parameters/gov/contrib/tax_exempt/in_effect.yaml new file mode 100644 index 00000000000..5d53c19cdc0 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/tax_exempt/in_effect.yaml @@ -0,0 +1,8 @@ +description: Various income sources are exempt from federal income or payroll tax, if this is true. +metadata: + unit: bool + period: year + label: Tax exemptions in effect + +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/tax_exempt/overtime/income_tax_exempt.yaml b/policyengine_us/parameters/gov/contrib/tax_exempt/overtime/income_tax_exempt.yaml new file mode 100644 index 00000000000..3d65573d2f0 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/tax_exempt/overtime/income_tax_exempt.yaml @@ -0,0 +1,8 @@ +description: The propsal to exempt overtime income from income tax applies, if this is true. +metadata: + unit: bool + period: year + label: Overtime income, income tax exempt + +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/tax_exempt/overtime/payroll_tax_exempt.yaml b/policyengine_us/parameters/gov/contrib/tax_exempt/overtime/payroll_tax_exempt.yaml new file mode 100644 index 00000000000..82ad0c0e50f --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/tax_exempt/overtime/payroll_tax_exempt.yaml @@ -0,0 +1,8 @@ +description: The propsal to exempt overtime income from payroll tax applies, if this is true. +metadata: + unit: bool + period: year + label: Overtime income payroll tax exempt + +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/tax_exempt/tip_income/income_tax_exempt.yaml b/policyengine_us/parameters/gov/contrib/tax_exempt/tip_income/income_tax_exempt.yaml new file mode 100644 index 00000000000..bce249074c3 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/tax_exempt/tip_income/income_tax_exempt.yaml @@ -0,0 +1,9 @@ + +description: The propsal to exempt tip income from payroll tax applies, if this is true. +metadata: + unit: bool + period: year + label: Tip income, income tax exempt + +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/tax_exempt/tip_income/payroll_tax_exempt.yaml b/policyengine_us/parameters/gov/contrib/tax_exempt/tip_income/payroll_tax_exempt.yaml new file mode 100644 index 00000000000..c2300f22d81 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/tax_exempt/tip_income/payroll_tax_exempt.yaml @@ -0,0 +1,8 @@ +description: The propsal to exempt tip income from payroll tax applies, if this is true. +metadata: + unit: bool + period: year + label: Tip income payroll tax exempt + +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/irs/gross_income/sources.yaml b/policyengine_us/parameters/gov/irs/gross_income/sources.yaml index adff19473a1..1e3306d12cd 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/sources.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/sources.yaml @@ -23,6 +23,7 @@ values: - miscellaneous_income # Listed separately on 1040 line 8g. - ak_permanent_fund_dividend + metadata: unit: list period: year diff --git a/policyengine_us/reforms/reforms.py b/policyengine_us/reforms/reforms.py index 890279dd6a7..3299fb7f791 100644 --- a/policyengine_us/reforms/reforms.py +++ b/policyengine_us/reforms/reforms.py @@ -53,6 +53,10 @@ from .harris.capital_gains import ( create_harris_capital_gains_reform, ) +from .tax_exempt.tax_exempt_reform import ( + create_tax_exempt_reform, +) + from policyengine_core.reforms import Reform import warnings @@ -126,6 +130,7 @@ def create_structural_reforms_from_parameters(parameters, period): harris_capital_gains = create_harris_capital_gains_reform( parameters, period ) + tip_income_tax_exempt = create_tax_exempt_reform(parameters, period) reforms = [ afa_reform, @@ -153,6 +158,7 @@ def create_structural_reforms_from_parameters(parameters, period): family_security_act_2024_eitc, repeal_dependent_exemptions, harris_capital_gains, + tip_income_tax_exempt, ] reforms = tuple(filter(lambda x: x is not None, reforms)) diff --git a/policyengine_us/reforms/tax_exempt/__init__.py b/policyengine_us/reforms/tax_exempt/__init__.py new file mode 100644 index 00000000000..ac6dbccddfb --- /dev/null +++ b/policyengine_us/reforms/tax_exempt/__init__.py @@ -0,0 +1,3 @@ +from .tax_exempt_reform import ( + create_tax_exempt_reform, +) diff --git a/policyengine_us/reforms/tax_exempt/tax_exempt_reform.py b/policyengine_us/reforms/tax_exempt/tax_exempt_reform.py new file mode 100644 index 00000000000..60b496f189d --- /dev/null +++ b/policyengine_us/reforms/tax_exempt/tax_exempt_reform.py @@ -0,0 +1,86 @@ +from policyengine_us.model_api import * + + +def create_tax_exempt() -> Reform: + class irs_gross_income(Variable): + value_type = float + entity = Person + label = "Gross income" + unit = USD + documentation = ( + "Gross income, as defined in the Internal Revenue Code." + ) + definition_period = YEAR + reference = "https://www.law.cornell.edu/uscode/text/26/61" + + def formula(person, period, parameters): + sources = parameters(period).gov.irs.gross_income.sources + total = 0 + not_dependent = ~person("is_tax_unit_dependent", period) + for source in sources: + # Add positive values only - losses are deducted later. + total += not_dependent * max_(0, add(person, period, [source])) + exempt_income = 0 + p = parameters(period).gov.contrib.tax_exempt + if p.tip_income.income_tax_exempt: + tip_income = person("tip_income", period) + exempt_income += tip_income + if p.overtime.income_tax_exempt: + exempt_income += person("overtime_income", period) + return max_(total - exempt_income, 0) + + class payroll_tax_gross_wages(Variable): + value_type = float + entity = Person + label = "Gross wages and salaries for payroll taxes" + definition_period = YEAR + unit = USD + + def formula(person, period, parameters): + income = person("irs_employment_income", period) + p = parameters(period).gov.contrib.tax_exempt + exempt_income = 0 + if p.tip_income.payroll_tax_exempt: + exempt_income += person("tip_income", period) + if p.overtime.payroll_tax_exempt: + exempt_income += person("overtime_income", period) + return max_(income - exempt_income, 0) + + class tip_income(Variable): + value_type = float + entity = Person + label = "Tip income" + unit = USD + definition_period = YEAR + reference = "https://www.law.cornell.edu/cfr/text/26/31.3402(k)-1" + + class overtime_income(Variable): + value_type = float + entity = Person + label = "Income from overtime hours worked" + unit = USD + definition_period = YEAR + + class reform(Reform): + def apply(self): + self.update_variable(irs_gross_income) + self.update_variable(tip_income) + self.update_variable(payroll_tax_gross_wages) + self.update_variable(overtime_income) + + return reform + + +def create_tax_exempt_reform(parameters, period, bypass: bool = False): + if bypass: + return create_tax_exempt() + + p = parameters(period).gov.contrib.tax_exempt + + if p.in_effect: + return create_tax_exempt() + else: + return None + + +tax_exempt_reform = create_tax_exempt_reform(None, None, bypass=True) diff --git a/policyengine_us/tests/policy/contrib/tax_exempt/tax_exempt_reform.yaml b/policyengine_us/tests/policy/contrib/tax_exempt/tax_exempt_reform.yaml new file mode 100644 index 00000000000..58d27df5e4c --- /dev/null +++ b/policyengine_us/tests/policy/contrib/tax_exempt/tax_exempt_reform.yaml @@ -0,0 +1,62 @@ +- name: Overtime and tips are excluded from income and payroll tax + period: 2024 + reforms: policyengine_us.reforms.tax_exempt.tax_exempt_reform.tax_exempt_reform + input: + gov.contrib.tax_exempt.in_effect: true + gov.contrib.tax_exempt.overtime.payroll_tax_exempt: true + gov.contrib.tax_exempt.overtime.income_tax_exempt: true + gov.contrib.tax_exempt.tip_income.payroll_tax_exempt: true + gov.contrib.tax_exempt.tip_income.income_tax_exempt: true + overtime_income: 10_000 + tip_income: 10_000 + irs_employment_income: 30_000 + output: + irs_gross_income: 10_000 + payroll_tax_gross_wages: 10_000 + +- name: Reform does not apply + period: 2024 + input: + gov.contrib.tax_exempt.in_effect: false + gov.contrib.tax_exempt.overtime.payroll_tax_exempt: true + gov.contrib.tax_exempt.overtime.income_tax_exempt: true + gov.contrib.tax_exempt.tip_income.payroll_tax_exempt: true + gov.contrib.tax_exempt.tip_income.income_tax_exempt: true + # overtime_income: 10_000 + # tip_income: 10_000 + irs_employment_income: 30_000 + output: + irs_gross_income: 30_000 + payroll_tax_gross_wages: 30_000 + +- name: Overtime and tips are excluded from income but not payroll tax + period: 2024 + reforms: policyengine_us.reforms.tax_exempt.tax_exempt_reform.tax_exempt_reform + input: + gov.contrib.tax_exempt.in_effect: true + gov.contrib.tax_exempt.overtime.payroll_tax_exempt: false + gov.contrib.tax_exempt.overtime.income_tax_exempt: true + gov.contrib.tax_exempt.tip_income.payroll_tax_exempt: false + gov.contrib.tax_exempt.tip_income.income_tax_exempt: true + overtime_income: 10_000 + tip_income: 10_000 + irs_employment_income: 30_000 + output: + irs_gross_income: 10_000 + payroll_tax_gross_wages: 30_000 + +- name: Overtime is income tax exempt and tips are payroll tax exempt + period: 2024 + reforms: policyengine_us.reforms.tax_exempt.tax_exempt_reform.tax_exempt_reform + input: + gov.contrib.tax_exempt.in_effect: true + gov.contrib.tax_exempt.overtime.payroll_tax_exempt: false + gov.contrib.tax_exempt.overtime.income_tax_exempt: true + gov.contrib.tax_exempt.tip_income.payroll_tax_exempt: true + gov.contrib.tax_exempt.tip_income.income_tax_exempt: false + overtime_income: 12_000 + tip_income: 11_000 + irs_employment_income: 30_000 + output: + irs_gross_income: 18_000 + payroll_tax_gross_wages: 19_000