These docs are for v1.1. Click to read the latest docs for v2.0.

Shift Filling

Input

Filling in pre-defined shifts with employees according to contractual agreements that enforce fair and cost efficient rosters. The input requires you to make up:

  • contract definitions
  • open shifts
  • available employees

Additionally you can customise the solver behaviour by also changing the weights and priority of the constraints

Contract

A contract definition consists of a multitude of labour restricting constraints such as the maximum number of consecutive working days, the maximum number of shifts per day, number of resting days, etc...

PropertyTypeDescription
namestringUnique name identifier for a contract.
maxstring (duration iso8601)Maximum duration of all assigned shifts per employee.
minstring (duration iso8601)Minimum total duration of all assigned shifts per employee.
maxConsecutiveWorkDaysintegerMaximum number of days that one employee is allowed to work in a row.
maxShiftsDayintegerMaximum number of shifts during one day.
minRestBetweenShiftsSameDaystring (duration iso8601)Minimum duration between two shifts on the same day.
maxWorkingDaysintegerMaximum number of days working in the planning period.
latestShiftStartstring (time iso8601)Latest time an employee can start his shift.
earliestShiftStartstring (time iso8601)Earliest time an employee can start his shift.
{
    "name": "FULL",
    "max": "PT38H",
    "min": "PT5H",
    "maxConsecutiveWorkDays": 5,
    "maxShiftsDay": 2,
    "minRestBetweenShiftsSameDay": 30,
    "maxWorkingDays": 6,
    "latestShiftStart": "10:00:00",
    "earliestShiftStart": "02:00:00"
}

Shifts

The shifts represent the demand. These shifts need to be filled in with employees.
A shift in its simplest form can be defined by a shift start time (from) and an end time (to).
Shifts are uniquely identified by a name and require a specific skill.
You can define the number of employees that need to be assigned to this shift with value.

PropertyTypeDescription
namestringUnique id of the shift
fromstring (datetime)Starting time of the shift
tostring (datetime)End time of the shift
skillsarray of stringsSkill name references
costnumberFinancial cost related to this shift. Will be minimised when overconstrained.
valuenumberActual number of employees that should be assigned to this shift
prioritynumberForces a priority constraint on this shift with 1 being highest priority and 10 being the lowest.
employeesarray of stringsList of planned employees. Or can be used to pre-plan.

Employees

Define the resources or employees with whom you want to fill up the shifts.

PropertyTypeDescription
namestringUnique identifier for this employee
contractstringReference to contract for this employee.
skillsarray of stringList of skill references.
lastRestDatestring (date)The last date on which the employee had a rest before the planning period.
availabilityarray of stringAvailable date-time range of employee.
preferencearray of stringPreference towards certain shifts. (shift name)
periodRulesarray of PeriodRuleList of Period Rule

Period Rule

A shift rule for an employee that applies to a period of time.

PropertyTypeDescription
periodPlanningPeriodPlanning period for this period rule.
maxWorkingDaysintegerMaximum number of total days working in planning period.
minWorkingDaysintegerMinimum number of total days working in planning period.
minWorkingDurationstringMinimum duration to work in the planning period.
maxWorkingDurationstringMaximum duration to work in the planning period.
minRestDurationBetweenShiftsSameDaystringMinimum duration between two shifts on the same day in this planning period.
minRestDurationstringMinimum duration between any two shifts in this planning period.

Fairness

For a select group of employees and shifts you can require fair distribution of shifts per planning period. The planning period can be the entire planning period or a subset of it.

{
  //...
  "fairnessBuckets": 
  [
    {
      "employees": ["John", "Andrew"],
      "shifts": ["shift1", "shift2"],
      "period": {
       "from": "2020-01-01",
        "to": "2020-01-15"
      }
    }
  ]
}

Output

Simply fetch the solution in the jobs/:id/solution endpoint and receive the shift assignments.
For every shift defined by its name we will assign the best employee.

[
{
  "name": "Morning Shift 1",
  "from": "2020-06-26T08:00:00",
  "to": "2020-06-30T08:00:00",
  "employee": "John Dory",
  "skills": [
      "waiter",
      "bar"
  ]
}
]

Weights

We take into account many constraints. Let us know if there are any constraints that you think are missing.

NamePropertyDefault priorityDescription
Maximum Working DaysmaxWorkingDaysHARDAn employee should not work more than contract.maxWorkingDays days in the planning horizon.
Maximum HoursmaxHoursHARDAn employee should not work more than contract.max hours in the planning horizon.
Minimum HoursminHoursHARDAn employee should not work less than contract.min hours in the planning horizon. Please ensure minimum feasibility over the whole workforce.
Earliest Shift StartshiftStartHARDEarliest time contract.earliestShiftStart in a day when an employee is allowed to work
Latest Shift StartlatestShiftStartHARDEarliest time contract.latestShiftStart in a day when an employee is allowed to start work
Latest Shift EndshiftEndHARDLatest time contract.latestShiftEnd in a day when an employee is allowed to end work
Maximum Shift LengthmaxShiftHARDMaximum time contract.maxShiftLength that an employee is allowed to work
DayOfWeek WorkingdayOfWeekHARDRestricts employee availability based on days in the week that
Minimum Shift LengthminShiftHARDMinimum time contract.maxShiftLength that an employee is allowed to work
Maximum Shifts On Same DaysameDayHARDMaximum number of shifts that an employee is allowed to work
Minimum Rest On Same DaysameDayMinRestHARDMinimum resting period between two shifts on the same day
Employee AvailabilityavailabilityHARDDate-time range of employee's availability
Locked AssignmentlockedHARDTake into account assignments that are fixed during the solve
Maximum Consecutive Working DaysmaxConsecutiveHARDNo more than contract.maxConsecutiveWorkDays consecutive shifts.
Minimum RestminRestHARDMinimum resting between two shifts (irrespective of shifts)
No Concurrent AssignmentsconcurrentHARDAn employee cannot have two assignments on the same time. (This should never happen)
Skill Requirement for shiftsrequirementsHARDMultiple shifts can have a shared requirement for a skill
Employee Skill MatchskillsHARDAssign employees to match according to their skills and the required skills for a shift
Travel TimedistanceSOFTTravel from home to shift location
PriorityprioritySOFTShift Priorities
Shift Employee PreferenceprefMEDIUMA preference for a certain shift assignment for an employee
Financial CostscostsSOFTSome shifts incur a higher cost when they are assigned to (opposite of priority)
Wage Costs per EmployeewagesSOFTHourly wage cost per employee influences choice of employee
Unassigned EmployeeunassignedMEDIUMMinimise the number of unassigned employees
Employee Skill Match SoftsoftSkillsSOFTAssign employees to match according to their skills and the required skills for a shift (soft rule)
Employee Critical Skill MatchcriticalSkillsSOFTPrefer assigning critical shifts first
Employee working daysworkingHARDRespect employees working days
Shift blakclistblacklistHARDDo not assign shift to blacklisted employees
EfficiencyefficiencySOFTWeight of the efficiency cost per employee
Employee skill level matchsoftSkillLevelSOFTMatch the skill level

The weights and priorities of these constraints can be set in the solve request by adding a weights object to the request where each property that we want to customise has a string with the format "<weight><priority>" where <weight> is a positive integer number and <priority> can assume one of the following values: soft, medium and hard. hard constraints are more important than medium constraints and medium constraints are more important than soft. Between violations of two constraints with the same priority, the solver will choose the one with the minimum weight. In the example below we are customising the weights for the locked and unassigned constraints.

{
   "weights":{
          "locked" : "100hard",
          "unassigned" : "5soft"
    }
}