issue-106 #107
@ -8,6 +8,7 @@ import java.time.DayOfWeek;
|
|||||||
public class TaskRepeatWeekDayInfo {
|
public class TaskRepeatWeekDayInfo {
|
||||||
private int offset;
|
private int offset;
|
||||||
private long taskID;
|
private long taskID;
|
||||||
|
private DayOfWeek dayOfWeek;
|
||||||
|
|
||||||
public int getOffset() {
|
public int getOffset() {
|
||||||
return offset;
|
return offset;
|
||||||
@ -24,4 +25,12 @@ public class TaskRepeatWeekDayInfo {
|
|||||||
public void setTaskID(long taskID) {
|
public void setTaskID(long taskID) {
|
||||||
this.taskID = 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;
|
package core.entities.timemanager;
|
||||||
|
|
||||||
import core.api.models.timemanager.tasks.TaskFieldInfo;
|
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 javax.persistence.*;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "tasks")
|
@Table(name = "tasks")
|
||||||
@ -54,14 +55,59 @@ public class Task {
|
|||||||
this.finishable = taskFieldInfo.isFinishable();
|
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();
|
Task clonedTask = new Task();
|
||||||
clonedTask.setTaskgroup(task.getTaskgroup());
|
clonedTasks.add(clonedTask);
|
||||||
clonedTask.setTaskName(task.taskName);
|
|
||||||
clonedTask.setEta(task.eta);
|
clonedTask.setTaskgroup(this.getTaskgroup());
|
||||||
clonedTask.setFinished(false);
|
clonedTask.setTaskName(this.taskName);
|
||||||
clonedTask.setFinishable(task.finishable);
|
clonedTask.setEta(this.eta);
|
||||||
return clonedTask;
|
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) {
|
public void increaseWorkTime(long minutes) {
|
||||||
this.workTime += (int) 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);
|
this.tasks.add(taskSerieItem);
|
||||||
return 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() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TaskSerieItem(Task task, int itemIndex) {
|
||||||
|
this.taskSerie = null;
|
||||||
|
this.seriesIndex = itemIndex;
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
public long getItemID() {
|
public long getItemID() {
|
||||||
return itemID;
|
return itemID;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ public interface TaskRepository extends CrudRepository<Task, Long> {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Modifying
|
@Modifying
|
||||||
|
@Query(value = "DELETE FROM Task t WHERE t.taskID = ?1")
|
||||||
void deleteByTaskID(long taskID);
|
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")
|
@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")
|
@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);
|
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 core.repositories.timemanager.TaskSeriesRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import util.Tupel;
|
||||||
|
|
||||||
|
import java.time.DayOfWeek;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class TaskSeriesService {
|
public class TaskSeriesService {
|
||||||
@ -30,59 +29,79 @@ public class TaskSeriesService {
|
|||||||
|
|
||||||
|
|
||||||
public ServiceExitCode createTaskSeries(TaskRepeatWeekInfo taskRepeatInfo) {
|
public ServiceExitCode createTaskSeries(TaskRepeatWeekInfo taskRepeatInfo) {
|
||||||
List<Task> createdTasks = new ArrayList<>();
|
Map<TaskRepeatWeekDayInfo, Tupel<Integer, Integer>> offsetMap = calcOffsetMap(taskRepeatInfo);
|
||||||
|
|
||||||
TaskSerie taskSerie = new TaskSerie();
|
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()) {
|
LocalDate currentDate = rootTask.getStartDate().plusDays(weekDayInfo.getOffset());
|
||||||
Optional<Task> task = taskRepository.findById(taskRepeatDayInfo.getTaskID());
|
|
||||||
if(task.isEmpty()) return ServiceExitCode.MISSING_ENTITY;
|
|
||||||
|
|
||||||
TaskSerieItem rootItem = taskSerie.addTask(task.get());
|
int itemIndex = weekDayIndex;
|
||||||
task.get().setTaskSerieItem(rootItem);
|
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());
|
for(Task clonedTask : cloneResult.getValue01()) {
|
||||||
while(currentTaskDate.isBefore(taskRepeatInfo.getEndDate())) {
|
TaskSerieItem item = new TaskSerieItem(clonedTask, itemIndex);
|
||||||
Task clonedTask = Task.cloneTask(task.get());
|
taskSerie.addItem(item);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
taskSeriesRepository.save(taskSerie);
|
||||||
taskRepository.saveAll(createdTasks);
|
taskRepository.saveAll(clonedTasks);
|
||||||
taskSerieItemRepository.saveAll(taskSerie.getTasks());
|
taskSerieItemRepository.saveAll(taskSerie.getTasks());
|
||||||
scheduleRepository.saveAll(abstractSchedules);
|
scheduleRepository.saveAll(clonedSchedules);
|
||||||
|
|
||||||
return ServiceExitCode.OK;
|
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) {
|
public ServiceExitCode createTaskSeries(Task rootTask, TaskRepeatDayInfo taskRepeatInfo) {
|
||||||
if(taskRepeatInfo.getDeadlineStrategy() == DeadlineStrategy.FIX_DEADLINE) {
|
if(taskRepeatInfo.getDeadlineStrategy() == DeadlineStrategy.FIX_DEADLINE) {
|
||||||
return ServiceExitCode.INVALID_PARAMETER;
|
return ServiceExitCode.INVALID_PARAMETER;
|
||||||
@ -96,18 +115,8 @@ public class TaskSeriesService {
|
|||||||
|
|
||||||
LocalDate currentTaskDate = rootTask.getStartDate().plusDays(taskRepeatInfo.getOffset());
|
LocalDate currentTaskDate = rootTask.getStartDate().plusDays(taskRepeatInfo.getOffset());
|
||||||
while(currentTaskDate.isBefore(taskRepeatInfo.getEndingDate())) {
|
while(currentTaskDate.isBefore(taskRepeatInfo.getEndingDate())) {
|
||||||
Task task = Task.cloneTask(rootTask);
|
Tupel<Task, Collection<Task>> clonedTasks = rootTask.cloneTask();
|
||||||
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);
|
|
||||||
|
|
||||||
abstractSchedules.addAll(cloneSchedules(rootTask, task));
|
|
||||||
currentTaskDate = currentTaskDate.plusDays(taskRepeatInfo.getOffset());
|
currentTaskDate = currentTaskDate.plusDays(taskRepeatInfo.getOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +114,7 @@ public class TaskService {
|
|||||||
public void clearTasks(Taskgroup taskgroup) {
|
public void clearTasks(Taskgroup taskgroup) {
|
||||||
taskSeriesService.deleteTaskSerieByTaskgroup(taskgroup);
|
taskSeriesService.deleteTaskSerieByTaskgroup(taskgroup);
|
||||||
taskScheduleService.deleteSchedulesByTaskgroup(taskgroup);
|
taskScheduleService.deleteSchedulesByTaskgroup(taskgroup);
|
||||||
|
taskRepository.deleteTaskHierarchyWhereTaskgroup(taskgroup);
|
||||||
taskRepository.deleteAllByTaskgroup(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