-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor income tax calculator. (#43)
* Add callable gem. * Break up income tax calculator into multiple, smaller services. * Refactor incomes methods in concern. * Uninstall callable gem, add callable module, configure to be used in application. * Refactor downstream. * Lint. * Add test for federal tax calculator. * Add test for fica and state tax calculators. * Lint. * Specs for net income calculator * Refactor with use of new services. * Remove commented out code. * Fix service. * Fix net income service. * Add standard deduction to federal tax calculator.
- Loading branch information
Showing
18 changed files
with
252 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,28 @@ | ||
# frozen_string_literal: true | ||
|
||
module TaxedIncome | ||
def tax_on_salary | ||
income = Income.find_by(income_type: "Salary") | ||
IncomeTaxCalculatorService.new(income: income) | ||
extend ActiveSupport::Concern | ||
|
||
def build_income_tax_variables! | ||
@salary_taxed = build_income_tax_object(income: salary_income) | ||
@hourly_taxed = build_income_tax_object(income: hourly_income) | ||
end | ||
|
||
private | ||
|
||
def salary_income | ||
@salary_income = Income.find_by(income_type: "Salary").weekly_income * 52 | ||
end | ||
|
||
def tax_on_hourly | ||
income = Income.find_by(income_type: "Hourly") | ||
IncomeTaxCalculatorService.new(income: income) | ||
def hourly_income | ||
@hourly_income = Income.find_by(income_type: "Hourly").weekly_income * 52 | ||
end | ||
|
||
def build_taxed_income_vars! | ||
@salary_taxed = tax_on_salary | ||
@hourly_taxed = tax_on_hourly | ||
def build_income_tax_object(income:) | ||
federal_tax = FederalTaxCalculator.call(income: income) | ||
fica_tax = FicaTaxCalculator.call(income: income) | ||
state_tax = StateTaxCalculator.call(income: income) | ||
net_income = income - (fica_tax + federal_tax + state_tax) | ||
OpenStruct.new(federal_tax: federal_tax, fica_tax: fica_tax, state_tax: state_tax, net_income: net_income) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
class FederalTaxCalculator | ||
include Callable | ||
|
||
def initialize(income:) | ||
self.income = income | ||
end | ||
|
||
def call | ||
calculate | ||
end | ||
|
||
private | ||
|
||
attr_accessor :income | ||
|
||
def calculate | ||
bracket = FederalTaxBracket.where("bottom_range_cents <= ?", taxable_income.fractional).order(:bottom_range_cents).last | ||
taxable_at_bracket_rate = Money.new(taxable_income - bracket.bottom_range) | ||
rated = bracket.rate * taxable_at_bracket_rate | ||
rated + bracket.cumulative | ||
end | ||
|
||
def taxable_income | ||
# 2024 standard deduction = 13,850 | ||
@taxable_income ||= income - Money.new(13_850_00) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
class FicaTaxCalculator | ||
include Callable | ||
|
||
def initialize(income:) | ||
self.income = income | ||
end | ||
|
||
def call | ||
income * 0.0765 | ||
end | ||
|
||
private | ||
|
||
attr_accessor :income | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
class NetIncomeCalculator | ||
attr_reader :annual_income, :daily_income, :weekly_income, :monthly_income, :quarterly_income, :biannual_income | ||
|
||
def initialize(annual_income:) | ||
@annual_income = annual_income | ||
@biannual_income = calculate_biannual_income | ||
@quarterly_income = calculate_quarterly_income | ||
@monthly_income = calculate_monthly_income | ||
@weekly_income = calculate_weekly_income | ||
@daily_income = calculate_daily_income | ||
end | ||
|
||
def calculate_biannual_income | ||
@annual_income / 2 | ||
end | ||
|
||
def calculate_quarterly_income | ||
@annual_income / 4 | ||
end | ||
|
||
def calculate_monthly_income | ||
@annual_income / 12 | ||
end | ||
|
||
def calculate_weekly_income | ||
@annual_income / 52 | ||
end | ||
|
||
def calculate_daily_income | ||
@annual_income / 365 | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
class StateTaxCalculator | ||
include Callable | ||
|
||
def initialize(income:) | ||
self.income = income | ||
end | ||
|
||
# Colorado state tax rate is 4.4% | ||
def call | ||
income * 0.044 | ||
end | ||
|
||
private | ||
|
||
attr_accessor :income | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
<% paid_taxes = [ taxed_income.federal_income_tax, taxed_income.fica_tax, taxed_income.state_tax, taxed_income.total_net_income ] %> | ||
<% paid_taxes = [ taxed_income.federal_tax, taxed_income.fica_tax, taxed_income.state_tax, taxed_income.net_income ] %> | ||
|
||
<% paid_taxes.each do |tax| %> | ||
<% if annual %> | ||
<div class="px-5"><%= humanized_money_with_symbol(tax) %></div> | ||
<% else %> | ||
<div class="px-5"><%= humanized_money_with_symbol(tax / 26) %></div> | ||
<% end %> | ||
<% end %> | ||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module Callable | ||
extend ActiveSupport::Concern | ||
|
||
class_methods do | ||
def call(**args) | ||
new(**args).call | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# frozen_string_literal: true | ||
|
||
require("rails_helper") | ||
|
||
RSpec.describe FederalTaxCalculator, type: :service do | ||
subject(:service) do | ||
described_class.call( | ||
income: salary_income.rate | ||
) | ||
end | ||
|
||
let!(:salary_income) { create(:income) } | ||
let!(:tax_brackets) { create(:federal_tax_bracket, :with_all_tiers) } | ||
|
||
it { expect(service).to be_a Money } | ||
|
||
it "calculates federal tax" do | ||
# salary_income = $50,000 | ||
# standard_deduction = $13,850 | ||
# tax_brackets = 10% on first $1,000, 15% from $1,001 to $100,000, 25% from $100,001 to $500,000 | ||
|
||
expect(service.format).to eq("$5,372.35") | ||
expect((salary_income.rate - service).format).to eq("$44,627.65") | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# frozen_string_literal: true | ||
|
||
require("rails_helper") | ||
|
||
RSpec.describe FicaTaxCalculator, type: :service do | ||
subject(:service) do | ||
described_class.call( | ||
income: salary_income.rate | ||
) | ||
end | ||
|
||
let!(:salary_income) { create(:income) } | ||
let!(:tax_brackets) { create(:federal_tax_bracket, :with_all_tiers) } | ||
|
||
it { expect(service).to be_a Money } | ||
|
||
it "calculates FICA tax" do | ||
# salary_income = $50,000 | ||
|
||
expect(service.format).to eq("$3,825.00") | ||
expect((salary_income.rate - service).format).to eq("$46,175.00") | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# frozen_string_literal: true | ||
|
||
require("rails_helper") | ||
|
||
RSpec.describe NetIncomeCalculator, type: :service do | ||
subject(:service) do | ||
described_class.new( | ||
annual_income: salary_income.rate | ||
) | ||
end | ||
|
||
let!(:salary_income) { create(:income) } | ||
let!(:tax_brackets) { create(:federal_tax_bracket, :with_all_tiers) } | ||
|
||
it { expect(service).to be_a NetIncomeCalculator } | ||
|
||
it { expect(service.annual_income.format).to eq("$50,000.00") } | ||
it { expect(service.biannual_income.format).to eq("$25,000.00") } | ||
it { expect(service.quarterly_income.format).to eq("$12,500.00") } | ||
it { expect(service.monthly_income.format).to eq("$4,166.67") } | ||
it { expect(service.weekly_income.format).to eq("$961.54") } | ||
it { expect(service.daily_income.format).to eq("$136.99") } | ||
end |
Oops, something went wrong.