Oracle HCM Cloud Fast Formula: Absence Integration in a TCR — The AbsenceType Array, the GET_VALUE_SET Claim Lookup, and the Back-Fill WHILE Loop
Oracle HCM Cloud Fast Formula: Absence Integration in a TCR — The AbsenceType Array, the GET_VALUE_SET Claim Lookup, and the Back-Fill WHILE Loop
Oracle HCM Cloud Fast Formula: Absence Integration in a TCR — The AbsenceType Array, the GET_VALUE_SET Claim Lookup, and the Back-Fill WHILE Loop
AbsenceType array as a sparse parallel track, the GET_VALUE_SET lookup that resolves the OT-eligibility claim, the Out_Abs_Cd / Out_Abs_Hours output buckets, and the retroactive WHILE loop that reclassifies regular hours as overtime when an absence pushes the worker over the monthly cap.A TCR doesn't only track worked hours. Absence hours — sick leave, vacation, jury duty, bereavement — flow through the same parallel-array iteration framework, share the same monthly threshold arithmetic, and end up affecting the same output buckets. The formula has to handle them as first-class citizens of the period, not as a parallel pipeline.
This post walks through the absence integration pattern: how the AbsenceType array surfaces absence entries to the TCR, how GET_VALUE_SET resolves each absence to its OT-eligibility claim, how the Out_Abs_* output buckets carry the data downstream to payroll, and — the most interesting move in the whole formula — how the TCR retroactively reclassifies already-allocated regular hours as overtime when an absence pushes the worker over the monthly threshold.
A single worked example threads through the post: a worker with 156 worked hours, 8 hours of OT-eligible absence, against a 160 hour monthly threshold. Total counted time: 164 hours. The 4 hours over threshold have to become OT — but the absence portion can't be "OT" because it's not worked time. So four of the previously-allocated worked hours have to be reclassified.
AbsenceType — The Sparse Track in the Parallel Array Stack
Part 3 introduced the HWM_CTXARY_* parallel-array family — multiple DBIs and input variables co-indexed by nidx so that position 1 across every track refers to the same timecard entry. AbsenceType joins that stack as a sixth parallel track.
It behaves differently from the worked-time tracks in one important way: it's sparse. The framework populates AbsenceType[nidx] only on positions that represent absence transactions. Worked-time entries leave it empty. Phase markers leave it empty. The first move inside the loop body — before any allocation logic fires — is checking whether this position is an absence.
The detection pattern is a straightforward .EXISTS() check at the top of the loop body:
(
IF (AbsenceType.exists(nidx)) THEN
(
l_absence_code = AbsenceType[nidx]
l_absence_hours = measure[nidx]
/* Absence branch — claim lookup + bucket population */
)
ELSE
(
/* Worked-time branch — covered in Part 5 */
)
)
The Absence Claim ID Lookup with GET_VALUE_SET
Detecting that an entry is an absence is only the first step. Not every absence counts toward the worker's OT calculation — that's a configuration decision, defined per absence type and per worker eligibility profile. Sick leave might count toward the monthly cap. Unpaid leave might not. Bereavement might be excluded entirely.
The TCR resolves this through a value-set lookup that takes the worker's person ID and the absence type code, and returns the absence claim ID — a reference to the OT plan configuration that governs how this particular absence interacts with threshold arithmetic. A non-zero return means the absence is OT-eligible and should accumulate toward the monthly bucket. A zero return means it flows to the Out_Abs_* buckets for payroll but is excluded from the OT calculation.
|| '''|P_ABS_CODE=''' || l_absence_code || ''''
l_abs_claim_id = TO_NUMBER(GET_VALUE_SET('XX_ABS_CLAIM_LOOKUP_VS', l_params))
IF (l_abs_claim_id > 0) THEN
(
l_is_ot_eligible = 'Y'
)
ELSE
(
l_is_ot_eligible = 'N'
)
The value set itself joins the absence plan configuration tables against the worker's plan enrollment, returning the claim ID if a match exists and zero otherwise. Keeping the SQL inside the value set (rather than inside the formula) lets the database optimizer cache the query plan and lets administrators update eligibility rules without touching the Fast Formula.
Populating the Out_Abs Output Buckets
Two output arrays carry absence data out of the TCR and into downstream payroll processing:
Out_Abs_Cd[nidx]— the absence type code ('SICK','VAC','BEREAVE') so the payroll element for that absence type fires.Out_Abs_Hours[nidx]— the absence duration so the element receives a quantity to pay.
Both arrays are populated unconditionally for every detected absence entry, regardless of whether the absence is OT-eligible. The payroll downstream needs both values to issue absence pay; OT eligibility only affects the threshold arithmetic.
Out_Abs_Hours[nidx] = l_absence_hours
The Monthly Accumulator — Why Absence Hours Count Toward OT
This is the design choice that catches most engineers off guard the first time they trace through the formula: l_period_regular accumulates both worked hours and OT-eligible absence hours. Not just worked hours.
The reasoning is regulatory. Many OT regimes treat paid absence as "working time" for the purpose of calculating whether a worker has exceeded the period threshold — the rationale being that the worker would have been earning regular hours during that time if they hadn't been on leave, so excluding leave from the threshold would unfairly punish workers who take statutory time off. The TCR encodes this by adding eligible-absence hours to the same period accumulator that tracks worked hours:
(
l_period_regular = l_period_regular + l_absence_hours
)
The same line gets executed during the worked-time branch (covered in Part 5) for each worked hour. By the time the loop reaches END_PERIOD, l_period_regular holds the combined total: worked + OT-eligible-absence.
The Threshold Crossover Problem
Walk through the worked example. The worker accumulates:
- 156 worked hours across the month, each one initially classified as Regular and added to
Out_Measure_RegHoursduring DETAIL iterations. - 8 hours of sick leave entered on one day, OT-eligible (claim ID returned non-zero), added to
l_period_regularalongside the worked hours. - Monthly threshold: 160 hours.
Total combined time: 156 + 8 = 164 hours. Over threshold by 4.
The Back-Fill WHILE Loop — Retroactive Reclassification
The correction happens at END_PERIOD — the final position in the iteration loop, where the formula has visibility into the total counted time. The over-threshold amount is computed, and a WHILE loop runs that decrements Out_Measure_RegHours and increments Out_Measure_OT_150_Hours by an equal amount, one hour at a time, until the over-threshold amount has been fully redistributed:
(
l_over_threshold = l_period_regular - l_monthly_threshold
IF (l_over_threshold > 0) THEN
(
l_remaining_adjustment = l_over_threshold
WHILE (l_remaining_adjustment > 0) LOOP
(
Out_Measure_RegHours = Out_Measure_RegHours - 1
Out_Measure_OT_150_Hours = Out_Measure_OT_150_Hours + 1
l_remaining_adjustment = l_remaining_adjustment - 1
)
)
)
The total worked hours stay constant — only the classification changes. 156 worked = (152 Regular) + (4 OT 150%). The 8 absence hours remain in their own buckets, untouched.
The Output Bucket Reference
Four output buckets carry the full picture of the worker's month downstream to payroll. Each one represents a different category of compensable time, and the back-fill loop is what guarantees the four sums add up correctly:
Part 5 — Regular and OT Bucket Allocation with the Day-Type Branch, l_ovt_150 / l_ovt_200, and the l_OT_counter Cascade
The worked-time branch of the DETAIL iteration — how the formula decides, for every worked hour as it streams through the loop, whether to allocate it to Out_Measure_RegHours, Out_Measure_OT_150_Hours, or Out_Measure_OT_200_Hours based on the day type (public holiday, Saturday, Sunday, weekday) and the running daily total.