У меня проблема со сбором фактов 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
}
Мне нужно суммировать продолжительность работы на основе значения WeekNo. на неделю№1 2 смены, будут суммироваться. Продолжительность первых двух смен суммируется за первую неделю,
Последующие две смены будут суммироваться за 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");
}