class Piawe::RuleSet

Class to encapsulate a set of PIAWE payment rules

Public Class Methods

new(rules_array) click to toggle source

Create a new RuleSet to represent the rules contained in a rules array The primary responsibiltiy of this class is to delegate rendering of a report line to the appropriate Rule

Parameters

  • rules_array - An array of rule hashes

Rule Hash

A rule hash it a Ruby hash that has has the following format:

{"rules":[
  {"applicableWeeks": "1-26", "percentagePayable": 90, "overtimeIncluded": true},
  {"applicableWeeks": "27-52", "percentagePayable": 80, "overtimeIncluded": true},
  {"applicableWeeks": "53-79", "percentagePayable": 70, "overtimeIncluded": true},
  {"applicableWeeks": "80-104", "percentagePayable": 60, "overtimeIncluded": false},
  {"applicableWeeks": "105+", "percentagePayable": 10, "overtimeIncluded": false}
]}
  • applicableWeeks - A String that indicates the range of injury weeks during which the rule applies - Week 1 starts at the day of the injury, and Week 2 starts on the 7th day after the injury, and so on. It can have two formats: either a start week and end week joined by a dash, or a start week followed by a plus sign, which indicates the rule should apply to all later weeks as well. The first rule must have a start week of 1, the last rule must use the plus sign syntax, and all intervening rules must have a start week that is one greater than the end week of the preceeding rule.

  • percentagePayable - A Numeric that indicates the percentage of Average Weekly Earnings that are paid when this rule applies.

  • overtimeIncluded - A TrueClass or FalseClass that indicates whether overtime earnings should be considered part of Average Weekly Earnings when this rule applies.

# File lib/piawe/rule_set.rb, line 35
def initialize(rules_array)
        rules_array && rules_array.is_a?(Array) || (raise ArgumentError, "rules array is required - got #{rules_array.inspect}")
        rules_array.size > 0 || (raise ArgumentError, "rules array must contain at least one entry")
        rules_array.each do |rule_hash|
                add(Rule.played_by rule_hash)
        end
        rules[-1].end_week.nil? || (raise ArgumentError, "last rule must have a terminating + sign")
end

Public Instance Methods

report_line(person, report_date) click to toggle source

Based on the included Rules, generate a report line for a given person at a given report date by delegating to matching Rule objects

Parameters

  • person - The Piawe::Person for whom the report line should be generated

  • report_date - The Date for which the report line should be generated

# File lib/piawe/rule_set.rb, line 55
def report_line(person, report_date)
        rules.each do |rule|
                return rule.report_line( person, report_date ) if rule.matches?( person.weeks_since_injury( report_date ) ) 
        end # each rule
        # this should not be possible - but putting this here defensively...
        raise "APPLICATION BUG - A RuleSet EXISTS THAT DOES NOT COVER ALL POSSIBLE DATES!! (Date was #{report_date.strftime('%Y/%m/%d')}, person was #{person.inspect})"
end

Private Instance Methods

add(rule) click to toggle source
# File lib/piawe/rule_set.rb, line 70
def add(rule)
        # check consistency of rule dates
        (rule.end_week.nil? || rule.end_week > rule.start_week) || (raise ArgumentError, "rule #{rules.size + 1} has an end week of #{rule.end_week} that is not later than it's start week of #{rule.start_week}")
        if rules[-1] # we have existing rules, check we are consistent
                rules[-1].end_week || (raise ArgumentError, "rule #{rules.size} has a terminating + sign, and should have been the last rule, however there was a subsequent rule: #{rule.inspect}")
                rule.start_week == rules[-1].end_week + 1 || (raise ArgumentError, "rule #{rules.size} ends at week #{rules[-1].end_week} but rule #{rules.size + 1} starts at week #{rule.start_week} - each rule should start one week after the prior rule ends")
        else # this should be the first rule - check it's start date
                1 == rule.start_week || (raise ArgumentError, "rule 1 should start at week 1, but starts at week #{rule.start_week}")
        end # if we have existing rules
        rules << rule
end
applicable_weeks() click to toggle source
# File lib/piawe/rule_set.rb, line 112
def applicable_weeks
        @applicable_weeks ||= (
                self.has_key?("applicableWeeks") || (raise ArgumentError, "rule hash did not have an applicableWeeks key: #{self.inspect}")
                /(^\d+\-\d+$)|(^\d+\+$)/ =~ self["applicableWeeks"] || (raise ArgumentError, "applicableWeeks key is not in valid format")
                self["applicableWeeks"]
        )
end
end_week() click to toggle source
# File lib/piawe/rule_set.rb, line 102
def end_week
        @end_week ||= if /\+$/ =~ applicable_weeks
                                                                        nil
                                                                else
                                                                        ( /\d*\-(?<ending_week>\d+)$/ =~ applicable_weeks ) || (raise ArgumentError, "invalid applicableWeeks value: #{applicable_weeks}")
                                                                        ending_week.to_i
                                                                end # if trailing + sign
end
matches?(weeks_since_injury) click to toggle source

The weeks_since_injury value is interpreted as a statement of which injury week we are currently in - the first week commencing at the date of the injury, the second week commencing 7 days after that date etc.

# File lib/piawe/rule_set.rb, line 137
def matches?(weeks_since_injury)
        weeks_since_injury >= (start_week - 1).to_f && # it's after the prior week, i.e. when injured, you are immediately in the first
                                                  # week of injury
        (
                end_week.nil? ||
                weeks_since_injury <  end_week.to_f  # it's before the end_week number - i.e. exactly 1 week after an injury,
                                                           # you are now into the second week of injury
        )                                                                     
end
overtime_included() click to toggle source
# File lib/piawe/rule_set.rb, line 128
def overtime_included
        self.has_key?("overtimeIncluded") || (raise ArgumentError, "rule_hash does not have an overtimeIncluded key: #{self.inspect}")
        ( self["overtimeIncluded"].is_a?(TrueClass) || self["overtimeIncluded"].is_a?(FalseClass) )  || (raise ArgumentError, "overtimeIncluded value was not a boolean true or false - value was #{ self['overtimeIncluded'] }" )
        self["overtimeIncluded"]
end
pay_for_this_week( person ) click to toggle source
# File lib/piawe/rule_set.rb, line 148
def pay_for_this_week( person )
        (
                ( 
                        person.normal_hours * person.hourly_rate + ( 
                                overtime_included ? person.overtime_hours * person.overtime_rate : 0 
                        ) 
                ) * ( percentage_payable / 100 )
        ).round(2)
end
percentage_payable() click to toggle source
# File lib/piawe/rule_set.rb, line 121
def percentage_payable
        self.has_key?("percentagePayable") || (raise ArgumentError, "rule_hash does not have a percentagePayable key: #{self.inspect}")
        self["percentagePayable"].is_a?(Numeric) || (raise ArgumentError, "rule_hash has a non-numeric value for percentagePayable key: #{self['percentagePayable']}")
        BigDecimal.new self["percentagePayable"]
end
rules() click to toggle source
# File lib/piawe/rule_set.rb, line 83
def rules 
        @rules ||= []
end
start_week() click to toggle source
# File lib/piawe/rule_set.rb, line 94
def start_week
        @start_week ||= (
                /(?<starting_week>\d+)[+-]/ =~ applicable_weeks
                starting_week.to_i
        )
end