issue-106 #107
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -114,6 +114,7 @@ public class TaskService {
|
||||
public void clearTasks(Taskgroup taskgroup) {
|
||||
taskSeriesService.deleteTaskSerieByTaskgroup(taskgroup);
|
||||
taskScheduleService.deleteSchedulesByTaskgroup(taskgroup);
|
||||
taskRepository.deleteTaskHierarchyWhereTaskgroup(taskgroup);
|
||||
taskRepository.deleteAllByTaskgroup(taskgroup);
|
||||
}
|
||||
|
||||
|
15
backend/src/main/java/util/Tripel.java
Normal file
15
backend/src/main/java/util/Tripel.java
Normal 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;
|
||||
}
|
||||
}
|
20
backend/src/main/java/util/Tupel.java
Normal file
20
backend/src/main/java/util/Tupel.java
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user