Skip to content

Commit 125ec0a

Browse files
Christopher-Chianellitriceo
authored andcommitted
chore: Remove real time planning classes and fields from employee scheduling
- Also, makes availability check for overlaps instead of same day
1 parent afef99c commit 125ec0a

File tree

10 files changed

+34
-256
lines changed

10 files changed

+34
-256
lines changed

use-cases/employee-scheduling/src/main/java/org/acme/employeescheduling/domain/EmployeeSchedule.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,12 @@ public class EmployeeSchedule {
2525
@PlanningScore
2626
private HardSoftScore score;
2727

28-
private ScheduleState scheduleState;
29-
3028
private SolverStatus solverStatus;
3129

3230
// No-arg constructor required for Timefold
3331
public EmployeeSchedule() {}
3432

35-
public EmployeeSchedule(ScheduleState scheduleState, List<Availability> availabilities, List<Employee> employees, List<Shift> shifts) {
36-
this.scheduleState = scheduleState;
33+
public EmployeeSchedule(List<Availability> availabilities, List<Employee> employees, List<Shift> shifts) {
3734
this.availabilities = availabilities;
3835
this.employees = employees;
3936
this.shifts = shifts;
@@ -44,14 +41,6 @@ public EmployeeSchedule(HardSoftScore score, SolverStatus solverStatus) {
4441
this.solverStatus = solverStatus;
4542
}
4643

47-
public ScheduleState getScheduleState() {
48-
return scheduleState;
49-
}
50-
51-
public void setScheduleState(ScheduleState scheduleState) {
52-
this.scheduleState = scheduleState;
53-
}
54-
5544
public List<Availability> getAvailabilities() {
5645
return availabilities;
5746
}

use-cases/employee-scheduling/src/main/java/org/acme/employeescheduling/domain/ScheduleState.java

Lines changed: 0 additions & 104 deletions
This file was deleted.

use-cases/employee-scheduling/src/main/java/org/acme/employeescheduling/domain/Shift.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import ai.timefold.solver.core.api.domain.lookup.PlanningId;
88
import ai.timefold.solver.core.api.domain.variable.PlanningVariable;
99

10-
@PlanningEntity(pinningFilter = ShiftPinningFilter.class)
10+
@PlanningEntity
1111
public class Shift {
1212
@PlanningId
1313
private String id;

use-cases/employee-scheduling/src/main/java/org/acme/employeescheduling/domain/ShiftPinningFilter.java

Lines changed: 0 additions & 12 deletions
This file was deleted.

use-cases/employee-scheduling/src/main/java/org/acme/employeescheduling/rest/DemoDataGenerator.java

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.acme.employeescheduling.domain.AvailabilityType;
2424
import org.acme.employeescheduling.domain.Employee;
2525
import org.acme.employeescheduling.domain.EmployeeSchedule;
26-
import org.acme.employeescheduling.domain.ScheduleState;
2726
import org.acme.employeescheduling.domain.Shift;
2827

2928
@ApplicationScoped
@@ -59,15 +58,6 @@ public EmployeeSchedule generateDemoData() {
5958
int initialRosterLengthInDays = 14;
6059
LocalDate startDate = LocalDate.now().with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
6160

62-
ScheduleState scheduleState = new ScheduleState();
63-
scheduleState.setFirstDraftDate(startDate);
64-
scheduleState.setDraftLength(initialRosterLengthInDays);
65-
scheduleState.setPublishLength(7);
66-
scheduleState.setLastHistoricDate(startDate.minusDays(7));
67-
scheduleState.setTenantId(EmployeeScheduleResource.SINGLETON_SCHEDULE_ID);
68-
69-
employeeSchedule.setScheduleState(scheduleState);
70-
7161
Random random = new Random(0);
7262

7363
int shiftTemplateIndex = 0;
@@ -143,37 +133,6 @@ private List<Shift> generateShiftForTimeslot(LocalDateTime timeslotStart, LocalD
143133
return shifts;
144134
}
145135

146-
public void addDraftShifts(EmployeeSchedule schedule) {
147-
List<Employee> employees = schedule.getEmployees();
148-
Random random = new Random(0);
149-
150-
List<Shift> shifts = new LinkedList<>();
151-
List<Availability> availabilities = new LinkedList<>();
152-
int countAvailability = schedule.getAvailabilities().stream()
153-
.map(Availability::getId)
154-
.mapToInt(Integer::parseInt)
155-
.max()
156-
.orElse(0);
157-
AtomicInteger countShift = new AtomicInteger(schedule.getShifts().stream()
158-
.map(Shift::getId)
159-
.mapToInt(Integer::parseInt)
160-
.max()
161-
.orElse(0));
162-
for (int i = 0; i < schedule.getScheduleState().getPublishLength(); i++) {
163-
Set<Employee> employeesWithAvailabitiesOnDay = pickSubset(employees, random, 4, 3, 2, 1);
164-
LocalDate date = schedule.getScheduleState().getFirstDraftDate()
165-
.plusDays(schedule.getScheduleState().getPublishLength() + i);
166-
for (Employee employee : employeesWithAvailabitiesOnDay) {
167-
AvailabilityType availabilityType = pickRandom(AvailabilityType.values(), random);
168-
availabilities.add(new Availability(Integer.toString(++countAvailability), employee, date, availabilityType));
169-
}
170-
shifts.addAll(generateShiftsForDay(date, random));
171-
}
172-
schedule.getAvailabilities().addAll(availabilities);
173-
shifts.forEach(s -> s.setId(Integer.toString(countShift.incrementAndGet())));
174-
schedule.getShifts().addAll(shifts);
175-
}
176-
177136
private <T> T pickRandom(T[] source, Random random) {
178137
return source[random.nextInt(source.length)];
179138
}

use-cases/employee-scheduling/src/main/java/org/acme/employeescheduling/rest/EmployeeScheduleResource.java

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.acme.employeescheduling.rest;
22

3-
import java.time.LocalDate;
43
import java.util.Collection;
54
import java.util.UUID;
65
import java.util.concurrent.ConcurrentHashMap;
@@ -27,7 +26,6 @@
2726
import ai.timefold.solver.core.api.solver.SolverStatus;
2827

2928
import org.acme.employeescheduling.domain.EmployeeSchedule;
30-
import org.acme.employeescheduling.domain.ScheduleState;
3129
import org.acme.employeescheduling.rest.exception.EmployeeScheduleSolverException;
3230
import org.acme.employeescheduling.rest.exception.ErrorInfo;
3331
import org.eclipse.microprofile.openapi.annotations.Operation;
@@ -195,39 +193,6 @@ public EmployeeSchedule getStatus(
195193
return new EmployeeSchedule(schedule.getScore(), solverStatus);
196194
}
197195

198-
@Operation(
199-
summary = "Publish a schedule.")
200-
@APIResponses(value = {
201-
@APIResponse(responseCode = "200", description = "The schedule updated.",
202-
content = @Content(mediaType = MediaType.APPLICATION_JSON,
203-
schema = @Schema(implementation = EmployeeSchedule.class))),
204-
@APIResponse(responseCode = "404", description = "No schedule found.",
205-
content = @Content(mediaType = MediaType.APPLICATION_JSON,
206-
schema = @Schema(implementation = ErrorInfo.class))),
207-
@APIResponse(responseCode = "500", description = "Exception while trying to publish the schedule.",
208-
content = @Content(mediaType = MediaType.APPLICATION_JSON,
209-
schema = @Schema(implementation = ErrorInfo.class)))
210-
})
211-
@POST
212-
@Path("{jobId}/publish")
213-
@Produces(MediaType.APPLICATION_JSON)
214-
public void
215-
publish(@Parameter(description = "The job ID returned by the POST method.") @PathParam("jobId") String jobId) {
216-
if (!getStatus(jobId).getSolverStatus().equals(SolverStatus.NOT_SOLVING)) {
217-
throw new IllegalStateException("Cannot publish a schedule while solving is in progress.");
218-
}
219-
EmployeeSchedule schedule = getEmployeeScheduleAndCheckForExceptions(jobId);
220-
ScheduleState scheduleState = schedule.getScheduleState();
221-
LocalDate newHistoricDate = scheduleState.getFirstDraftDate();
222-
LocalDate newDraftDate = scheduleState.getFirstDraftDate().plusDays(scheduleState.getPublishLength());
223-
224-
scheduleState.setLastHistoricDate(newHistoricDate);
225-
scheduleState.setFirstDraftDate(newDraftDate);
226-
227-
dataGenerator.addDraftShifts(schedule);
228-
jobIdToJob.put(jobId, Job.ofSchedule(schedule));
229-
}
230-
231196
private record Job(EmployeeSchedule schedule, Throwable exception) {
232197

233198
static Job ofSchedule(EmployeeSchedule schedule) {

use-cases/employee-scheduling/src/main/java/org/acme/employeescheduling/solver/EmployeeSchedulingConstraintProvider.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,11 @@ Constraint oneShiftPerDay(ConstraintFactory constraintFactory) {
8181

8282
Constraint unavailableEmployee(ConstraintFactory constraintFactory) {
8383
return constraintFactory.forEach(Shift.class)
84-
.join(Availability.class, Joiners.equal((Shift shift) -> shift.getStart().toLocalDate(), Availability::getDate),
85-
Joiners.equal(Shift::getEmployee, Availability::getEmployee))
84+
.join(Availability.class,
85+
Joiners.equal(Shift::getEmployee, Availability::getEmployee),
86+
Joiners.overlapping(Shift::getStart, Shift::getEnd,
87+
availability -> availability.getDate().atStartOfDay(),
88+
availability -> availability.getDate().plusDays(1).atStartOfDay()))
8689
.filter((shift, availability) -> availability.getAvailabilityType() == AvailabilityType.UNAVAILABLE)
8790
.penalize(HardSoftScore.ONE_HARD,
8891
(shift, availability) -> getShiftDurationInMinutes(shift))
@@ -91,8 +94,11 @@ Constraint unavailableEmployee(ConstraintFactory constraintFactory) {
9194

9295
Constraint desiredDayForEmployee(ConstraintFactory constraintFactory) {
9396
return constraintFactory.forEach(Shift.class)
94-
.join(Availability.class, Joiners.equal((Shift shift) -> shift.getStart().toLocalDate(), Availability::getDate),
95-
Joiners.equal(Shift::getEmployee, Availability::getEmployee))
97+
.join(Availability.class,
98+
Joiners.equal(Shift::getEmployee, Availability::getEmployee),
99+
Joiners.overlapping(Shift::getStart, Shift::getEnd,
100+
availability -> availability.getDate().atStartOfDay(),
101+
availability -> availability.getDate().plusDays(1).atStartOfDay()))
96102
.filter((shift, availability) -> availability.getAvailabilityType() == AvailabilityType.DESIRED)
97103
.reward(HardSoftScore.ONE_SOFT,
98104
(shift, availability) -> getShiftDurationInMinutes(shift))
@@ -101,8 +107,12 @@ Constraint desiredDayForEmployee(ConstraintFactory constraintFactory) {
101107

102108
Constraint undesiredDayForEmployee(ConstraintFactory constraintFactory) {
103109
return constraintFactory.forEach(Shift.class)
104-
.join(Availability.class, Joiners.equal((Shift shift) -> shift.getStart().toLocalDate(), Availability::getDate),
105-
Joiners.equal(Shift::getEmployee, Availability::getEmployee))
110+
.join(Availability.class,
111+
Joiners.equal(Shift::getEmployee, Availability::getEmployee),
112+
Joiners.overlapping(Shift::getStart, Shift::getEnd,
113+
availability -> availability.getDate().atStartOfDay(),
114+
availability -> availability.getDate().plusDays(1).atStartOfDay())
115+
)
106116
.filter((shift, availability) -> availability.getAvailabilityType() == AvailabilityType.UNDESIRED)
107117
.penalize(HardSoftScore.ONE_SOFT,
108118
(shift, availability) -> getShiftDurationInMinutes(shift))

0 commit comments

Comments
 (0)