Forum Discussion

Will_H's avatar
Will_H
MYOB Moderator
2 months ago

WFM Pay Conditions primer (Draft)

Hi all,
Sorry the below is a bit rough, this is my draft notes that I'm intending to work up into a proper whitepaper/training if I ever get capacity.

These notes are copied from the Technical Resources area of Partner Self Service, I'm intending to maintain them here, rather than in Partner Self Service.

 

These notes are as at 30 May 2024 very draft, and slightly out of date.  Still, I need to have this information available incase it helps anyone implement a new WFM site.

====General Principles====

=====Categorize hours first =====

First Categorize all time into different categories.
Then pay the categories you have set up.
This allows you to make changes to the overall rule structure easier in future.

Reasons for doing this:
This means if you have to change a section of the rules, the logic is separated from the actual application of the pay rule.

Also makes it easier to set exclusions.  SInce instead of saying 
Not_ All the things that make up overtime calculation.
You set to:
Not_ Anything on the Overtime category.

=====Use "When All" =====

Rules should generally be set to "When all of these conditions are met"
Most people want rules to be set to every condition inside applying.  One of the most common mistakes I see from new rule writers is using "Any"

=====Keep it simple =====

Rules should be as simple as possible.
It is better to make 3 different rules that assign into the same category, than to make 1 very complicated rule that covers all conditions for that category.
Note: We don't currently have access to a performance tuner for Rules, but this is likely to be the case for performance as well, since adding OR conditions to a rule is generally slow at a database query level.


====Rule Logic====

The rule engine is not pretty, but it is functional. The most important thing to remember are the basics of predicate logic. 

=====When All of these conditions are met=====

If a Rule says that "All" conditions must be met, it is a logical AND operator.
This means everything below it must be true.
A 3 part rule would have to be:
Part 1 True
Part 2 True
Part 3 True
For the rule to apply.

=====When Any of these conditions are met=====

If a Rule says that "Any" conditions must be met, it is a logical OR operator.
This is a non-exclusive OR.
Using a 3 Part Rule, this means that ANY of Part 1, Part 2 or Part 3 must be true.

=====Conditions=====

These are things that must be true.

=====Nested Conditions=====

This is effectively a bracket.
So when Nested conditions are added/applied it acts as 
ALL 
When Condition (X)
When Any Nested Condition
 When Nested Condition (Y)
 When Nested Condition (Z)
X AND (Y OR Z)
This is very useful for being able to pick some parts of logic to be OR, while keeping all other conditions true.

=====Should I have 1 complicated Rule, or 2 rules?=====

If you have different categories of employees, some of whom qualify for additional benefits and others who do not, the options are really:
1. Set up different Pay Tags, and use the pay tags to say "this section of this rule only applies to these people"
2. Set up 2 completely separate Rules.

While 2. is much easier to write, and to troubleshoot, it does require updates in 2 places if you change things, which increases long term cost to maintain.

====General Structure of a basic rule====

I recommend keeping a structure, in general I run with:
Categorize Everything
THEN
Pay Everything

Categorize Public Holidays
Categorize Leave
Categorize Overtime (if applicable)
Categorize Any other allowances/exceptions
Categorize "Ordinary Time"

This sets everything up with the complexity at the start.

=====Category publicholiday=====

This category allows you to define when to pay public holiday rates.  This needs to cope with 3 situations:
When someone is on leave during a public holiday, they should not have Leave hours deducted, they should earn Public Holiday Not Worked hours.
'''New Zealand consideration - Ordinary Working Day'''
In New Zealand it's important to know if something is an ordinary working day for an employee.
This means that someone working a Public Holiday in New Zealand needs to receive different entitlements depending on whether they regularly work that day.
Since the calculations for "is this an ordinary working day?" are vague in legislation/interpretation, we cannot really determine a rule for this.
There will likely be 3 types of pattern here:
'''Salaried/set hours employees'''
Salaried employees, or employees with very set working patterns, will likely need to have Alternative Holiday accrual by standard if they work a public holiday.
If they don't work, they just get paid public holiday not worked.
'''Waged employees with variable hours'''
Waged employees whose schedules aren't fully set will probably need to be set up on an alternative rule, or have an exception built into the overall rule, so that they do not accrue Alternative Holidays by default.
'''Casual Employees/employees employed specifically to work public holiday cover'''
These employees may not be eligible for public holiday rates/alt day accrual.  
However, it is reasoanbly common for casuals to receive public holiday incentives even if not legislatively required.  Check with site being implemented.

