Как подвести итоги продолжительности смен за неделю

У меня проблема со сбором фактов 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");
    }
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
91
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я бы рекомендовал поставить 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");
}

Другие вопросы по теме

Как суммировать продолжительность смены с настройкой дня
Почему после обновления TimeFold guiScoreDirector.getIndictmentMap() возвращает значение null
Timefold: лучшие практики использования Spring JPA в проекте школьного расписания
Организация планирования с несколькими переменными планирования не будет постоянно пробовать некоторые сценарии
Как принудительно сгруппировать уроки для одной и той же серии учеников в одном временном интервале и в одном и том же таймфолде/оптапланнере комнаты?
Timefold Solver по умолчанию применяет ограничения на основе приоритета/порядка ограничений (из ConstraintProvider)?
Какие алгоритмы используются Timefold Solver по умолчанию, если вы не предоставляете никакой конфигурации?
Временной интервал: как создать ограничение на мощность оборудования на заданиях, запланированных для сотрудников?
Как получить последовательные пары уроков (в зависимости от их временного интервала) в Timefold?
OptaPlanner — используйте groupBy для избежаниеOvertime, но только на ресурсе, создающем сверхурочную работу