Skip to content

Commit

Permalink
testing and logic
Browse files Browse the repository at this point in the history
  • Loading branch information
PavelMakarchuk committed Nov 27, 2024
1 parent 15cb150 commit c3d30dd
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 23 deletions.
5 changes: 4 additions & 1 deletion changelog_entry.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@

- bump: minor
changes:
added:
- Second earner tax reform.
60 changes: 38 additions & 22 deletions policyengine_us/reforms/second_earner/second_earner_tax_reform.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,7 @@ def formula(person, period, parameters):
deductions = (
person.tax_unit("taxable_income_deductions", period) / 2
)
is_tax_unit_head_or_spouse = person("is_tax_unit_head_or_spouse", period)
return max_(0, agi - exemptions - deductions) * is_tax_unit_head_or_spouse


#TODO: Attribute dependent income to the head

return max_(0, agi - exemptions - deductions)

class income_tax_main_rates(Variable):
value_type = float
Expand All @@ -33,22 +28,46 @@ class income_tax_main_rates(Variable):
def formula(tax_unit, period, parameters):
person = tax_unit.members
full_taxable_income = person("taxable_income_person", period)
cg_exclusion = tax_unit("capital_gains_excluded_from_taxable_income", period) / 2
is_tax_unit_head_or_spouse = person(
"is_tax_unit_head_or_spouse", period
)
cg_exclusion = (
tax_unit("capital_gains_excluded_from_taxable_income", period)
/ 2
) * is_tax_unit_head_or_spouse
taxinc = max_(0, full_taxable_income - cg_exclusion)
p = parameters(period).gov.irs.income
bracket_tops = p.bracket.thresholds
bracket_rates = p.bracket.rates
filing_status = tax_unit("filing_status", period)

# Determine primary and secondary earner incomes based on income size
is_tax_unit_head_or_spouse = person("is_tax_unit_head_or_spouse", period)
is_tax_unit_head = person("is_tax_unit_head", period)
is_tax_unit_dependent = person("is_tax_unit_dependent", period)

# Add dependent income to head's income
dependent_income = (taxinc * is_tax_unit_dependent).sum()
earner_taxinc = taxinc * is_tax_unit_head_or_spouse
max_income = max_(earner_taxinc)
is_primary_earner = (earner_taxinc == max_income) & (earner_taxinc > 0)
is_secondary_earner = is_tax_unit_head_or_spouse & ~is_primary_earner

taxable_income_primary_earner = where(is_primary_earner, taxinc, 0).sum()
taxable_income_secondary_earner = where(is_secondary_earner, taxinc, 0).sum()
earner_taxinc = where(
is_tax_unit_head,
earner_taxinc + dependent_income,
earner_taxinc,
)

max_income = tax_unit.max(earner_taxinc)
is_primary_earner = (earner_taxinc == max_income) & (
earner_taxinc > 0
)
is_secondary_earner = (
is_tax_unit_head_or_spouse & ~is_primary_earner
)

taxable_income_primary_earner = where(
is_primary_earner, earner_taxinc, 0
).sum()
taxable_income_secondary_earner = where(
is_secondary_earner, earner_taxinc, 0
).sum()

# Calculate primary earner tax using actual filing status
primary_earner_tax = 0
Expand All @@ -64,22 +83,19 @@ def formula(tax_unit, period, parameters):
# Calculate secondary earner tax using single filing status
secondary_earner_tax = 0
bracket_bottom = 0
filing_statuses = filing_status.possible_values
single_status = filing_statuses.SINGLE
single_status = "SINGLE"
for i in range(1, len(list(bracket_rates.__iter__())) + 1):
b = str(i)
bracket_top = bracket_tops[b][single_status]
secondary_earner_tax += bracket_rates[b] * amount_between(
taxable_income_secondary_earner, bracket_bottom, bracket_top
taxable_income_secondary_earner,
bracket_bottom,
bracket_top,
)
bracket_bottom = bracket_top

return primary_earner_tax + secondary_earner_tax





class reform(Reform):
def apply(self):
self.update_variable(taxable_income_person)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,188 @@
taxable_income_deductions: 500
output:
taxable_income_person: [19_250, 0]

- name: Two people, both with income in the first bracket
period: 2023
reforms: policyengine_us.reforms.second_earner.second_earner_tax_reform.second_earner_tax_reform
input:
gov.contrib.second_earner_reform.in_effect: true
people:
person1:
is_tax_unit_head_or_spouse: true
taxable_income_person: 20_000
person2:
is_tax_unit_head_or_spouse: true
taxable_income_person: 1_000
tax_units:
tax_unit:
members: [person1, person2]
capital_gains_excluded_from_taxable_income: 0
filing_status: JOINT
output:
income_tax_main_rates: 2_100

