Tips and Tricks Best Practices: Annual Leave Accrual Calculation based on different leave limits
Hello Friends, I am back again with another interesting blog and a solution approach. I am pretty sure you won’t be bored with this topic and the solution that I have.
Overview and requirement
You might have heard of a very common requirement around recalculating annual leave accruals based on different leave types or time types. For example, If an employee takes say a long term unpaid leave, then you need to prorate the accruals for that year.
Say as an employee you get 30 days of paid annual leave. The employee takes two months of unpaid leave approx. 60 days. Then the prorated balance is approx.: 30 * ((365-60) / 365)) = 25 days
This is a very straight forward case and relatively easier to deal with and a most common one as well.
What if we add more complexities to this? Here is a twist to this story now
In an organization, a paid annual leave of 30 days is provided in a calendar year. Further, we have the following leave limits in place.
- Study Leave: 30 days limit in a year. The accruals should be recalculated only if the employee crosses study leave limit of 30 days in a year. Until they reach 30 days of study leave, no accruals are recalculated.
Example 1: If my total study leave in a year is 20 days, I will still continue to get full accrual
of 30 days for that year
Example 2: If my total study leave in a year is 35 days, then my prorated accrual
is 30 * ( (365- 5 / 365)) = 29.5 days as I have exceeded the limit by 5 days for study leave
2. Parental leave: 60 days limit
3. Military Leave: 10 days limit
And so, on
I have come across a requirement where there are 10 such limits for 10 different time types. Well, it is no longer a straightforward case as discussed in the introduction . We need to take care of each time type limit and consider recalculating accruals only when they cross their individual limits.
Current most common approach
What comes to our mind when we see this requirement?
The most common approach that some follow is:
- Use “Get Absence In Days For Period Based On Working Days For Time Types ()” rule function to check the consumed absences for each time type like study leave, military leave etc.
- Use multiple IF Else Conditions to check if they have crossed the limit like:
If (Get Absence In Days For Period Based On Working Days For Time Types : Study Leave) > 30 && (Get Absence In Days For Period Based On Working Days For Time Types : Military Leave) > 10 && (Get Absence In Days For Period Based On Working Days For Time Types : Parental Leave )> 60
Then
…..
Else If (Get Absence In Days For Period Based On Working Days For Time Types : Study Leave) > 30 && (Get Absence In Days For Period Based On Working Days For Time Types : Military Leave) > 10
Then
——
And so on
Did you observe that we need to check for each and every possible outcome with this approach. There will be too many If and else and permutation and combinations with each leave type. It can happen that:
- The employee has crossed only study leave limit for the year
- The employee has crossed only military leave limit for the year
- The employee has crossed only parental leave limit for the year
- The employee has crossed Study leave and Military leave both for the year
- The employee has crossed Study leave and Parental leave both for the year
- The employee has crossed Parental leave and Military leave both for the year
- Employee has crossed all three leave limits in a year
- Employee has not crossed any leave limit for the year
This itself has 8 If else conditions to check for each possible case for 3 time types. Imagine if you have 10 such time types with different leave limits for each time type. Your rule would become mammoth figuring out all if else conditions and different combinations. And naturally, it would be difficult to trouble shoot and maintain it in future.
What if I tell you a method or a trick where you could achieve this with just 1 condition? You might be thinking that I might be joking or just blabbering some random stuff. But believe me , I am serious. It is possible to achieve all the above just using 1 rule block. Well, if you are interested read the solution below and thank me later if you find it useful. This riddle can be solved with a game of mathematics in simple words!!
Please note: We have also used the below approaches in some of our SAP SuccessFactors best practices solution. You can also have a look at Finland Time Off best practices which has this concept.
Better approach / Solution
Create different variables in your rule to get absences in a period for each time type :
The concept used is below:
We start with taking difference between the time type limit and the get absence in a period rule function
Say in this case the First value is the time type limit. Study leave has 30 days. The variable cust_testAccrualLimit.num is 30 days
The second value is the result from Get Absences in a period and is stored in cust_testAccrualLimit.num2
Say an employee takes 35 days of study leave in a year.
So the component with minus () would give us (30 -35) = -5 days
Further Minimum of (0, -5) is -5
Further opposite sign of -5 is 5 days. This correctly translates into 5 days of study leave limit crossed for the year now.
Another example
Say an employee takes 20 days of study leave in a year.
So the component with minus () would give us (30 -20) = 10 days
Further Minimum of (0, 10 ) is 0
Further opposite sign of 0 is 0 itself. This means employee has not crossed any limit of study leave for that year or in other words its 0 days.
If we use the same concept in the business rule, then it translates into the below snippet:
As you can see, we are using the same concept described above. We have created three variables for three different leave types as described in the overview section.
These variables will store either a positive value ( if the limit was crossed and by how much beyond a threshold like 30 days for study leave) or a zero value (if the limit is not crossed)
Then you can just use these variables in the rule block like below
We take the total number of eligible days for the year and subtract them with those variables. So for instance in our example, if study leave limit (5 days) was breached for the year and other leave types did not cross the limit, then this would be
365 – (5) –(0) – (0) = 360 days
Further the annual leave accrual is prorated accordingly: 30 * 360/365 days.
With this approach we have effectively reduced so many if else conditions and handled this in one block itself. The above single block handles all such combinations for multiple leave types. If the limit for a leave type has not yet breached, then they would have a 0 , else will have a positive value.
Testing
Now let’s test this for one employee.
The employee initially has 30 days of annual leave accrual
The employee takes study leave in two chunks spread across Jan, Feb and March
The limit for Study leave is 30 days. Total consumed is 24+11 – 30 = 35 days. Hence exceeded the limit by 5 days. The other leave types have not breached the limit. hence they will be 0 days
i.e 366 – Study Limit Crossed (5 days) – Parental Leave limit crossed (0 days) – Military Leave limit crossed (0 days)
Accrual is recalculated accordingly.
Now say the employee applies a military leave of 25 days. Limit of military leave is 10 days. So, the employee has exceeded the limit by 25-10 = 15 days for the year
This means in that year; the employee has crossed the study leave limit by 5 days and military leave limit by 15 days. So overall 20 days. The recalculated accrual now is
Lets verify if our calculation is correct :
((366-5-15))/366 * 30 = 28.36
As you see our result is perfect. We are able to handle multiple leave limits in one single block
In essence, we have handled all if and else’s in a single block. It is very simple to comprehend this. In a normal if else we would be processing the block by checking if the combination of different time types have crossed the limit or not (see the 8 if else examples I gave above) whereas in this single block , the leave types not crossing the limit always returns 0 days and only leave types crossing the limit returns a positive value. If you subtract , add , or do whatever with 0, the result remains the same. And hence the end result contains the reduced accrual value impacted by the leave types which crossed the limit (with positive result)