issue-106 #107

Merged
sebastian merged 18 commits from issue-106 into master 2024-03-17 09:17:11 +01:00
9 changed files with 192 additions and 65 deletions
Showing only changes of commit f0d50a280e - Show all commits

View File

@ -8,6 +8,7 @@ import java.time.DayOfWeek;
public class TaskRepeatWeekDayInfo {
private int offset;
private long taskID;
private DayOfWeek dayOfWeek;
public int getOffset() {
return offset;
@ -24,4 +25,12 @@ public class TaskRepeatWeekDayInfo {
public void setTaskID(long taskID) {
this.taskID = taskID;
}
public DayOfWeek getDayOfWeek() {
return dayOfWeek;
}
public void setDayOfWeek(DayOfWeek dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
}

View File

@ -1,14 +1,15 @@
package core.entities.timemanager;
import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.api.models.timemanager.tasks.repeatinginfo.DeadlineStrategy;
import util.Tripel;
import util.Tupel;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.time.temporal.ChronoUnit;
import java.util.*;
@Entity
@Table(name = "tasks")
@ -54,14 +55,59 @@ public class Task {
this.finishable = taskFieldInfo.isFinishable();
}
public static Task cloneTask(Task task) {
public Tripel<Task, Collection<Task>, Collection<AbstractSchedule>> cloneTask() {
Collection<Task> clonedTasks = new ArrayList<>();
Collection<AbstractSchedule> clonedSchedules = new ArrayList<>();
Task clonedTask = new Task();
clonedTask.setTaskgroup(task.getTaskgroup());
clonedTask.setTaskName(task.taskName);
clonedTask.setEta(task.eta);
clonedTask.setFinished(false);
clonedTask.setFinishable(task.finishable);
return clonedTask;
clonedTasks.add(clonedTask);
clonedTask.setTaskgroup(this.getTaskgroup());
clonedTask.setTaskName(this.taskName);
clonedTask.setEta(this.eta);
clonedTask.setFinished(this.finished);
clonedTask.setFinishable(this.finishable);
clonedTask.setStartDate(this.startDate);
clonedTask.setDeadline(this.deadline);
for(AbstractSchedule abstractSchedule : this.basicTaskSchedules) {
AbstractSchedule clonedSchedule = abstractSchedule.cloneSchedule();
clonedSchedules.add(clonedSchedule);
}
Set<Task> clonedSubtasks = new HashSet<>();
for(Task task : this.subtasks) {
Tripel<Task, Collection<Task>, Collection<AbstractSchedule>> clonedSubtask = task.cloneTask();
clonedSubtask.getValue00().setParent(clonedTask);
clonedSubtasks.add(clonedSubtask.getValue00());
clonedTasks.addAll(clonedSubtask.getValue01());
clonedSchedules.addAll(clonedSubtask.getValue02());
}
clonedTask.setSubtasks(clonedSubtasks);
return new Tripel<>(clonedTask, clonedTasks, clonedSchedules);
}
public void shiftTask(long startingDayDifference, long endingDayDifference) {
this.setStartDate(this.getStartDate().plusDays(startingDayDifference));
this.setDeadline(this.getDeadline().plusDays(endingDayDifference));
for(AbstractSchedule abstractSchedule : this.basicTaskSchedules) {
abstractSchedule.shiftSchedule(startingDayDifference);
}
for(Task subtask: this.subtasks) {
subtask.shiftTask(startingDayDifference, endingDayDifference);
}
}
public void shiftTask(long startingDayDifference) {
this.setStartDate(this.getStartDate().plusDays(startingDayDifference));
this.setDeadline(this.getStartDate());
for(Task subtask: this.subtasks) {
subtask.shiftTask(startingDayDifference);
}
}
@ -253,4 +299,11 @@ public class Task {
public void increaseWorkTime(long minutes) {
this.workTime += (int) minutes;
}
public void shiftStartingTask(long dayDifference) {
this.setStartDate(this.getStartDate().plusDays(dayDifference));
for (Task subtask : this.subtasks) {
subtask.shiftTask(dayDifference);
}
}
}

View File

@ -39,4 +39,9 @@ public class TaskSerie {
this.tasks.add(taskSerieItem);
return taskSerieItem;
}
public void addItem(TaskSerieItem taskSerieItem) {
this.tasks.add(taskSerieItem);
taskSerieItem.setTaskSerie(this);
}
}

View File

@ -31,6 +31,12 @@ public class TaskSerieItem {
public TaskSerieItem() {
}
public TaskSerieItem(Task task, int itemIndex) {
this.taskSerie = null;
this.seriesIndex = itemIndex;
this.task = task;
}
public long getItemID() {
return itemID;
}

View File

@ -25,6 +25,7 @@ public interface TaskRepository extends CrudRepository<Task, Long> {
@Transactional
@Modifying
@Query(value = "DELETE FROM Task t WHERE t.taskID = ?1")
void deleteByTaskID(long taskID);
@Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND t.deadline is NOT NULL AND t.deadline < ?2 AND t.finished = FALSE")
@ -35,4 +36,12 @@ public interface TaskRepository extends CrudRepository<Task, Long> {
@Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND (t.startDate IS NULL OR t.startDate <= ?2) AND t.finished = FALSE")
List<Task> findAllActive(String username, LocalDate now);
@Query(value = "SELECT t FROM Task t WHERE t.taskgroup = ?1")
List<Task> findAllByTaskgroup(Taskgroup taskgroup);
@Modifying
@Transactional
@Query(value = "UPDATE Task t SET t.parent = null WHERE t.taskgroup = ?1")
void deleteTaskHierarchyWhereTaskgroup(Taskgroup taskgroup);
}

View File

@ -11,14 +11,13 @@ import core.repositories.timemanager.TaskSerieItemRepository;
import core.repositories.timemanager.TaskSeriesRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import util.Tupel;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.*;
@Service
public class TaskSeriesService {
@ -30,59 +29,79 @@ public class TaskSeriesService {
public ServiceExitCode createTaskSeries(TaskRepeatWeekInfo taskRepeatInfo) {
List<Task> createdTasks = new ArrayList<>();
Map<TaskRepeatWeekDayInfo, Tupel<Integer, Integer>> offsetMap = calcOffsetMap(taskRepeatInfo);
TaskSerie taskSerie = new TaskSerie();
List<AbstractSchedule> abstractSchedules = new ArrayList<>();
List<Task> clonedTasks = new ArrayList<>();
List<AbstractSchedule> clonedSchedules = new ArrayList<>();
int weekDayIndex = 0;
for(TaskRepeatWeekDayInfo weekDayInfo : taskRepeatInfo.getWeekDayInfos()) {
Optional<Task> requestedTask = taskRepository.findById(weekDayInfo.getTaskID());
if(requestedTask.isEmpty()) return ServiceExitCode.MISSING_ENTITY;
Task rootTask = requestedTask.get();
for(TaskRepeatWeekDayInfo taskRepeatDayInfo : taskRepeatInfo.getWeekDayInfos()) {
Optional<Task> task = taskRepository.findById(taskRepeatDayInfo.getTaskID());
if(task.isEmpty()) return ServiceExitCode.MISSING_ENTITY;
LocalDate currentDate = rootTask.getStartDate().plusDays(weekDayInfo.getOffset());
TaskSerieItem rootItem = taskSerie.addTask(task.get());
task.get().setTaskSerieItem(rootItem);
int itemIndex = weekDayIndex;
while(currentDate.isBefore(taskRepeatInfo.getEndDate())) {
var cloneResult = rootTask.cloneTask();
Task clonedRootTask = cloneResult.getValue00();
clonedTasks.addAll(cloneResult.getValue01());
clonedSchedules.addAll(cloneResult.getValue02());
LocalDate currentTaskDate = task.get().getStartDate().plusDays(taskRepeatDayInfo.getOffset());
while(currentTaskDate.isBefore(taskRepeatInfo.getEndDate())) {
Task clonedTask = Task.cloneTask(task.get());
clonedTask.setStartDate(currentTaskDate);
TaskSerieItem taskSerieItem = taskSerie.addTask(clonedTask);
clonedTask.setTaskSerieItem(taskSerieItem);
createdTasks.add(clonedTask);
abstractSchedules.addAll(cloneSchedules(task.get(), clonedTask));
currentTaskDate = currentTaskDate.plusDays(taskRepeatDayInfo.getOffset());
}
}
taskSerie.getTasks().sort(Comparator.comparing(o -> o.getTask().getStartDate()));
for(int i=0; i<taskSerie.getTasks().size(); i++) {
taskSerie.getTasks().get(i).setSeriesIndex(i+1);
if(taskRepeatInfo.getDeadlineStrategy() == DeadlineStrategy.DEADLINE_EQUAL_START) {
taskSerie.getTasks().get(i).getTask().setDeadline(taskSerie.getTasks().get(i).getTask().getStartDate());
} else {
if(i + 1 == taskSerie.getTasks().size()) {
int firstWeekDayIndex = i % taskRepeatInfo.getWeekDayInfos().size();
LocalDate reference_start = taskSerie.getTasks().get(firstWeekDayIndex).getTask().getStartDate();
LocalDate reference_deadline = taskSerie.getTasks().get(firstWeekDayIndex).getTask().getDeadline();
Duration duration = Duration.between(reference_start, reference_deadline);
long days = duration.toDays();
taskSerie.getTasks().get(i).getTask().setDeadline(taskSerie.getTasks().get(i).getTask().getStartDate().plusDays(days));
} else {
taskSerie.getTasks().get(i).getTask().setDeadline(taskSerie.getTasks().get(i+1).getTask().getStartDate().minusDays(1));
for(Task clonedTask : cloneResult.getValue01()) {
TaskSerieItem item = new TaskSerieItem(clonedTask, itemIndex);
taskSerie.addItem(item);
}
Tupel<Integer, Integer> offsetEntry = offsetMap.get(weekDayInfo);
clonedRootTask.shiftTask(offsetEntry.getValue00(), offsetEntry.getValue01());
currentDate = currentDate.plusDays(weekDayInfo.getOffset());
itemIndex += taskRepeatInfo.getWeekDayInfos().size();
}
weekDayIndex++;
}
taskSeriesRepository.save(taskSerie);
taskRepository.saveAll(createdTasks);
taskRepository.saveAll(clonedTasks);
taskSerieItemRepository.saveAll(taskSerie.getTasks());
scheduleRepository.saveAll(abstractSchedules);
scheduleRepository.saveAll(clonedSchedules);
return ServiceExitCode.OK;
}
private HashMap<TaskRepeatWeekDayInfo, Tupel<Integer, Integer>> calcOffsetMap(TaskRepeatWeekInfo weekInfo) {
HashMap<TaskRepeatWeekDayInfo, Tupel<Integer, Integer>> offsetMap = new HashMap<>();
weekInfo.getWeekDayInfos().sort(Comparator.comparing(TaskRepeatWeekDayInfo::getDayOfWeek));
for(int i=0; i<weekInfo.getWeekDayInfos().size(); i++) {
if(weekInfo.getDeadlineStrategy() == DeadlineStrategy.DEADLINE_EQUAL_START) {
int offset = weekInfo.getWeekDayInfos().get(i).getOffset()-1;
offsetMap.put(weekInfo.getWeekDayInfos().get(i), new Tupel<>(offset, offset));
} else {
int startingOffset = weekInfo.getWeekDayInfos().get(i).getOffset() -1;
DayOfWeek nextWeekday = null;
if(i == weekInfo.getWeekDayInfos().size()-1) {
nextWeekday = weekInfo.getWeekDayInfos().get(0).getDayOfWeek();
} else {
nextWeekday = weekInfo.getWeekDayInfos().get(i+1).getDayOfWeek();
}
DayOfWeek currentWeekDay = weekInfo.getWeekDayInfos().get(i).getDayOfWeek();
int endingOffset = startingOffset + Math.abs(nextWeekday.getValue() - currentWeekDay.getValue());
offsetMap.put(weekInfo.getWeekDayInfos().get(i), new Tupel<>(startingOffset, endingOffset));
}
}
return offsetMap;
}
public ServiceExitCode createTaskSeries(Task rootTask, TaskRepeatDayInfo taskRepeatInfo) {
if(taskRepeatInfo.getDeadlineStrategy() == DeadlineStrategy.FIX_DEADLINE) {
return ServiceExitCode.INVALID_PARAMETER;
@ -96,18 +115,8 @@ public class TaskSeriesService {
LocalDate currentTaskDate = rootTask.getStartDate().plusDays(taskRepeatInfo.getOffset());
while(currentTaskDate.isBefore(taskRepeatInfo.getEndingDate())) {
Task task = Task.cloneTask(rootTask);
task.setStartDate(currentTaskDate);
if(taskRepeatInfo.getDeadlineStrategy() == DeadlineStrategy.DEADLINE_EQUAL_START) {
task.setDeadline(currentTaskDate);
} else if(taskRepeatInfo.getDeadlineStrategy() == DeadlineStrategy.DEADLINE_FIT_START) {
task.setDeadline(currentTaskDate.plusDays(taskRepeatInfo.getOffset()-1));
}
TaskSerieItem taskSerieItem = taskSerie.addTask(task);
taskList.add(task);
task.setTaskSerieItem(taskSerieItem);
Tupel<Task, Collection<Task>> clonedTasks = rootTask.cloneTask();
abstractSchedules.addAll(cloneSchedules(rootTask, task));
currentTaskDate = currentTaskDate.plusDays(taskRepeatInfo.getOffset());
}

View File

@ -114,6 +114,7 @@ public class TaskService {
public void clearTasks(Taskgroup taskgroup) {
taskSeriesService.deleteTaskSerieByTaskgroup(taskgroup);
taskScheduleService.deleteSchedulesByTaskgroup(taskgroup);
taskRepository.deleteTaskHierarchyWhereTaskgroup(taskgroup);
taskRepository.deleteAllByTaskgroup(taskgroup);
}

View File

@ -0,0 +1,15 @@
package util;
public class Tripel<A,B,C> extends Tupel<A, B> {
private final C value02;
public Tripel(A value00, B value01, C value02) {
super(value00, value01);
this.value02 = value02;
}
public C getValue02() {
return value02;
}
}

View File

@ -0,0 +1,20 @@
package util;
public class Tupel <A, B>{
private final A value00;
private final B value01;
public Tupel(A value00, B value01) {
this.value00 = value00;
this.value01 = value01;
}
public A getValue00() {
return value00;
}
public B getValue01() {
return value01;
}
}