- name: Two people, spouse in second single bracket
period: 2023
reforms: policyengine_us.reforms.second_earner.second_earner_tax_reform.second_earner_tax_reform
input:
gov.contrib.second_earner_reform.in_effect: true
people:
person1:
is_tax_unit_head_or_spouse: true
taxable_income_person: 20_000
person2:
is_tax_unit_head_or_spouse: true
taxable_income_person: 15_000
tax_units:
tax_unit:
members: [person1, person2]
capital_gains_excluded_from_taxable_income: 0
filing_status: JOINT
output:
income_tax_main_rates: 3_580

- name: Two people, spouse in second single bracket - reform not applied
period: 2023
input:
gov.contrib.second_earner_reform.in_effect: false
people:
person1:
is_tax_unit_head_or_spouse: true
person2:
is_tax_unit_head_or_spouse: true
tax_units:
tax_unit:
members: [person1, person2]
capital_gains_excluded_from_taxable_income: 0
filing_status: JOINT
taxable_income: 45_000
output:
income_tax_main_rates: 4_960


- name: Spouse with higher income becomes primary earner
period: 2023
reforms: policyengine_us.reforms.second_earner.second_earner_tax_reform.second_earner_tax_reform
input:
gov.contrib.second_earner_reform.in_effect: true
people:
person1:
is_tax_unit_head_or_spouse: true
taxable_income_person: 20_000
person2:
is_tax_unit_head_or_spouse: true
taxable_income_person: 40_000
tax_units:
tax_unit:
members: [person1, person2]
capital_gains_excluded_from_taxable_income: 0
filing_status: JOINT
output:
income_tax_main_rates: 6_540

- name: One person with one dependent taxes as head of household
period: 2023
reforms: policyengine_us.reforms.second_earner.second_earner_tax_reform.second_earner_tax_reform
input:
gov.contrib.second_earner_reform.in_effect: true
people:
person1:
taxable_income_person: 40_000
person2:
age: 10
tax_units:
tax_unit:
members: [person1, person2]
capital_gains_excluded_from_taxable_income: 0
output:
income_tax_main_rates: 4_486

- name: One person alone is taxed as single
period: 2023
reforms: policyengine_us.reforms.second_earner.second_earner_tax_reform.second_earner_tax_reform
input:
gov.contrib.second_earner_reform.in_effect: true
people:
person1:
taxable_income_person: 15_000
tax_units:
tax_unit:
members: [person1]
capital_gains_excluded_from_taxable_income: 0
output:
income_tax_main_rates: 1_580

- name: Joint couple with one dependent, cg exclusion included
period: 2023
reforms: policyengine_us.reforms.second_earner.second_earner_tax_reform.second_earner_tax_reform
input:
gov.contrib.second_earner_reform.in_effect: true
people:
person1:
age: 40
taxable_income_person: 30_000
person2:
age: 40
taxable_income_person: 15_000
person3:
age: 16
taxable_income_person: 1_000
tax_units:
tax_unit:
members: [person1, person2, person3]
capital_gains_excluded_from_taxable_income: 2_000
output:
income_tax_main_rates: 4_620

- name: Integration, joint household with one depedent, reform not applied
period: 2023
input:
gov.contrib.second_earner_reform.in_effect: false
people:
person1:
age: 40
employment_income: 50_000
person2:
age: 40
employment_income: 40_000
person3:
age: 16
employment_income: 1_000
tax_units:
tax_unit:
members: [person1, person2, person3]
output:
adjusted_gross_income: 90_000
adjusted_gross_income_person: [50_000, 40_000, 0]
exemptions: 0
taxable_income_deductions: 27_700
taxable_income: 62_300
income_tax_main_rates: 7_036

- name: Integration, joint household with one depedent, reform applied
period: 2023
reforms: policyengine_us.reforms.second_earner.second_earner_tax_reform.second_earner_tax_reform
input:
gov.contrib.second_earner_reform.in_effect: true
people:
person1:
age: 40
employment_income: 50_000
person2:
age: 40
employment_income: 40_000
person3:
age: 16
employment_income: 1_000
tax_units:
tax_unit:
members: [person1, person2, person3]
output:
adjusted_gross_income: 90_000
adjusted_gross_income_person: [50_000, 40_000, 0]
taxable_income: 62_300
exemptions: 0
taxable_income_deductions: 27_700
taxable_income_person: [36_150, 26_150, 0]
income_tax_main_rates: 6_816

0 comments on commit c3d30dd

Please sign in to comment.