The question is for the TimeFold employee scheduling sample customization. I have a Shift class:
public class Shift {
@PlanningId
private String id;
private LocalDateTime start;
private LocalDateTime end;
private String location;
private String requiredSkill;
@PlanningVariable(allowsUnassigned = true)
private Employee employee;
private HashMap<String, HardMediumSoftScore> scoreMap = new HashMap<String, HardMediumSoftScore>();
}
I have a Employee class:
public class Employee {
@PlanningId
private String name;
private Set<String> skills;
private Contract contracts;
}
I have to add a rule when the same employee is assigned multiple shifts on the same date. Then the shift duration in minutes has to be summed up. I have tried like follows:
constraintFactory.forEach(Shift.class)
.join(Shift.class)
.filter((shift1, shift2) -> shift1.getEmployee() != null && shift2.getEmployee() != null)
.filter((shift1, shift2) -> shift1.getEmployee() == shift2.getEmployee())
.filter((shift1, shift2)-> shift1.getStartDate() == shift2.getStartDate())
.groupBy((shift1, shift2)->sum(shift1.getDuration()))
// The above line not working giving an error
.penalize(HardMediumSoftScore.ONE_MEDIUM) // Here I have to put the calculated sum value.
.indictWith((shift1, shift2)->List.of(new RuleShiftKey(shift1.getId(), "Rule1")))
// Here in the above line, I need the shift object to get the shift ID.
.asConstraint("Daywise score filter");
Please help to rewrite the rule.
I would use the employee and date as keys in the groupby:
constraintFactory.forEach(Shift.class) // For each shift
// Group shifts that...
.groupBy(Shift::getEmployee, // ...has the same employee
Shift::getStartDate, // ...on the same day
// and accumulate their results into
//...the number of shifts the employee has on that day
ConstraintCollectors.count(),
//...the total duration worked by the employee on that day
ConstraintCollectors.sumDuration(Shift::getDuration))
// Include only days where the employee worked more that one shift
.filter((employee, date, count, totalDuration) -> count >= 2)
// Penalize by the duration worked by the employee that day, in minutes
.penalize(HardMediumSoftScore.ONE_MEDIUM,
(employee, date, count, totalDuration) -> (int) totalDuration.toMinutes())
.indictWith((employee, date, count, totalDuration) -> List.of(new RuleShiftKey(date, "Rule1")))
.asConstraint("Daywise score filter");