''Which is better to have as default?''
This will depend strongly on industry.  

'''Work types'''
Because of the above complexity, you will likely need 3 work types for handling Public Holidays:
__Public Holiday Not Worked __
This is used for workers who don't work that day at all.
__Public Holiday Worked - Otherwise Working Day __
This is used to define explicitly a day as otherwise working day and that the employee should receive alternative leave accrual.
__Public Holiday Worked - Not OWD. __
This is used to define explciitly a day that should not receive alternative leave accrual.

I'd also recommend thinking about a 4th category if casuals do not qualify for public holiday rates:
__Not a Public Holiday__
This is just used to override the system and say a public holiday doesn't exist.  This shouldn't generally be necessary.

=====Category Paid Leave & Category Unpaid Leave=====

Assigning Leave categories can make it easier to exclude all of your leave types from affecting other rules.  In particular, defining a "Unpaid leave" category, and then everything that isn't unpaid leave but is leave as Paid Leave can help simplify writing ordinary hours calculations for overtime.

This can help with maintenance as well, since if there are extra unpaid leave categories to add, you can just add them to the unpaid leave category, and assume any other categories added will work normally.

=====Category Overtime=====

Overtime can be calculated.  This can get complicated and as of 9.7 we're unable to properly support Period based overtime. (Over 40 hours per week = overtime).  
The existing overtime engine as at 9.7 can easily cover "time of day" based overtime.

=====Categorize Allowances, etc=====

This could be combined straight into the Payment step, but it's likely to be easier to set up by doing this as 2 rules if you need to reuse the logic at all.

=====Category Ordinary Time=====

We require Ordinary Time to be explicitly defined, if you don't define hours as having at least 1 category they don't get paid.

=====Pay Everything=====

While a long section of rule, this should be reasonably easy to configure.

====Individual Conditions explained====

=====Nested Conditions=====

A bracket for conditions under it. See Rule Logic above. Will always need conditions inside it to be valid.

=====Timesheet has specific types=====

This refers to Timesheet types (Leave, shifts or Not Rostered)

=====Worked Hours=====

Can also be described as "Above X Hours", "Only hours over" or "In Excess of"
This is a great way to say "If someone works more than 8 hours in a day, all hours after 8 are overtime"
If you're trying to say "When someone works exactly 8 hours, they get an allowance" then I recommend using:
"Worked Hours > 7.99"
And apply Pay Item by "Day" or "Timesheet" (depending on what best matches your needs. Be aware of split shifts, and overnight shifts, when choosing these settings, especially for businesses that regularly work across midnight.

=====Under contracted hours=====

If hours do not match the hours the employee is contracted for, bring up results.

Explanation needs rewriting

=====On specific days=====

The On specific days condition matches the portion of timesheets that fall on given day(s) of the week. 

The way in which we match the time depends on the Match type configuration.

=====On specific date=====

On a specific day of the year. I'm not clear on the practical use for this, but it is configurable separate from the general public holiday system.

=====Group Timesheets=====

Allows you to group other timesheets together. Especially useful at anywhere someone works split shifts, or is clocking in to different departments/roles, to make sure you evaluate their time correctly for award calculations.

=====Timesheet matches an above rule=====

To be used with the "Categories" action.
((({S:Warn}
You must actually list the names of assigned categories from above rules to exclude that information. Leaving this blank is bad practice.)))

=====Exceeding X hours in a period=====

Allows you to evaluate time across weeks or months, and has specific starting calculation date. 

'''This rule is deprecated, and is known to have some calculation quirks. Go-forward rules should be written using Limit Matches .'''


=====Limit Matches=====

Options are: Day, week, Timesheet, Match, Group, Pay Run.
If you want this to apply for every day I personally recommend setting to "On Specific Days" and selecting every day of the week.

The Pay Run option works using the employee's Pay Run Template.

=====Top up timesheet to X hours=====

The Top up timesheet to X hours condition creates matches whether the length of worked hours in a timesheet does not reach a required threshold of hours.

 ((({S:Hint}
This is different to the Minimum length action, in that this condition creates matches for the missing hours, but does not change the timesheet end time(s). 

This condition has no impact on the end time of the timsheet, and therefore other conditions that look at the length of the timesheet, or its end time will continue to see the ‘original' end time of the timesheet as it has been recorded.

The minimum length action changes the end time of the timesheet data, meaning that subsequent conditions that look at the length of a timesheet, or the end time of a timesheet, see the ‘adjusted’ end time as calculated by the action.)))

=====insufficient hours between prior timesheet=====

The Insufficient hours between prior timesheet condition creates matches whether the period of time between the start of the current timesheet and the end of the previous timesheet is less than the threshold.

To identify when an employee's shifts are too close together.
Likely to need to be used in conjunction with Grouped Timesheets if employee works in multiple departments/cost centres/locations/positions.

=====Employee has a pay tag=====

The Employee has a pay tag condition creates matches whether the employee on the shift or timesheet has one of the listed pay tags in the configuration. If the employee has any of the pay tags, a match is created.

Allows you to query Pay Tags, which are set per employee. 
As an example, this can allow you to specify some of your workers as getting an allowance which others do not without needing to create 2 rules.

=====On a public holiday=====

The On a public holiday condition creates matches whether the shift or timesheet falls on a public holiday.

The way in which we match the time depends on the Match type configuration.

Note: If a public holiday qualifies for Mondayisation, then the condition matches the Mondayised date of the public holiday if the employee is not scheduled to work on the original public holiday date.

i.e. if a public holiday falls on a Saturday, and employee does not work a shift on the Saturday (according to the employee’s standard hours) the public holiday is treated as the Monday following the original public holiday date)
((({S:Danger}Did not seem to be working correctly for Summer 2022.)))


