我在事实收集 DaySetting 方面遇到问题。
public class DaySetting {
String businessDate;
Integer weekNo;
Integer monthNo;
}
我还有一个班次:
public class Shift {
@PlanningId
private String id;
private LocalDateTime start;
private LocalDateTime end;
public Long getShiftDuration() {
long minutes = ChronoUnit.MINUTES.between(start, end);
return minutes;
}
public String getStartDate() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String dateStr = getStart().toLocalDate().format(formatter);
return dateStr;
}
}
日期设置可以采用如下值:
public class DaySetting {
String businessDate = 2024-06-01;
Integer weekNo = 1; // first week of June
Integer monthNo = 6;//June
}
public class DaySetting {
String businessDate = 2024-06-02;
Integer weekNo = 1; // first week of June
Integer monthNo = 6;//June
}
public class DaySetting {
String businessDate = 2024-06-09;
Integer weekNo = 2; // Second week of June
Integer monthNo = 6;//June
}
public class DaySetting {
String businessDate = 2024-06-10;
Integer weekNo = 2; // second week of June
Integer monthNo = 6;//June
}
我必须根据周来总结工作的持续时间没有值。对于第 1 周,有 2 个班次,将进行总结。前两个班次持续时间将汇总为第 1 周,
后两个班次将在第 2 周进行总结。
所以,到目前为止我在下面尝试过:
Constraint workingHoursLessThanMaximumInContractPerWeek(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(DaySetting.class)
.join(Shift.class)
.groupBy((daySetting, shift) -> day.getWeekNo(),
ConstraintCollectors.sumLong((daySetting, shift) -> shift.getShiftDuration()))
//Shift don't have weekNo field. It only have getStartDate() to get the business date,
//so we have to take the date value from DaySettings class and match with the date of Shift class. How to achieve this with the constraints.
.penalize(HardMediumSoftScore.ONE_SOFT, ((weekNo, sumValue))->{
return sumValue;
})
.asConstraint("Working Hours Greater Than Maximum In Contract Per Week");
}
我建议将
DaySetting
放入 Shift
以避免因跨多天的轮班(例如夜班)而产生歧义。此外,还应包括年份,否则在跨年度规划时间表时可能会出现问题。我将创建一个 WeekIdentifier
记录,将 LocalDate
映射到一年中的一年 + 一周:
public record WeekIdentifier(long year, long weekInYear) {
private final static WeekFields WEEK_DEFINITION = WeekFields.of(DayOfWeek.MONDAY, 7);
public static WeekIdentifier forDate(LocalDate date) {
return new WeekIdentifier(WEEK_DEFINITION.weekBasedYear().getFrom(date),
WEEK_DEFINITION.weekOfWeekBasedYear().getFrom(date));
}
}
然后我会添加一个方法来获取
WeekIdentifer
的 Shift
:
// Assumption, Shift is a @PlanningEntity with a @PlanningVariable employee
@PlanningEntity
public class Shift {
@PlanningId
private String id;
private LocalDateTime start;
private LocalDateTime end;
@PlanningVariable
private Employee employee;
public Long getShiftDuration() {
long minutes = ChronoUnit.MINUTES.between(start, end);
return minutes;
}
public WeekIdentifier getWeekIdentifier() {
return WeekIdentifier.forDate(getStart().toLocalDate());
}
public Employee getEmployee() {
return employee;
}
}
然后我会这样写
Constriant
:
Constraint workingHoursLessThanMaximumInContractPerWeek(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Shift.class)
.groupBy(Shift::getEmployee,
Shift::getWeekIdentifier,
ConstraintCollectors.sumLong(Shift::getShiftDuration))
.filter((employee, week, minutes) -> minutes > employee.getMaximumMinutesPerWeek())
.penalize(HardMediumSoftScore.ONE_SOFT, (employee, week, minutes) -> {
return minutes - employee.getMaximumMinutesPerWeek();
})
.asConstraint("Working Hours Greater Than Maximum In Contract Per Week");
}