formulas 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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