For detecting public holidays.
((({S:Danger} Due to a fringe issue where 2 Public Holidays are created on the same day, it is strongly recommended to only use this for Categorizing time. Do not pay directly from this condition.)))

=====Between certain times=====

The Between certain times condition matches the portion of timesheets that falls in a given time window on any given day. 

Only the portion of time that falls in the window is matched in this condition.

=====Has specific work types=====

The Has specific work types condition creates matches shifts or timesheets associated with one or more of the configured work types in the condition settings.

When a match is found, the whole timesheet is matched.

=====Has leave types=====

The Has leave types condition creates matches shifts or timesheets associated with a leave request that contains one or more of the configured leave types.

When a match is found, the whole timesheet is matched.

=====Within the rostered hours=====

The Within rostered hours condition matches the portion of timesheets that are within the rostered hours in the associated shift. 

For example, when the Within rostered hours condition is configured, the condition matches time on the timesheet within the hours of the shift, allowing us to use the inverse to find timesheet hours that are outside of the employee’s rostered shift. This might be useful for determining when an employee was asked to work later than usual, but the (additional) hours worked fall short of a consecutive hours or time of day threshold for attracting penalties.

Each timesheet is evaluated individually.

=====Within the rostered length=====

The Within rostered length condition matches time for the employee that is within the original rostered length of the shift. 

This condition can be used in the inverse to apply a match to timesheet hours that are in excess of the original rostered length of the shift, regardless of how the exceed the length of the shift. 

Each timesheet is evaluated individually.
((({S:Hint}
These two rules differ in the way they look at the rostered shift. <br />The first will flag if someone starts & finishes late, but only works their normal number of hours. <br />The second only flags hours above roster, so it doesn't care when I start, just how many hours worked.)))

=====Within employees standard hours=====

Identifies time that's within the employee's standard hours. Useful for figuring out overtime/callbacks/etc. 

=====Timesheet has locations=====

Used to identify staff at particular locations

=====Time worked without a break=====

For identifying when an employee qualifies for a late/no break allowance.


====Individual Actions Explained====

=====Multiple Actions=====

Do several actions all at once. 
Note, these happen simultaneously, not in order. In general use separate rules rather than Multiple Actions.

=====Category=====

Assign a category to some hours, which allows you to later pay them.

=====Group Timesheets=====

Group timesheets together, which allows you to run later rule conditions.

=====Minimum Length=====

Increases the number of hours to meet the minimum length.

=====Pay Item=====

Pay an item.

No RepliesBe the first to reply