Reputation: 67
I am trying to add a constraint that limits the amount of shifts assigned to employees in a ConstraintProvider class but I want to know if there is a better way to define this rather than having to add an attribute in both my @PlanningEntity and @PlanningVariable class ?
Here is my @PlanningEntity class attributes:
@PlanningEntity
@Entity
public class Shift {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "shiftId")
private int shiftId;
@Column(name = "startTime")
private LocalTime startTime;
@Column(name = "endTime")
private LocalTime endTime;
@Column(name = "day")
private String day;
@Column(name = "requiredSkillLevel")
private int requiredSkillLevel;
@Column(name = "shiftAmount")
private int shiftAmount;
@Transient
@PlanningVariable(valueRangeProviderRefs = "employee")
private Employee employee;
Here is my @PlanningVariable class:
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "employeeId")
private int employeeId;
@Column(name = "employeeName")
private String employeeName;
@Column(name = "skillLevel")
private int skillLevel;
@Column(name = "employeeType")
@Enumerated(EnumType.STRING)
private EmployeeType employeeType;
@Column(name = "associatedDepartment")
@Enumerated(EnumType.STRING)
private Departments associatedDepartment;
@Column(name = "weeklyShiftAllowance")
private int weeklyShiftAllowance;
My constraints are as follows:
public class ScheduleConstraintProvider implements org.optaplanner.core.api.score.stream.ConstraintProvider {
@Override
public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
return new Constraint[]{
requiredSkillLevelOfEmployeesForShifts(constraintFactory),
maximumNumberOfAllowableShiftsForEmployees(constraintFactory)
};
}
private Constraint maximumNumberOfAllowableShiftsForEmployees(ConstraintFactory constraintFactory) {
return constraintFactory.from(Shift.class)
.groupBy(Shift::getEmployee, sum(Shift::getShiftAmount))
.filter((employee, shiftAmount) -> shiftAmount > employee.getWeeklyShiftAllowance())
.penalize("Weekly Shift Allowance for each Employee",
HardSoftScore.ONE_HARD,
(employee, shiftAmount) -> shiftAmount - employee.getWeeklyShiftAllowance());
}
private Constraint requiredSkillLevelOfEmployeesForShifts(ConstraintFactory constraintFactory) {
return constraintFactory.from(Shift.class)
.groupBy(Shift::getEmployee, sum(Shift::getRequiredSkillLevel))
.filter((employee, requiredSkillLevel) -> requiredSkillLevel > employee.getSkillLevel())
.penalize("Required Skill Level for a Shift",
HardSoftScore.ONE_HARD,
(employee, requiredSkillLevel) -> requiredSkillLevel - employee.getSkillLevel());
}
}
Rather than having shiftAmount in my Shift class can I add something that treats each Shift as counting as 1 shift assignment ?
Upvotes: 1
Views: 363
Reputation: 27337
Yes
Instead of:
return constraintFactory.from(Shift.class)
.groupBy(Shift::getEmployee, sum(Shift::getShiftAmount))
do
return constraintFactory.from(Shift.class)
.groupBy(Shift::getEmployee, count())
(If you want a long, use countLong()
.)
Upvotes: 1