class SingaporeCPFCalculator::BaseCalculator

Base class for CPF calculators.

Attributes

additional_wages[R]
estimated_yearly_ow[R]
ordinary_wages[R]
ytd_additional_wages[R]
ytd_ow_subject_to_cpf[R]

Public Class Methods

applies_to?(date, birthdate:) click to toggle source

@param [Fixnum] age @return [true, false] returns true if the calculator applies to the employee's age.

# File lib/singapore_cpf_calculator/base_calculator.rb, line 8
def applies_to?(date, birthdate:)
  AgeGroup.get(date, birthdate: birthdate) == required_age_group
end
calculate(ordinary_wages:, additional_wages:, ytd_additional_wages: 0.0, ytd_ow_subject_to_cpf: 0.0, estimated_yearly_ow: 0.0) click to toggle source

@param [BigDecimal] ordinary_wages:

Ordinary wages are wages due or granted in respect of employment and include allowances (e.g.
food allowance and overtime payments) earned by an employee in the month and payable before
the due date for payment of CPF contributions for that month.

@param [BigDecimal] additional_wages:

Additional wages are wage supplements which are not granted wholly and exclusively for the
month, such as annual bonus and leave pay. These and other incentive payments may be made at
intervals of more than a month.

@param [BigDecimal] ytd_additional_wages The year to date additional wages @param [BigDecimal] ytd_ow_subject_to_cpf The year to date ordinary wages @return [Hash] returns the total, employee, employer amounts for the CPF contribution

# File lib/singapore_cpf_calculator/base_calculator.rb, line 24
def calculate(ordinary_wages:, additional_wages:, ytd_additional_wages: 0.0, ytd_ow_subject_to_cpf: 0.0,
              estimated_yearly_ow: 0.0)
  new(ordinary_wages: ordinary_wages, additional_wages: additional_wages,
      ytd_ow_subject_to_cpf: ytd_ow_subject_to_cpf, ytd_additional_wages: ytd_additional_wages,
      estimated_yearly_ow: estimated_yearly_ow).calculate
end
new(ordinary_wages:, additional_wages:, ytd_additional_wages: 0.0, ytd_ow_subject_to_cpf: 0.0, estimated_yearly_ow: 0.0) click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 38
def initialize(ordinary_wages:, additional_wages:, ytd_additional_wages: 0.0, ytd_ow_subject_to_cpf: 0.0,
               estimated_yearly_ow: 0.0)
  @ordinary_wages = ordinary_wages
  @ytd_ow_subject_to_cpf = ytd_ow_subject_to_cpf
  @ytd_additional_wages = ytd_additional_wages
  @estimated_yearly_ow = estimated_yearly_ow
  @additional_wages = additional_wages
  clip_additional_wages_based_on_ceiling()
end

Private Class Methods

required_age_group() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 33
def required_age_group
  raise NotImplementedError, "sub classes needs to implement .required_age_group"
end

Public Instance Methods

calculate() click to toggle source

@return [Hash] returns the total, employee, employer amounts for the CPF contribution

# File lib/singapore_cpf_calculator/base_calculator.rb, line 49
def calculate
  CPFContribution.new total: total_contribution,
                      employee: employee_contribution,
                      aw_subject_to_cpf: additional_wages,
                      ow_subject_to_cpf: capped_ordinary_wages
end

Private Instance Methods

additional_wage_ceiling() click to toggle source

generally applies only to spr3 and citizens

# File lib/singapore_cpf_calculator/base_calculator.rb, line 123
def additional_wage_ceiling
  nil
end
adjustment_rate() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 140
def adjustment_rate
  raise NotImplementedError, "sub classes needs to implement #adjustment_rate"
end
calculated_employee_contribution() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 111
def calculated_employee_contribution
  case
  when total_wages < d("500.0000")
    d("0.0")
  when total_wages < d("750.0000")
    (d(adjustment_rate) * (total_wages - d("500.00")))
  else # >= $750
    (d(ec_rate) * capped_ordinary_wages) + (d(ec_rate) * additional_wages)
  end
end
calculated_remaining_wage_ceiling() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 88
def calculated_remaining_wage_ceiling
  max_remaining = additional_wage_ceiling - ytd_ow_subject_to_cpf - capped_ordinary_wages - ytd_additional_wages
  [max_remaining, d('0.0')].max
end
calculated_total_contribution() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 98
def calculated_total_contribution
  case
  when total_wages <= d("50.00")
    d("0.0")
  when total_wages <= d("500.00")
    d(tc_rate_1) * total_wages
  when total_wages < d("750.0000")
    (d(tc_rate_1) * total_wages) + (d(adjustment_rate) * (total_wages - d("500.00")))
  else # >= $750
    (d(tc_rate_2) * capped_ordinary_wages) + (d(tc_rate_2) * additional_wages)
  end
end
capped_ordinary_wages() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 144
def capped_ordinary_wages
  raise NotImplementedError, "sub classes needs to implement #capped_ordinary_wages"
end
clip_additional_wages_based_on_ceiling() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 82
def clip_additional_wages_based_on_ceiling
  unless additional_wage_ceiling.blank?
    @additional_wages = [additional_wages, calculated_remaining_wage_ceiling, estimated_remaining_wage_ceiling].min
  end
end
d(val) click to toggle source

precision helper

# File lib/singapore_cpf_calculator/base_calculator.rb, line 149
def d(val)
  BigDecimal(val)
end
ec_rate() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 136
def ec_rate
  raise NotImplementedError, "sub classes needs to implement #ec_rate"
end
employee_contribution() click to toggle source

Steps to compute CPF contribution:

a. Compute the total CPF contribution (rounded to the nearest dollar). An amount of 50 cents
   should be regarded as an additional dollar.
b. Compute the employee’s share of CPF contribution (cents should be dropped)
c. Employer’s share = Total contribution – Employee’s share
# File lib/singapore_cpf_calculator/base_calculator.rb, line 70
def employee_contribution
  @employee_contribution ||= calculated_employee_contribution.round(0, :truncate)
end
employer_contribution() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 74
def employer_contribution
  @employer_contribution ||= total_contribution - employee_contribution
end
estimated_remaining_wage_ceiling() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 93
def estimated_remaining_wage_ceiling
  estimated_remaining = additional_wage_ceiling - estimated_yearly_ow - ytd_additional_wages
  [estimated_remaining, d('0.0')].max
end
tc_rate_1() click to toggle source

TC Rate 1 is

# File lib/singapore_cpf_calculator/base_calculator.rb, line 128
def tc_rate_1
  raise NotImplementedError, "sub classes needs to implement #tc_rate_1"
end
tc_rate_2() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 132
def tc_rate_2
  raise NotImplementedError, "sub classes needs to implement #tc_rate_2"
end
total_contribution() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 61
def total_contribution
  @total_contribution ||= calculated_total_contribution.round(0, :half_up)
end
total_wages() click to toggle source
# File lib/singapore_cpf_calculator/base_calculator.rb, line 78
def total_wages
  ordinary_wages + additional_wages
end