Skip to content

Shift

The shift module defines working hours for factory lines. It has three layers: base shifts, shift overrides, and available time — a pre-generated table that combines them for fast lookup at runtime.

Lines are divided into work groups ([Planning].[WorkGroup]). Each line can have multiple work groups.

Each work group has its own shift schedule.

Overrides can target individual work groups to apply different timings for specific lines or sections of a line.

Base shifts are defined in [Planning].[Shift].

Multiple shifts can exist simultaneously (e.g., Morning, General, Night).

A base shift applies to all work groups and all dates unless an override says otherwise.

Each shift defines a six-point attendance window:

FieldDescription
EarlyInTimeEarliest allowed clock-in
InTimeScheduled start time
LateInTimeLatest allowed clock-in
EarlyOutTimeEarliest allowed clock-out
OutTimeScheduled end time
LateOutTimeLatest allowed clock-out

The maximum possible shift span runs from EarlyInTime to LateOutTime.

The normal shift span runs from InTime to OutTime.

All durations are in minutes and exclude break time.

FieldDescription
ShiftMinutesNormal shift duration (OutTime − InTime)
MaxShiftMinutesMaximum shift duration (LateOutTime − EarlyInTime)
BreakMinutesTotal break duration

Breaks are stored as a JSON array in the Breaks column:

[
{ "start": "12:00:00", "end": "12:30:00" },
{ "start": "15:00:00", "end": "15:15:00" }
]

BreakMinutes is the sum of all break durations.

ShiftMinutes and MaxShiftMinutes are calculated after subtracting BreakMinutes.

[Planning].[ShiftOverride] allows modifying or disabling a base shift for specific contexts.

Each override references an existing shift via ShiftID.

Overrides cannot add new shifts, only modify or disable existing ones.

Each override narrows its scope using one or more of three optional filters.

At least one filter must be set.

FilterFieldsDescription
Work GroupWorkGroupIDApplies only to this work group
Date RangeStartDate + EndDateApplies only within this date range (both fields must be set together)
Day of WeekDayOfWeekApplies only on this day (e.g., "Friday")

When IsDisabled = 1, the override suppresses that shift for the matching context.

An [Planning].[AvailableTime] entry is still created for that shift on those days, but with IsDisabled = 1. Other shifts on the same day are unaffected.

When multiple overrides match the same shift on a given date for a given work group, the following rules determine which one applies:

Rule 1 — More filters wins. An override with more filters set takes precedence over one with fewer, regardless of which filters are used.

Rule 2 — Tie-break by filter rank. When two overrides have the same number of filters, compare their highest-ranked filter. The filter rank is: WorkGroup > DateRange > DayOfWeek. The override with the higher-ranked filter wins.

Full precedence order (highest to lowest):

Filters setFilter countScore
WorkGroup + DateRange + DayOfWeek318
WorkGroup + DateRange210
WorkGroup + DayOfWeek28
DateRange + DayOfWeek26
WorkGroup only13
DateRange only12
DayOfWeek only11

Example 1 — Shorter Friday shift for all lines

Add an override with DayOfWeek = "Friday" and the adjusted timings.

Leave WorkGroupID, StartDate, and EndDate null. Applies to every work group every Friday.


Example 2 — Ramadan timings for all lines

Add an override with StartDate = 2026-02-17 and EndDate = 2026-03-19 and the adjusted timings.

Leave WorkGroupID and DayOfWeek null. Applies to every work group throughout Ramadan.


Example 3 — Ramadan Fridays get their own schedule (coexisting with Examples 1 and 2)

Add a third override with the same StartDate/EndDate range, DayOfWeek = "Friday", and its own timings.

This 2-filter override has higher precedence than both the 1-filter Friday override (Example 1) and the 1-filter Ramadan range override (Example 2).

On Fridays during Ramadan, this override wins.


Example 4 — A specific work group has different timings year-round

Add a WorkGroup-only override (WorkGroupID set, date range and day of week null).

If the global Friday override from Example 1 also exists, the WorkGroup override wins on Fridays for this group — both have 1 filter, but WorkGroup outranks DayOfWeek.

To give this work group a different Friday schedule as well, add a second override with both WorkGroupID and DayOfWeek = "Friday" set.

That 2-filter override then takes precedence over the 1-filter WorkGroup-only override on Fridays.


Example 5 — Disable a night shift for a work group during Ramadan

Add an override with WorkGroupID and StartDate/EndDate set, and IsDisabled = 1.

The night shift’s [Planning].[AvailableTime] entries for that work group during Ramadan are created with IsDisabled = 1. All other shifts on those days are unaffected.

Day off rules are defined in [Planning].[DayOffRule]. Each rule is global — it applies to all work groups and all shifts on matching dates.

When a date matches any day off rule, all AvailableTime entries for that day are generated with IsDisabled = 1, regardless of what shifts or overrides exist.

TypeDescriptionStartDate / EndDateDayOfWeek
OneTimeA specific date or date rangeFull date values
AnnualRepeats every year on the same month/daySentinel year 1900; only month+day used
MonthlyRepeats every month on the same day(s)Sentinel year+month 1900-01; only day used
DayOfWeekRepeats every week on a given weekdayRequired

StartDate and EndDate are required for OneTime, Annual, and Monthly rules. For a single-day rule, set it equal to StartDate.

DayOfWeek rules leave both StartDate and EndDate null.

For DayOfWeek, one row per weekday. A “Weekend” rule covering Saturday and Sunday requires two rows sharing the same RuleName.

[Planning].[AvailableTime] is a pre-generated table storing the resolved shift timings for every work group × day combination.

This is the table queried at runtime for shift information — lookups never touch the base shift or override tables directly.

For each work group and each day in the selected year:

  1. All base shifts are evaluated.
  2. For each base shift, all applicable overrides are found (matching ShiftID, WorkGroupID, date range, and day of week).
  3. For each date and work group, the override with the highest precedence is selected. If none apply, the base shift is used.
  4. One AvailableTime row is written using the resolved timings.
  5. IsDisabled is set to 1 if the date matches any day off rule, or if the winning override has IsDisabled = 1.

A single day can have multiple AvailableTime rows if multiple base shifts are active (e.g., both a morning and a night shift run for the same work group).

Generation is triggered manually in the portal via a Generate button with a year picker.

Only shift times for the current and next year can be generated.

Only entries from today onward are deleted and regenerated. Past entries are left untouched.

ColumnDescription
ShiftDateThe specific date
ShiftIDReference to the base shift
WorkGroupIDReference to the work group
IsDisabled1 if the entry is a day off or the winning override is disabled
EarlyInTime / InTime / LateInTimeResolved clock-in window
EarlyOutTime / OutTime / LateOutTimeResolved clock-out window
ShiftMinutesNormal shift duration (excluding breaks)
MaxShiftMinutesMaximum shift duration (excluding breaks)
BreakMinutesTotal break duration
OvertimeMinutesComputed: MaxShiftMinutes − ShiftMinutes