formulas 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 689f6cec1e958e23dba5a41b2eb083aa812961657b4a011911374afe5fef20f6
4
- data.tar.gz: e00de4f4bb6e815516a3cc8ece2c7ba8655921d56143a6a92d4e41b22abcdc90
3
+ metadata.gz: a7f8f146ead6fce0f64131ee26955ff1066d13300b3c73f81d7ea3cafb61c8be
4
+ data.tar.gz: 1ac72a62a41f905d27c84cecd1da31ad434a632ba51110bc05242f0b3d8004c9
5
5
  SHA512:
6
- metadata.gz: 0f3be3c409bce08fd1606ff9cde1da525353f5d1e25cf87c1083e7a13c592b6dd0c77c507f67bfa444add566f9fe3abab39aa0bcc85b2ffc8a2f2bed0bcb9892
7
- data.tar.gz: 3e3e80e654b6f904342e0e87ba8c92e175c19f5d4e64b1670bba81c2325a8a8d0e8dd7ecf15c1c48234b25e9a8a4f916c3dd46f4f8a0a4cfd07c13534eff75d8
6
+ metadata.gz: a7d7ccbff597d9ca4b9fa5abac846235086e23d89b714e98cc85d7526cf54e42b6525158d8a294149b96403dc1e98ac6406ef0eecaa5800f8485d84bc92a7061
7
+ data.tar.gz: 0c2e7a4e8a6ee19433ec5b337c38a90cf1f54e6112bebaf37ad5c34564c8d3509d313d8242e8b014bdfc9d50bde367c9beb63c5937ff3d10d7f29f667e0cdfe4
data/formulas.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'formulas'
3
+ s.version = '0.1.1'
4
+ s.summary = "formulas"
5
+ s.description = "Home loan formulas"
6
+ s.authors = ["formulas"]
7
+ s.email = 'boopage@gmail.com'
8
+ s.platform = Gem::Platform::RUBY
9
+ s.files = Dir['lib/**/*.rb', 'formulas.gemspec']
10
+ s.homepage =
11
+ 'https://rubygems.org/gems/formulas'
12
+ s.license = 'MIT'
13
+ s.require_paths = ["lib"]
14
+
15
+ s.add_development_dependency "minitest", ">= 5.8"
16
+ s.add_development_dependency "minitest-reporters", ">= 1.1"
17
+ end
data/lib/formulas.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Formulas
4
- autoload :StudentLoanRepayment, './lib/formulas/student_loan_repayment'
5
- autoload :Salary, './lib/formulas/salary'
6
- autoload :PAYE, './lib/formulas/paye'
7
- autoload :PAYG, './lib/formulas/payg'
8
- autoload :Income, './lib/formulas/income'
9
- autoload :WithholdingTax, './lib/formulas/withholding_tax'
10
- autoload :Superannuation, './lib/formulas/superannuation'
11
- autoload :LoanPrincipalCalculator, './lib/formulas/loan_principal_calculator'
4
+ autoload :StudentLoanRepayment, 'formulas/student_loan_repayment'
5
+ autoload :Salary, 'formulas/salary'
6
+ autoload :PAYE, 'formulas/paye'
7
+ autoload :PAYG, 'formulas/payg'
8
+ autoload :Income, 'formulas/income'
9
+ autoload :WithholdingTax, 'formulas/withholding_tax'
10
+ autoload :Superannuation, 'formulas/superannuation'
11
+ autoload :LoanPrincipalCalculator, 'formulas/loan_principal_calculator'
12
12
 
