How can I handle Recurring Availability in Optaplanner?

56 Views Asked by At

I working off of the Optaweb (currently discontinued) platform, and I have an EmployeeAvailability class where I can define a startDateTime and an endDateTime and the state (one of the following: UNAVAILABLE, UNDESIRED, DESIRED). However these are singular events. What I want is for the EmployeeAvailability to be a recurring event. Where I can define its recurrence (e.g. every Friday) and then it automatically handles that when planning shifts. How can I do that? I'm not looking for very specific instructions, but higher level understanding of how this could be done.

For now, I have tried solving this by setting a flag isRecurring on each EmployeeAvailability and then when I'm planning the next week, I run a function to duplicate all EmployeeAvailability with isRecurring == True in the past week. This works for weekly recurrences, but its a pretty manual process.

Ideally, I would want:

1

There are 1 best solutions below

0
Christopher Chianelli On

One way to do it is to create a new class, EmployeeAvailabilityPattern, which have a method, appliesToShift(Shift), which return true if the Shift matches the availability pattern, false otherwise. Then the constraint that matches EmployeeAvailabilityPattern would look like this:

private static BiConstraintStream<EmployeeAvailabilityPattern, Shift> getConstraintStreamWithAvailabilityPatternIntersections(
            ConstraintFactory constraintFactory, EmployeeAvailabilityState employeeAvailabilityState) {
    return constraintFactory.forEach(EmployeeAvailabilityPattern.class)
        .filter(pattern -> pattern.getState() == employeeAvailabilityState)
        .join(Shift.class,
              equal(EmployeeAvailabilityPattern::getEmployee, Shift::getEmployee))
        .filter((pattern, shift) -> pattern.appliesToShift(shift));
}

Constraint unavailablePatternEmployeeTimeSlot(ConstraintFactory constraintFactory) {
    return getConstraintStreamWithAvailabilityPatternIntersections(constraintFactory, UNAVAILABLE)
               .penalizeConfigurableLong(CONSTRAINT_UNAVAILABLE_TIME_SLOT_FOR_AN_EMPLOYEE,
                        ((employeeAvailability, shift) -> shift.getLengthInMinutes()));
}