From 06fc825501f6440d043203097faa2c37e3d6bec0 Mon Sep 17 00:00:00 2001 From: Benjamin Randolph <104036158+neb417@users.noreply.github.com> Date: Sat, 13 Jan 2024 07:55:00 -0700 Subject: [PATCH] Refactor federal tax (#35) * Calculate taxes for self-employed. * Add tests. * Lint. --- app/services/income_tax_calculator_service.rb | 34 +++++++++--- app/views/shared/_taxed_income.html.erb | 2 +- spec/factories/federal_tax_brackets.rb | 26 ++++----- .../income_tax_calculator_service_spec.rb | 54 +++++++++++++++++++ 4 files changed, 94 insertions(+), 22 deletions(-) create mode 100644 spec/services/income_tax_calculator_service_spec.rb diff --git a/app/services/income_tax_calculator_service.rb b/app/services/income_tax_calculator_service.rb index ce7e99e..f8895c9 100644 --- a/app/services/income_tax_calculator_service.rb +++ b/app/services/income_tax_calculator_service.rb @@ -1,8 +1,11 @@ class IncomeTaxCalculatorService attr_reader :income, :annual_income, - :federal_tax, :fica_tax, + :agi_deduction, + :agi, + :federal_income_tax, + :total_federal_tax, :net_after_fed_tax, :state_tax, :total_net_income, @@ -16,8 +19,11 @@ class IncomeTaxCalculatorService def initialize(income:) @income = income @annual_income = income.weekly_income * 52 - @federal_tax = calculate_fed_tax @fica_tax = calculate_fica_tax + @agi_deduction = calculate_agi_deduction + @agi = calculate_agi + @federal_income_tax = calculate_fed_tax + @total_federal_tax = calculate_total_federal_tax @net_after_fed_tax = calculate_net_after_fed_tax @state_tax = calculate_state_tax @total_net_income = calculate_total_net_income @@ -31,23 +37,35 @@ def initialize(income:) private + def calculate_fica_tax + @annual_income * 0.153 + end + + def calculate_agi_deduction + @fica_tax * 0.5 + end + + def calculate_agi + @annual_income - @agi_deduction + end + def calculate_fed_tax - bracket = FederalTaxBracket.where("bottom_range_cents <= ?", @annual_income.cents).order(:bottom_range_cents).last - taxable_at_bracket_rate = Money.new(@annual_income.cents - bracket.bottom_range_cents) + bracket = FederalTaxBracket.where("bottom_range_cents <= ?", @agi.cents).order(:bottom_range_cents).last + taxable_at_bracket_rate = Money.new(@agi - bracket.bottom_range) rated = bracket.rate * taxable_at_bracket_rate rated + bracket.cumulative end - def calculate_fica_tax - @annual_income * 0.0765 + def calculate_total_federal_tax + @fica_tax + @federal_income_tax end def calculate_state_tax - @net_after_fed_tax * 0.0463 + @net_after_fed_tax * 0.044 end def calculate_net_after_fed_tax - @annual_income - @federal_tax + @agi - @federal_income_tax end def calculate_total_net_income diff --git a/app/views/shared/_taxed_income.html.erb b/app/views/shared/_taxed_income.html.erb index 06bdbaa..97bf581 100644 --- a/app/views/shared/_taxed_income.html.erb +++ b/app/views/shared/_taxed_income.html.erb @@ -1,4 +1,4 @@ -<% paid_taxes = [ taxed_income.federal_tax, taxed_income.fica_tax, taxed_income.state_tax, taxed_income.total_net_income ] %> +<% paid_taxes = [ taxed_income.federal_income_tax, taxed_income.fica_tax, taxed_income.state_tax, taxed_income.total_net_income ] %> <% paid_taxes.each do |tax| %> <% if annual %> diff --git a/spec/factories/federal_tax_brackets.rb b/spec/factories/federal_tax_brackets.rb index 9f823f5..1b0433d 100644 --- a/spec/factories/federal_tax_brackets.rb +++ b/spec/factories/federal_tax_brackets.rb @@ -18,32 +18,32 @@ factory :federal_tax_bracket do tier { "Tier 1" } bottom_range_cents { 0 } - top_range_cents { 100000 } + top_range_cents { 100_000 } rate { 0.1 } cumulative_cents { 0 } trait :tier_2 do tier { "Tier 2" } - bottom_range_cents { 1000100 } - top_range_cents { 10000000 } + bottom_range_cents { 1_000_100 } + top_range_cents { 10_000_000 } rate { 0.15 } - cumulative_cents { 200000 } + cumulative_cents { 200_000 } end trait :tier_3 do tier { "Tier 2" } - bottom_range_cents { 10000100 } - top_range_cents { 50000000 } + bottom_range_cents { 10_000_100 } + top_range_cents { 50_000_000 } rate { 0.25 } - cumulative_cents { 500000 } + cumulative_cents { 500_000 } end - # trait :with_all_tiers do - # after :create do |_record| - # create(:federal_tax_bracket, :tier_2) - # create(:federal_tax_bracket, :tier_3) - # end - # end + trait :with_all_tiers do + after :create do |_record| + create(:federal_tax_bracket, :tier_2) + create(:federal_tax_bracket, :tier_3) + end + end # # to_create do |instance| # instance.id = FederalTaxBracket.find_or_create_by(tier: instance.tier).id diff --git a/spec/services/income_tax_calculator_service_spec.rb b/spec/services/income_tax_calculator_service_spec.rb new file mode 100644 index 0000000..eaa8512 --- /dev/null +++ b/spec/services/income_tax_calculator_service_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require("rails_helper") + +RSpec.describe IncomeTaxCalculatorService, type: :service do + let(:salary) { create(:income) } + let(:hourly) { create(:income, :hourly) } + let!(:tax_brackets) { create(:federal_tax_bracket, :with_all_tiers) } + let!(:taxed_salary) { IncomeTaxCalculatorService.new(income: salary) } + let!(:taxed_hourly) { IncomeTaxCalculatorService.new(income: hourly) } + + describe "income taxes calculator" do + it { expect(taxed_salary).to be_an IncomeTaxCalculatorService } + it { expect(taxed_hourly).to be_an IncomeTaxCalculatorService } + + it "calculates salary" do + expect(taxed_salary.income).to be_truthy + expect(taxed_salary.annual_income).to be_truthy + expect(taxed_salary.fica_tax).to be_truthy + expect(taxed_salary.agi_deduction).to be_truthy + expect(taxed_salary.agi).to be_truthy + expect(taxed_salary.federal_income_tax).to be_truthy + expect(taxed_salary.total_federal_tax).to be_truthy + expect(taxed_salary.net_after_fed_tax).to be_truthy + expect(taxed_salary.state_tax).to be_truthy + expect(taxed_salary.total_net_income).to be_truthy + expect(taxed_salary.bi_weekly_net_income).to be_truthy + expect(taxed_salary.daily_income).to be_truthy + expect(taxed_salary.weekly_income).to be_truthy + expect(taxed_salary.monthly_income).to be_truthy + expect(taxed_salary.quarterly_income).to be_truthy + expect(taxed_salary.biannual_income).to be_truthy + end + + it "calculates hourly" do + expect(taxed_hourly.income).to be_truthy + expect(taxed_hourly.annual_income).to be_truthy + expect(taxed_hourly.fica_tax).to be_truthy + expect(taxed_hourly.agi_deduction).to be_truthy + expect(taxed_hourly.agi).to be_truthy + expect(taxed_hourly.federal_income_tax).to be_truthy + expect(taxed_hourly.total_federal_tax).to be_truthy + expect(taxed_hourly.net_after_fed_tax).to be_truthy + expect(taxed_hourly.state_tax).to be_truthy + expect(taxed_hourly.total_net_income).to be_truthy + expect(taxed_hourly.bi_weekly_net_income).to be_truthy + expect(taxed_hourly.daily_income).to be_truthy + expect(taxed_hourly.weekly_income).to be_truthy + expect(taxed_hourly.monthly_income).to be_truthy + expect(taxed_hourly.quarterly_income).to be_truthy + expect(taxed_hourly.biannual_income).to be_truthy + end + end +end