13
13
  MULTIPLIER_IN_FREQUENCY = {
14
14
  weekly: 52,
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formulas
4
+ module Expense
5
+ extend self
6
+
7
+ # Expense.monthly_credit_card(10_000, 3)
8
+ # => 300
9
+ def monthly_credit_card(amount, monthly_interest_rate)
10
+ amount * (monthly_interest_rate / 100)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formulas
4
+ # Provide calculation for household expenses based on the number of child
5
+ # and single or pair of adults
6
+ #
7
+ # source = Household::Source.new(independent_expenses: [1262, 1878], dependent_expenses: 347)
8
+ # household = Household.new(independents: integer, dependents: integer, source: source)
9
+ #
10
+ # household.cal(:month)
11
+ #
12
+ class HouseHold
13
+ def initialize(independents:, dependents:, source: Source.new)
14
+ @independents = independents
15
+ @dependents = dependents
16
+ @source = source
17
+ end
18
+
19
+ def cal
20
+ @source.calculate_expense(independents: @independents, dependents: @dependents)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formulas
4
+ module Expense
5
+ module Household
6
+ class Source
7
+ DEFAULT_INDEPENDENT_EXPENSE = [1_262, 1_878]
8
+ DEFAULT_DEPENDENT_EXPENSE = 347
9
+ MAX_DEPENDENT = 4
10
+ MAX_INDEPENDENT = 2
11
+
12
+ def calculate_expense(independents:, dependents:)
13
+ validate(independents, dependents)
14
+
15
+ ind_exp = DEFAULT_DEPENDENT_EXPENSE[0..independents].sum
16
+ de_exp = dependents * DEFAULT_DEPENDENT_EXPENSE
17
+ ind_exp + de_exp
18
+ end
19
+
20
+ private
21
+
22
+ def validate(independents, dependents)
23
+ raise "" if independents < 0
24
+ raise "" if dependents < 0
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formulas
4
+ module Income
5
+ extend self
6
+ DEFAULT_KIWISAVER = 3
7
+ DEFAULT_SUPER = 9.5
8
+
9
+ # Income.monthly_benefit_payment(100, :weekly)
10
+ # => 433
11
+ def monthly_benefit_payment(amount, frequency)
12
+ amount * Formulas::MULTIPLIER_IN_FREQUENCY[frequency] / 12
13
+ end
14
+
15
+ alias monthly_boarder_income monthly_benefit_payment
16
+
17
+ # Income.monthly_rental_income(100, :weekly)
18
+ # => 325
19
+ def monthly_rental_income(amount, frequency, fraction: 0.75)
20
+ (amount * Formulas::MULTIPLIER_IN_FREQUENCY[frequency] / 12) * fraction
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ module Formulas
4
+ class LoanPrincipalCalculator
5
+ attr_accessor :apr, :months, :repayment
6
+
7
+ def divide_by
8
+ interest_with_principal - 1
9
+ end
10
+
11
+ def interest_with_principal
12
+ (1 + (apr / 12)) ** months
13
+ end
14
+
15
+ def principal
16
+ (((repayment * divide_by) / interest_with_principal) * 12 ) / apr
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ # https://www.ato.gov.au/Rates/Individual-income-tax-rates/
3
+ #
4
+ module Formulas
5
+ # Calculate basic salary in frequency
6
+ # paye = Formulas::PAYE.new(gross_pay: 52_000, frequency: Formulas::ANNUAL)
7
+ #
8
+ # paye.tax(:monthly)
9
+ # => 718.33
10
+ #
11
+ # Provide a way to calculate pay as you earn calculator
12
+ class PAYE < WithholdingTax
13
+ # Provide a way to calculate PAYE tax
14
+ TAX_RATES = [
15
+ [[0, 14_000], 10.5],
16
+ [[14_000, 48_000], 17.5],
17
+ [[48_000, 70_000], 30],
18
+ [[70_000, 180_000], 33],
19
+ [[180_000], 39]
20
+ ]
21
+
22
+ def initialize(gross_pay:, frequency: Formulas::MONTHLY)
23
+ super(gross_pay, frequency, TAX_RATES)
24
+ end
25
+
26
+ def tax(request_frequency: Formulas::WEEKLY)
27
+ calculate_tax(request_frequency)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+ # https://www.ato.gov.au/rates/individual-income-tax-rates/
3
+ #
4
+ module Formulas
5
+ # Calculate basic salary in frequency
6
+ # salary = Income::Salary.new(52_000, Salary::ANNUAL)
7
+ #
8
+ # Taxable income
9
+ #
10
+ # Tax on this income
11
+ #
12
+ # 0 – $18,200
13
+ #
14
+ # Nil
15
+ #
16
+ # $18,201 – $45,000
17
+ #
18
+ # 19 cents for each $1 over $18,200
19
+ #
20
+ # $45,001 – $120,000
21
+ #
22
+ # $5,092 plus 32.5 cents for each $1 over $45,000
23
+ #
24
+ # $120,001 – $180,000
25
+ #
26
+ # $29,467 plus 37 cents for each $1 over $120,000
27
+ #
28
+ # $180,001 and over
29
+ #
30
+ # $51,667 plus 45 cents for each $1 over $180,000
31
+ #
32
+ # Plus 2 percent medicare
33
+ #
34
+ # salary.calculate(:monthly)
35
+ class PAYG < WithholdingTax
36
+ # Provide a way to calculate pay as you earn calculator
37
+ TAX_RATES = [
38
+ [[0, 18_200], 0],
39
+ [[18_201, 45_000], 19],
40
+ [[45_001, 120_000], 32.5],
41
+ [[120_001, 180_000], 37],
42
+ [[180_001], 45]
43
+ ]
44
+
45
+ def initialize(gross_pay:, frequency: Formulas::MONTHLY)
46
+ super(gross_pay, frequency, TAX_RATES)
47
+ end
48
+
49
+ def tax(request_frequency: Formulas::WEEKLY)
50
+ calculate_tax(request_frequency) * 1.02
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formulas
4
+ # Calculate basic salary in frequency
5
+ # salary = Formulas::Salary.new(gross_pay: 52_000, Salary::ANNUAL)
6
+ #
7
+ # salary.pay(:monthly)
8
+ #
9
+ # Provide a way to calculate salary in different frequencies
10
+ # It provide summaries of salary breakdown after deductions
11
+ # such as withholding tax, super, health care and methods to
12
+ # get the take home pay
13
+ #
14
+ class Salary
15
+ include FrequencyConversions
16
+ attr_reader :frequency
17
+
18
+ def initialize(gross_pay:, frequency:)
19
+ invalid_frequency unless FREQUENCIES.include?(frequency)
20
+ raise ArgumentError, 'Gross pay must be numeric' unless Numeric === gross_pay
21
+
22
+ @gross_pay = gross_pay
23
+ @frequency = frequency
24
+ end
25
+
26
+ def gross_pay(request_frequency: @frequency)
27
+ invalid_frequency unless FREQUENCIES.include?(frequency)
28
+ return @gross_pay if @frequency == request_frequency
29
+
30
+ convert_gross_pay_to(request_frequency).round(2)
31
+ end
32
+
33
+ private
34
+
35
+ def invalid_frequency
36
+ raise ArgumentError, "Invalid frequency, frequency are: #{FREQUENCIES.join(', ')}"
37
+ end
38
+
39
+ def convert_gross_pay_to(request_frequency)
40
+ send("convert_#{@frequency}_to_#{request_frequency}", @gross_pay)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require_relative 'student_loan_repayment/fix_repayment_per_period'
4
+
5
+ module Formulas
6
+
7
+ # Provide calculation to work out student loan repayment in frequency
8
+ # loan = StudentLoan.new(salary_amount: 1000, salary_frequency: Income::Salary::WEEKLY)
9
+ #
10
+ # loan.repayment
11
+ # => <#ConstantPerPeriod>
12
+ #
13
+ # loan.repayment
14
+ # => 317
15
+ #
16
+ #
17
+ module StudentLoanRepayment
18
+ autoload :RepaymentBase, './lib/formulas/student_loan_repayment/repayment_base'
19
+ autoload :FixRepaymentPerPeriod, './lib/formulas/student_loan_repayment/fix_repayment_per_period'
20
+ autoload :PercentRepaymentPerThreshold, './lib/formulas/student_loan_repayment/percent_repayment_per_threshold'
21
+ attr_reader :repayment
22
+
23
+ def initialize(income_strategy: , repayment_strategy:, rates:)
24
+ raise 'Missing required salary' unless income_strategy
25
+ raise 'Missing required repayment rates' unless rates
26
+ raise 'Missing required repayment strategy' unless repayment_strategy
27
+
28
+ @repayment = repayment_strategy.new(salary: income_strategy, repayment: rates)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # @salary = Formulas::Salary.new(gross_pay: 100_000, frequency: Formulas::ANNUALLY)
4
+ # @repayment_rates = Formulas::StudentLoanRepayment::FixRepaymentPerPeriod::DEFAULT_THRESHOLD
5
+ #
6
+ # loan = Formulas::StudentLoanRepayment::FixRepaymentPerPeriod.new(salary: @salary, repayment: @repayment_rates)
7
+ # assert_equal loan.repayment, 797.2
8
+ #
9
+ module Formulas
10
+ module StudentLoanRepayment
11
+ class FixRepaymentPerPeriod < RepaymentBase
12
+ FIX_RATE = 0.12
13
+
14
+ DEFAULT_THRESHOLD = {
15
+ weekly: [390, 52],
16
+ fortnightly: [780, 26],
17
+ four_weeks: [1560, 13],
18
+ monthly: [1690, 12],
19
+ annually: [20280, 1],
20
+ }
21
+
22
+ def repayment
23
+ selected_base = @repayment_threshold[@salary.frequency]
24
+ less_base_cost = @salary.gross_pay - selected_base[0]
25
+ ((FIX_RATE * less_base_cost * selected_base[1]) / 12).round(2)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formulas
4
+ module StudentLoanRepayment
5
+ class PercentRepaymentPerThreshold < RepaymentBase
6
+ DEFAULT_THRESHOLD = [
7
+ [[0, 46_620], 0],
8
+ [[46_620, 53_826], 1],
9
+ [[53_826, 57_055], 2],
10
+ [[57_056, 60_479], 2.5],
11
+ [[60_480, 64_108], 3],
12
+ [[64_109, 67_954], 3.5],
13
+ [[67_955, 72_031], 4],
14
+ [[72_032, 76_354], 4.5],
15
+ [[76_355, 80_935], 5],
16
+ [[80_936, 85_792], 5.5],
17
+ [[85_793, 90_939], 6],
18
+ [[90_940, 96_396], 6.5],
19
+ [[96_397, 102_179], 7],
20
+ [[102_180, 108_309], 7.5],
21
+ [[108_310, 114_707], 8],
22
+ [[114_708, 121_698], 8.5],
23
+ [[121_699, 128_999], 9],
24
+ [[129_000, 136_739], 9.5],
25
+ [[136_740], 10],
26
+ ]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ module Formulas
2
+ module StudentLoanRepayment
3
+ class RepaymentBase
4
+ def initialize(salary:, repayment_threshold:)
5
+ @salary = salary
6
+ @repayment_threshold = repayment_threshold
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formulas
4
+ # Calculate the super using the as per frequency
5
+ #
6
+ # salary = Formulas::Salary.new(gross_pay: 52_000, Salary::ANNUAL)
7
+ # super = Super.new(salary: salary, Super::KIWISAVER)
8
+ #
9
+ # super.calculate
10
+ # => 1,560.00
11
+ #
12
+ # super.calculate(Formulas::WEEKLY)
13
+ # => 30.00
14
+ #
15
+ class Superannuation
16
+ include FrequencyConversions
17
+
18
+ KIWISAVER = 3
19
+ AU_SUPER = 10
20
+
21
+ def initialize(salary:, superannuation:)
22
+ @salary = salary
23
+ @super = superannuation
24
+ end
25
+
26
+ def calculate(request_frequency: Formulas::ANNUALLY)
27
+ result = @salary.gross_pay(request_frequency: request_frequency) * (@super.to_f / 100)
28
+ result.round(2)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formulas
4
+ class WithholdingTax
5
+ include FrequencyConversions
6
+
7
+ def initialize(gross_pay, origin_frequency, tax_rate)
8
+ @gross_pay = gross_pay
9
+ @origin_frequency = origin_frequency
10
+ @tax_rate = tax_rate
11
+ end
12
+
13
+ protected
14
+
15
+ def calculate_tax(request_frequency)
16
+ @request_frequency = request_frequency
17
+
18
+ return annual_tax if request_frequency == Formulas::ANNUALLY
19
+
20
+ send("convert_annually_to_#{request_frequency}", annual_tax).round(2)
21
+ end
22
+
23
+ private
24
+
25
+ def annual_tax
26
+ annual_result = 0
27
+
28
+ if gross_pay_tax_index > 0
29
+ @tax_rate[0..gross_pay_tax_index].each_with_index do |current, index|
30
+ l = (index == gross_pay_tax_index) ? @gross_pay : current[0][1]
31
+ annual_result += ((l - current[0][0]) * (current[1].to_f / 100))
32
+ end
33
+ end
34
+ annual_result
35
+ end
36
+
37
+ def annual_gross_pay
38
+ return @gross_pay if @origin_frequency == Formulas::ANNUALLY
39
+ send("convert_#{@origin_frequency}_to_annually", @gross_pay)
40
+ end
41
+
42
+ def gross_pay_tax_index
43
+ @tax_rate.index { |current| current[0][0] <= annual_gross_pay && current[0][1] >= annual_gross_pay }
44
+ end
45
+ end
46
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: formulas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - formulas
@@ -39,12 +39,27 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.1'
41
41
  description: Home loan formulas
42
- email: ''
42
+ email: boopage@gmail.com
43
43
  executables: []
44
44
  extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
+ - formulas.gemspec
47
48
  - lib/formulas.rb
49
+ - lib/formulas/expense.rb
50
+ - lib/formulas/household.rb
51
+ - lib/formulas/household/source.rb
52
+ - lib/formulas/income.rb
53
+ - lib/formulas/loan_principal_calculator.rb
54
+ - lib/formulas/paye.rb
55
+ - lib/formulas/payg.rb
56
+ - lib/formulas/salary.rb
57
+ - lib/formulas/student_loan_repayment.rb
58
+ - lib/formulas/student_loan_repayment/fix_repayment_per_period.rb
59
+ - lib/formulas/student_loan_repayment/percent_repayment_per_threshold.rb
60
+ - lib/formulas/student_loan_repayment/repayment_base.rb
61
+ - lib/formulas/superannuation.rb
62
+ - lib/formulas/withholding_tax.rb
48
63
  homepage: https://rubygems.org/gems/formulas
49
64
  licenses:
50
65
  - MIT