TSK-442 improve task refresh on classification update
This commit is contained in:
parent
9251975f47
commit
87fd1af390
|
|
@ -135,6 +135,8 @@ public class TaskanaEngineConfiguration {
|
||||||
this.rolesSeparator = rolesSeparator;
|
this.rolesSeparator = rolesSeparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setGermanPublicHolidaysEnabled(true);
|
||||||
|
|
||||||
if (dataSource != null) {
|
if (dataSource != null) {
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import org.apache.ibatis.session.SqlSessionManager;
|
||||||
import org.apache.ibatis.transaction.TransactionFactory;
|
import org.apache.ibatis.transaction.TransactionFactory;
|
||||||
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
||||||
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
|
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
@ -250,6 +251,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
// register type handlers
|
// register type handlers
|
||||||
configuration.getTypeHandlerRegistry().register(new MapTypeHandler());
|
configuration.getTypeHandlerRegistry().register(new MapTypeHandler());
|
||||||
configuration.getTypeHandlerRegistry().register(Instant.class, new InstantTypeHandler());
|
configuration.getTypeHandlerRegistry().register(Instant.class, new InstantTypeHandler());
|
||||||
|
configuration.getTypeHandlerRegistry().register(JdbcType.TIMESTAMP,new InstantTypeHandler());
|
||||||
// add mappers
|
// add mappers
|
||||||
configuration.addMapper(TaskMapper.class);
|
configuration.addMapper(TaskMapper.class);
|
||||||
configuration.addMapper(MonitorMapper.class);
|
configuration.addMapper(MonitorMapper.class);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package pro.taskana.common.internal.jobs;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
@ -43,16 +42,18 @@ public class ClassificationChangedJob extends AbstractTaskanaJob {
|
||||||
LOGGER.info("Running ClassificationChangedJob for classification ({})", classificationId);
|
LOGGER.info("Running ClassificationChangedJob for classification ({})", classificationId);
|
||||||
try {
|
try {
|
||||||
TaskServiceImpl taskService = (TaskServiceImpl) taskanaEngineImpl.getTaskService();
|
TaskServiceImpl taskService = (TaskServiceImpl) taskanaEngineImpl.getTaskService();
|
||||||
Set<String> affectedTaskIds =
|
List<String> affectedTaskIds =
|
||||||
taskService.findTasksIdsAffectedByClassificationChange(classificationId);
|
taskService.findTasksIdsAffectedByClassificationChange(classificationId);
|
||||||
scheduleTaskRefreshJobs(affectedTaskIds);
|
if (!affectedTaskIds.isEmpty()) {
|
||||||
|
scheduleTaskRefreshJobs(affectedTaskIds);
|
||||||
|
}
|
||||||
LOGGER.info("ClassificationChangedJob ended successfully.");
|
LOGGER.info("ClassificationChangedJob ended successfully.");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TaskanaException("Error while processing ClassificationChangedJob.", e);
|
throw new TaskanaException("Error while processing ClassificationChangedJob.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleTaskRefreshJobs(Set<String> affectedTaskIds) {
|
private void scheduleTaskRefreshJobs(List<String> affectedTaskIds) {
|
||||||
int batchSize = taskanaEngineImpl.getConfiguration().getMaxNumberOfUpdatesPerTransaction();
|
int batchSize = taskanaEngineImpl.getConfiguration().getMaxNumberOfUpdatesPerTransaction();
|
||||||
List<List<String>> affectedTaskBatches = partition(affectedTaskIds, batchSize);
|
List<List<String>> affectedTaskBatches = partition(affectedTaskIds, batchSize);
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,22 @@ package pro.taskana.common.internal.jobs;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.security.PrivilegedActionException;
|
||||||
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javax.security.auth.Subject;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import pro.taskana.common.api.ScheduledJob;
|
import pro.taskana.common.api.ScheduledJob;
|
||||||
import pro.taskana.common.api.TaskanaEngine;
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
|
import pro.taskana.common.api.TaskanaRole;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
import pro.taskana.common.internal.JobServiceImpl;
|
||||||
import pro.taskana.common.internal.TaskanaEngineImpl;
|
import pro.taskana.common.internal.TaskanaEngineImpl;
|
||||||
|
import pro.taskana.common.internal.security.UserPrincipal;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
import pro.taskana.task.internal.TaskServiceImpl;
|
import pro.taskana.task.internal.TaskServiceImpl;
|
||||||
|
|
||||||
|
|
@ -101,6 +107,35 @@ public class JobRunner {
|
||||||
|
|
||||||
private void runScheduledJob(ScheduledJob scheduledJob) {
|
private void runScheduledJob(ScheduledJob scheduledJob) {
|
||||||
LOGGER.debug("entry to runScheduledJob(job = {})", scheduledJob);
|
LOGGER.debug("entry to runScheduledJob(job = {})", scheduledJob);
|
||||||
|
|
||||||
|
if (taskanaEngine.isUserInRole(TaskanaRole.ADMIN)) {
|
||||||
|
// we run already as admin
|
||||||
|
runScheduledJobImpl(scheduledJob);
|
||||||
|
} else {
|
||||||
|
// we must establish admin context
|
||||||
|
try {
|
||||||
|
Subject.doAs(
|
||||||
|
getAdminSubject(),
|
||||||
|
new PrivilegedExceptionAction<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object run() throws Exception {
|
||||||
|
try {
|
||||||
|
runScheduledJobImpl(scheduledJob);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format("could not run Job %s.", scheduledJob), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (PrivilegedActionException e) {
|
||||||
|
LOGGER.warn("Attempt to run job {} failed.", scheduledJob, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOGGER.debug("exit from runScheduledJob");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runScheduledJobImpl(ScheduledJob scheduledJob) {
|
||||||
try {
|
try {
|
||||||
TaskanaJob job =
|
TaskanaJob job =
|
||||||
AbstractTaskanaJob.createFromScheduledJob(taskanaEngine, txProvider, scheduledJob);
|
AbstractTaskanaJob.createFromScheduledJob(taskanaEngine, txProvider, scheduledJob);
|
||||||
|
|
@ -114,6 +149,24 @@ public class JobRunner {
|
||||||
+ e.getMessage(),
|
+ e.getMessage(),
|
||||||
e);
|
e);
|
||||||
}
|
}
|
||||||
LOGGER.debug("exit from runScheduledJob");
|
}
|
||||||
|
|
||||||
|
private Subject getAdminSubject() {
|
||||||
|
Subject subject = new Subject();
|
||||||
|
List<Principal> principalList = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
principalList.add(
|
||||||
|
new UserPrincipal(
|
||||||
|
taskanaEngine
|
||||||
|
.getConfiguration()
|
||||||
|
.getRoleMap()
|
||||||
|
.get(TaskanaRole.ADMIN)
|
||||||
|
.iterator()
|
||||||
|
.next()));
|
||||||
|
} catch (Exception t) {
|
||||||
|
LOGGER.warn("Could not determine a configured admin user.", t);
|
||||||
|
}
|
||||||
|
subject.getPrincipals().addAll(principalList);
|
||||||
|
return subject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,18 @@ public class TaskRefreshJob extends AbstractTaskanaJob {
|
||||||
public static final String ARG_TASK_IDS = "taskIds";
|
public static final String ARG_TASK_IDS = "taskIds";
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(TaskRefreshJob.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(TaskRefreshJob.class);
|
||||||
private List<String> affectedTaskIds;
|
private List<String> affectedTaskIds;
|
||||||
|
private boolean priorityChanged;
|
||||||
|
private boolean serviceLevelChanged;
|
||||||
|
|
||||||
public TaskRefreshJob(
|
public TaskRefreshJob(
|
||||||
TaskanaEngine engine, TaskanaTransactionProvider<Object> txProvider, ScheduledJob job) {
|
TaskanaEngine engine, TaskanaTransactionProvider<Object> txProvider, ScheduledJob job) {
|
||||||
super(engine, txProvider, job);
|
super(engine, txProvider, job);
|
||||||
Map<String, String> args = job.getArguments();
|
Map<String, String> args = job.getArguments();
|
||||||
String taskIdsString = args.get(ARG_TASK_IDS);
|
String taskIdsString = args.get(ClassificationChangedJob.TASK_IDS);
|
||||||
affectedTaskIds = Arrays.asList(taskIdsString.split(","));
|
affectedTaskIds = Arrays.asList(taskIdsString.split(","));
|
||||||
|
priorityChanged = Boolean.parseBoolean(args.get(ClassificationChangedJob.PRIORITY_CHANGED));
|
||||||
|
serviceLevelChanged =
|
||||||
|
Boolean.parseBoolean(args.get(ClassificationChangedJob.SERVICE_LEVEL_CHANGED));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -37,14 +42,8 @@ public class TaskRefreshJob extends AbstractTaskanaJob {
|
||||||
LOGGER.info("Running TaskRefreshJob for {} tasks", affectedTaskIds.size());
|
LOGGER.info("Running TaskRefreshJob for {} tasks", affectedTaskIds.size());
|
||||||
try {
|
try {
|
||||||
TaskServiceImpl taskService = (TaskServiceImpl) taskanaEngineImpl.getTaskService();
|
TaskServiceImpl taskService = (TaskServiceImpl) taskanaEngineImpl.getTaskService();
|
||||||
for (String taskId : affectedTaskIds) {
|
taskService.refreshPriorityAndDueDatesOfTasksOnClassificationUpdate(
|
||||||
try {
|
affectedTaskIds, serviceLevelChanged, priorityChanged);
|
||||||
taskService.refreshPriorityAndDueDateOnClassificationUpdate(taskId);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.warn(
|
|
||||||
"Task {} could not be refreshed because of exception: {}", taskId, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOGGER.info("TaskRefreshJob ended successfully.");
|
LOGGER.info("TaskRefreshJob ended successfully.");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TaskanaException("Error while processing TaskRefreshJob.", e);
|
throw new TaskanaException("Error while processing TaskRefreshJob.", e);
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,61 @@
|
||||||
package pro.taskana.common.internal.util;
|
package pro.taskana.common.internal.util;
|
||||||
|
|
||||||
public class Pair<L, R> {
|
import java.util.Objects;
|
||||||
|
|
||||||
private final L left;
|
public final class Pair<L, R> {
|
||||||
|
|
||||||
private final R right;
|
private L left;
|
||||||
|
|
||||||
|
private R right;
|
||||||
|
|
||||||
public Pair(L left, R right) {
|
public Pair(L left, R right) {
|
||||||
this.left = left;
|
this.left = left;
|
||||||
this.right = right;
|
this.right = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Pair() {}
|
||||||
|
|
||||||
public L getLeft() {
|
public L getLeft() {
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLeft(L left) {
|
||||||
|
this.left = left;
|
||||||
|
}
|
||||||
|
|
||||||
public R getRight() {
|
public R getRight() {
|
||||||
return right;
|
return right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRight(R right) {
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
public static <L, R> Pair<L, R> of(L left, R right) {
|
public static <L, R> Pair<L, R> of(L left, R right) {
|
||||||
return new Pair<>(left, right);
|
return new Pair<>(left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Pair<?, ?> other = (Pair<?, ?>) obj;
|
||||||
|
return Objects.equals(left, other.left)
|
||||||
|
&& Objects.equals(right, other.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Pair [left=" + left + ", right=" + right + "]";
|
return "Pair [left=" + left + ", right=" + right + "]";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package pro.taskana.task.internal;
|
package pro.taskana.task.internal;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.apache.ibatis.annotations.Delete;
|
import org.apache.ibatis.annotations.Delete;
|
||||||
|
|
@ -12,6 +13,7 @@ import org.apache.ibatis.annotations.Update;
|
||||||
import org.apache.ibatis.type.ClobTypeHandler;
|
import org.apache.ibatis.type.ClobTypeHandler;
|
||||||
|
|
||||||
import pro.taskana.common.internal.persistence.MapTypeHandler;
|
import pro.taskana.common.internal.persistence.MapTypeHandler;
|
||||||
|
import pro.taskana.common.internal.util.Pair;
|
||||||
import pro.taskana.task.internal.models.AttachmentImpl;
|
import pro.taskana.task.internal.models.AttachmentImpl;
|
||||||
import pro.taskana.task.internal.models.AttachmentSummaryImpl;
|
import pro.taskana.task.internal.models.AttachmentSummaryImpl;
|
||||||
|
|
||||||
|
|
@ -85,7 +87,8 @@ public interface AttachmentMapper {
|
||||||
@Result(property = "channel", column = "CHANNEL"),
|
@Result(property = "channel", column = "CHANNEL"),
|
||||||
@Result(property = "received", column = "RECEIVED")
|
@Result(property = "received", column = "RECEIVED")
|
||||||
})
|
})
|
||||||
List<AttachmentSummaryImpl> findAttachmentSummariesByTaskIds(@Param("taskIds") List<String> taskIds);
|
List<AttachmentSummaryImpl> findAttachmentSummariesByTaskIds(
|
||||||
|
@Param("taskIds") List<String> taskIds);
|
||||||
|
|
||||||
@Delete("DELETE FROM ATTACHMENT WHERE ID=#{attachmentId}")
|
@Delete("DELETE FROM ATTACHMENT WHERE ID=#{attachmentId}")
|
||||||
void deleteAttachment(@Param("attachmentId") String attachmentId);
|
void deleteAttachment(@Param("attachmentId") String attachmentId);
|
||||||
|
|
@ -113,10 +116,18 @@ public interface AttachmentMapper {
|
||||||
String getCustomAttributesAsString(@Param("attachmentId") String attachmentId);
|
String getCustomAttributesAsString(@Param("attachmentId") String attachmentId);
|
||||||
|
|
||||||
@Select(
|
@Select(
|
||||||
"<script> SELECT DISTINCT TASK_ID FROM ATTACHMENT WHERE CLASSIFICATION_ID = #{classificationId} "
|
"<script> SELECT DISTINCT t.ID, t.PLANNED FROM TASK t "
|
||||||
|
+ "LEFT JOIN ATTACHMENT AS a on a.TASK_ID = t.ID"
|
||||||
|
+ " WHERE a.CLASSIFICATION_ID = #{classificationId} "
|
||||||
+ "<if test=\"_databaseId == 'db2'\">with UR </if> "
|
+ "<if test=\"_databaseId == 'db2'\">with UR </if> "
|
||||||
+ "</script>")
|
+ "</script>")
|
||||||
@Results(value = {@Result(property = "taskId", column = "TASK_ID")})
|
@Results(
|
||||||
List<String> findTaskIdsAffectedByClassificationChange(
|
value = {
|
||||||
|
@Result(property = "left", column = "ID"),
|
||||||
|
@Result(property = "right", column = "PLANNED")
|
||||||
|
// , javaType = Instant.class,
|
||||||
|
// typeHandler = InstantTypeHandler.class)
|
||||||
|
})
|
||||||
|
List<Pair<String, Instant>> findTaskIdsAndPlannedAffectedByClassificationChange(
|
||||||
@Param("classificationId") String classificationId);
|
@Param("classificationId") String classificationId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
@ -50,7 +51,7 @@ class ServiceLevelHandler {
|
||||||
DaysToWorkingDaysConverter.setGermanPublicHolidaysEnabled(
|
DaysToWorkingDaysConverter.setGermanPublicHolidaysEnabled(
|
||||||
taskanaEngine.getEngine().getConfiguration().isGermanPublicHolidaysEnabled());
|
taskanaEngine.getEngine().getConfiguration().isGermanPublicHolidaysEnabled());
|
||||||
try {
|
try {
|
||||||
this.converter = DaysToWorkingDaysConverter.initialize();
|
converter = DaysToWorkingDaysConverter.initialize();
|
||||||
} catch (InvalidArgumentException e) {
|
} catch (InvalidArgumentException e) {
|
||||||
LOGGER.error(ERROR_CANNOT_INITIALIZE_DAYS_TO_WORKING_DAYS_CONVERTER);
|
LOGGER.error(ERROR_CANNOT_INITIALIZE_DAYS_TO_WORKING_DAYS_CONVERTER);
|
||||||
throw new SystemException(
|
throw new SystemException(
|
||||||
|
|
@ -245,6 +246,9 @@ class ServiceLevelHandler {
|
||||||
private TaskImpl updatePlannedDueOnTaskUpdate(
|
private TaskImpl updatePlannedDueOnTaskUpdate(
|
||||||
TaskImpl newTaskImpl, TaskImpl oldTaskImpl, DurationPrioHolder durationPrioHolder)
|
TaskImpl newTaskImpl, TaskImpl oldTaskImpl, DurationPrioHolder durationPrioHolder)
|
||||||
throws InvalidArgumentException {
|
throws InvalidArgumentException {
|
||||||
|
if (newTaskImpl.getPlanned() == null && newTaskImpl.getDue() == null) {
|
||||||
|
newTaskImpl.setPlanned(oldTaskImpl.getPlanned());
|
||||||
|
}
|
||||||
// case 1: no change of planned / due, but potentially change of an attachment or classification
|
// case 1: no change of planned / due, but potentially change of an attachment or classification
|
||||||
if (oldTaskImpl.getDue().equals(newTaskImpl.getDue())
|
if (oldTaskImpl.getDue().equals(newTaskImpl.getDue())
|
||||||
&& oldTaskImpl.getPlanned().equals(newTaskImpl.getPlanned())) {
|
&& oldTaskImpl.getPlanned().equals(newTaskImpl.getPlanned())) {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ import org.apache.ibatis.annotations.Select;
|
||||||
import org.apache.ibatis.annotations.Update;
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
import pro.taskana.common.internal.CustomPropertySelector;
|
import pro.taskana.common.internal.CustomPropertySelector;
|
||||||
|
import pro.taskana.common.internal.persistence.InstantTypeHandler;
|
||||||
import pro.taskana.common.internal.persistence.MapTypeHandler;
|
import pro.taskana.common.internal.persistence.MapTypeHandler;
|
||||||
|
import pro.taskana.common.internal.util.Pair;
|
||||||
import pro.taskana.task.api.CallbackState;
|
import pro.taskana.task.api.CallbackState;
|
||||||
import pro.taskana.task.internal.models.MinimalTaskSummary;
|
import pro.taskana.task.internal.models.MinimalTaskSummary;
|
||||||
import pro.taskana.task.internal.models.TaskImpl;
|
import pro.taskana.task.internal.models.TaskImpl;
|
||||||
|
|
@ -232,14 +234,34 @@ public interface TaskMapper {
|
||||||
long updateTaskDueDates(
|
long updateTaskDueDates(
|
||||||
@Param("taskIds") List<String> taskIds, @Param("referenceTask") TaskImpl referenceTask);
|
@Param("taskIds") List<String> taskIds, @Param("referenceTask") TaskImpl referenceTask);
|
||||||
|
|
||||||
|
@Update(
|
||||||
|
"<script>"
|
||||||
|
+ "<if test='taskIds != null'> "
|
||||||
|
+ "UPDATE TASK SET MODIFIED = #{referenceTask.modified}, "
|
||||||
|
+ "PRIORITY = #{referenceTask.priority} "
|
||||||
|
+ "WHERE ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>) "
|
||||||
|
+ "</if> "
|
||||||
|
+ "</script>")
|
||||||
|
long updatePriorityOfTasks(
|
||||||
|
@Param("taskIds") List<String> taskIds, @Param("referenceTask") TaskImpl referenceTask);
|
||||||
|
|
||||||
@Select(
|
@Select(
|
||||||
"<script>SELECT ID, STATE FROM TASK "
|
"<script>SELECT ID, PLANNED, STATE FROM TASK "
|
||||||
+ "WHERE ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>) "
|
+ "WHERE ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>) "
|
||||||
+ "AND STATE IN ( 'READY','CLAIMED') "
|
+ "AND STATE IN ( 'READY','CLAIMED') "
|
||||||
+ "<if test=\"_databaseId == 'db2'\">with UR </if> "
|
+ "<if test=\"_databaseId == 'db2'\">with UR </if> "
|
||||||
+ "</script>")
|
+ "</script>")
|
||||||
@Results(value = {@Result(property = "taskId", column = "ID")})
|
@Results(
|
||||||
List<String> filterTaskIdsForNotCompleted(@Param("taskIds") List<String> taskIds);
|
value = {
|
||||||
|
@Result(property = "left", column = "ID"),
|
||||||
|
@Result(
|
||||||
|
property = "right",
|
||||||
|
column = "PLANNED",
|
||||||
|
javaType = Instant.class,
|
||||||
|
typeHandler = InstantTypeHandler.class)
|
||||||
|
})
|
||||||
|
List<Pair<String, Instant>> filterTaskIdsForReadyAndClaimed(
|
||||||
|
@Param("taskIds") List<String> taskIds);
|
||||||
|
|
||||||
@Select(
|
@Select(
|
||||||
"<script> "
|
"<script> "
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package pro.taskana.task.internal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -748,75 +749,78 @@ public class TaskServiceImpl implements TaskService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> findTasksIdsAffectedByClassificationChange(String classificationId) {
|
public List<String> findTasksIdsAffectedByClassificationChange(String classificationId) {
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"entry to findTasksIdsAffectedByClassificationChange(classificationId = {})",
|
"entry to findTasksIdsAffectedByClassificationChange(classificationId = {})",
|
||||||
classificationId);
|
classificationId);
|
||||||
// tasks directly affected
|
// tasks directly affected
|
||||||
List<TaskSummary> tasks =
|
List<TaskSummary> tasksAffectedDirectly =
|
||||||
createTaskQuery()
|
createTaskQuery()
|
||||||
.classificationIdIn(classificationId)
|
.classificationIdIn(classificationId)
|
||||||
.stateIn(TaskState.READY, TaskState.CLAIMED)
|
.stateIn(TaskState.READY, TaskState.CLAIMED)
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
// tasks indirectly affected via attachments
|
// tasks indirectly affected via attachments
|
||||||
List<String> taskIdsFromAttachments =
|
List<Pair<String, Instant>> affectedPairs =
|
||||||
attachmentMapper.findTaskIdsAffectedByClassificationChange(classificationId);
|
tasksAffectedDirectly.stream()
|
||||||
|
.map(t -> new Pair<String, Instant>(t.getId(), t.getPlanned()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// tasks indirectly affected via attachments
|
||||||
|
List<Pair<String, Instant>> taskIdsAndPlannedFromAttachments =
|
||||||
|
attachmentMapper.findTaskIdsAndPlannedAffectedByClassificationChange(classificationId);
|
||||||
|
|
||||||
List<String> filteredTaskIdsFromAttachments =
|
List<String> taskIdsFromAttachments =
|
||||||
|
taskIdsAndPlannedFromAttachments.stream().map(Pair::getLeft).collect(Collectors.toList());
|
||||||
|
List<Pair<String, Instant>> filteredTaskIdsAndPlannedFromAttachments =
|
||||||
taskIdsFromAttachments.isEmpty()
|
taskIdsFromAttachments.isEmpty()
|
||||||
? new ArrayList<>()
|
? new ArrayList<>()
|
||||||
: taskMapper.filterTaskIdsForNotCompleted(taskIdsFromAttachments);
|
: taskMapper.filterTaskIdsForReadyAndClaimed(taskIdsFromAttachments);
|
||||||
|
affectedPairs.addAll(filteredTaskIdsAndPlannedFromAttachments);
|
||||||
|
// sort all affected tasks according to the planned instant
|
||||||
|
List<String> affectedTaskIds =
|
||||||
|
affectedPairs.stream()
|
||||||
|
.sorted(Comparator.comparing(Pair::getRight))
|
||||||
|
.distinct()
|
||||||
|
.map(Pair::getLeft)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
Set<String> affectedTaskIds = new HashSet<>(filteredTaskIdsFromAttachments);
|
|
||||||
for (TaskSummary task : tasks) {
|
|
||||||
affectedTaskIds.add(task.getId());
|
|
||||||
}
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"the following tasks are affected by the update of classification {} : {}",
|
"the following tasks are affected by the update of classification {} : {}",
|
||||||
classificationId,
|
classificationId,
|
||||||
LoggerUtils.setToString(affectedTaskIds));
|
LoggerUtils.listToString(affectedTaskIds));
|
||||||
}
|
}
|
||||||
LOGGER.debug("exit from findTasksIdsAffectedByClassificationChange(). ");
|
LOGGER.debug("exit from findTasksIdsAffectedByClassificationChange(). ");
|
||||||
return affectedTaskIds;
|
return affectedTaskIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshPriorityAndDueDateOnClassificationUpdate(String taskId)
|
public void refreshPriorityAndDueDatesOfTasksOnClassificationUpdate(
|
||||||
throws ClassificationNotFoundException {
|
List<String> taskIds, boolean serviceLevelChanged, boolean priorityChanged) {
|
||||||
LOGGER.debug("entry to refreshPriorityAndDueDate(taskId = {})", taskId);
|
if (LOGGER.isDebugEnabled()) {
|
||||||
TaskImpl task;
|
LOGGER.debug(
|
||||||
BulkOperationResults<String, Exception> bulkLog = new BulkOperationResults<>();
|
"entry to refreshPriorityAndDueDateOfTasks(tasks = {})",
|
||||||
|
LoggerUtils.listToString(taskIds));
|
||||||
|
}
|
||||||
|
Pair<List<MinimalTaskSummary>, BulkLog> resultsPair = getMinimalTaskSummaries(taskIds);
|
||||||
|
List<MinimalTaskSummary> tasks = resultsPair.getLeft();
|
||||||
try {
|
try {
|
||||||
taskanaEngine.openConnection();
|
taskanaEngine.openConnection();
|
||||||
if (taskId == null || taskId.isEmpty()) {
|
Set<String> adminAccessIds =
|
||||||
return;
|
taskanaEngine.getEngine().getConfiguration().getRoleMap().get(TaskanaRole.ADMIN);
|
||||||
|
if (adminAccessIds.contains(CurrentUserContext.getUserid())) {
|
||||||
|
serviceLevelHandler.refreshPriorityAndDueDatesOfTasks(
|
||||||
|
tasks, serviceLevelChanged, priorityChanged);
|
||||||
|
} else {
|
||||||
|
taskanaEngine.runAsAdmin(
|
||||||
|
() -> {
|
||||||
|
serviceLevelHandler.refreshPriorityAndDueDatesOfTasks(
|
||||||
|
tasks, serviceLevelChanged, priorityChanged);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
task = taskMapper.findById(taskId);
|
|
||||||
|
|
||||||
List<AttachmentImpl> attachmentImpls = attachmentMapper.findAttachmentsByTaskId(task.getId());
|
|
||||||
if (attachmentImpls == null) {
|
|
||||||
attachmentImpls = new ArrayList<>();
|
|
||||||
}
|
|
||||||
List<Attachment> attachments =
|
|
||||||
attachmentHandler.augmentAttachmentsByClassification(attachmentImpls, bulkLog);
|
|
||||||
task.setAttachments(attachments);
|
|
||||||
|
|
||||||
ClassificationSummary classificationSummary =
|
|
||||||
classificationService
|
|
||||||
.getClassification(task.getClassificationKey(), task.getDomain())
|
|
||||||
.asSummary();
|
|
||||||
task.setClassificationSummary(classificationSummary);
|
|
||||||
task = serviceLevelHandler.updatePrioPlannedDueOfTask(task, null, true);
|
|
||||||
|
|
||||||
task.setModified(Instant.now());
|
|
||||||
taskMapper.update(task);
|
|
||||||
} catch (InvalidArgumentException e) {
|
|
||||||
LOGGER.error("Internal System error. This situation should not happen. Caught exceptio ", e);
|
|
||||||
} finally {
|
} finally {
|
||||||
|
LOGGER.debug("exit from refreshPriorityAndDueDateOfTasks");
|
||||||
taskanaEngine.returnConnection();
|
taskanaEngine.returnConnection();
|
||||||
LOGGER.debug("exit from refreshPriorityAndDueDate(). ");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1217,44 +1221,45 @@ public class TaskServiceImpl implements TaskService {
|
||||||
|
|
||||||
private void standardSettings(TaskImpl task, Classification classification)
|
private void standardSettings(TaskImpl task, Classification classification)
|
||||||
throws InvalidArgumentException {
|
throws InvalidArgumentException {
|
||||||
|
TaskImpl task1 = task;
|
||||||
LOGGER.debug("entry to standardSettings()");
|
LOGGER.debug("entry to standardSettings()");
|
||||||
final Instant now = Instant.now();
|
final Instant now = Instant.now();
|
||||||
task.setId(IdGenerator.generateWithPrefix(ID_PREFIX_TASK));
|
task1.setId(IdGenerator.generateWithPrefix(ID_PREFIX_TASK));
|
||||||
if (task.getExternalId() == null) {
|
if (task1.getExternalId() == null) {
|
||||||
task.setExternalId(IdGenerator.generateWithPrefix(ID_PREFIX_EXT_TASK_ID));
|
task1.setExternalId(IdGenerator.generateWithPrefix(ID_PREFIX_EXT_TASK_ID));
|
||||||
}
|
}
|
||||||
task.setState(TaskState.READY);
|
task1.setState(TaskState.READY);
|
||||||
task.setCreated(now);
|
task1.setCreated(now);
|
||||||
task.setModified(now);
|
task1.setModified(now);
|
||||||
task.setRead(false);
|
task1.setRead(false);
|
||||||
task.setTransferred(false);
|
task1.setTransferred(false);
|
||||||
|
|
||||||
String creator = CurrentUserContext.getUserid();
|
String creator = CurrentUserContext.getUserid();
|
||||||
if (taskanaEngine.getEngine().getConfiguration().isSecurityEnabled() && creator == null) {
|
if (taskanaEngine.getEngine().getConfiguration().isSecurityEnabled() && creator == null) {
|
||||||
throw new SystemException(
|
throw new SystemException(
|
||||||
"TaskanaSecurity is enabled, but the current UserId is NULL while creating a Task.");
|
"TaskanaSecurity is enabled, but the current UserId is NULL while creating a Task.");
|
||||||
}
|
}
|
||||||
task.setCreator(creator);
|
task1.setCreator(creator);
|
||||||
|
|
||||||
// if no business process id is provided, a unique id is created.
|
// if no business process id is provided, a unique id is created.
|
||||||
if (task.getBusinessProcessId() == null) {
|
if (task1.getBusinessProcessId() == null) {
|
||||||
task.setBusinessProcessId(IdGenerator.generateWithPrefix(ID_PREFIX_BUSINESS_PROCESS));
|
task1.setBusinessProcessId(IdGenerator.generateWithPrefix(ID_PREFIX_BUSINESS_PROCESS));
|
||||||
}
|
}
|
||||||
|
|
||||||
// null in case of manual tasks
|
// null in case of manual tasks
|
||||||
if (task.getPlanned() == null && (classification == null || task.getDue() == null)) {
|
if (task1.getPlanned() == null && (classification == null || task1.getDue() == null)) {
|
||||||
task.setPlanned(now);
|
task1.setPlanned(now);
|
||||||
}
|
}
|
||||||
if (classification != null) {
|
if (classification != null) {
|
||||||
task = serviceLevelHandler.updatePrioPlannedDueOfTask(task, null, false);
|
task1 = serviceLevelHandler.updatePrioPlannedDueOfTask(task1, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task.getName() == null && classification != null) {
|
if (task1.getName() == null && classification != null) {
|
||||||
task.setName(classification.getName());
|
task1.setName(classification.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task.getDescription() == null && classification != null) {
|
if (task1.getDescription() == null && classification != null) {
|
||||||
task.setDescription(classification.getDescription());
|
task1.setDescription(classification.getDescription());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
attachmentHandler.insertNewAttachmentsOnTaskCreation(task);
|
attachmentHandler.insertNewAttachmentsOnTaskCreation(task);
|
||||||
|
|
@ -1276,7 +1281,6 @@ public class TaskServiceImpl implements TaskService {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.warn(
|
LOGGER.warn(
|
||||||
"Attempted to determine callback state from {} and caught exception", value, e);
|
"Attempted to determine callback state from {} and caught exception", value, e);
|
||||||
|
|
||||||
throw new InvalidArgumentException(
|
throw new InvalidArgumentException(
|
||||||
String.format("Attempted to set callback state for task %s.", task.getId()), e);
|
String.format("Attempted to set callback state for task %s.", task.getId()), e);
|
||||||
}
|
}
|
||||||
|
|
@ -1654,20 +1658,20 @@ public class TaskServiceImpl implements TaskService {
|
||||||
|
|
||||||
updateClassificationSummary(newTaskImpl, oldTaskImpl);
|
updateClassificationSummary(newTaskImpl, oldTaskImpl);
|
||||||
|
|
||||||
newTaskImpl = serviceLevelHandler.updatePrioPlannedDueOfTask(newTaskImpl, oldTaskImpl, false);
|
TaskImpl newTaskImpl1 =
|
||||||
|
serviceLevelHandler.updatePrioPlannedDueOfTask(newTaskImpl, oldTaskImpl, false);
|
||||||
|
|
||||||
// if no business process id is provided, use the id of the old task.
|
// if no business process id is provided, use the id of the old task.
|
||||||
if (newTaskImpl.getBusinessProcessId() == null) {
|
if (newTaskImpl1.getBusinessProcessId() == null) {
|
||||||
newTaskImpl.setBusinessProcessId(oldTaskImpl.getBusinessProcessId());
|
newTaskImpl1.setBusinessProcessId(oldTaskImpl.getBusinessProcessId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// owner can only be changed if task is in state ready
|
// owner can only be changed if task is in state ready
|
||||||
boolean isOwnerChanged = !Objects.equals(newTaskImpl.getOwner(), oldTaskImpl.getOwner());
|
boolean isOwnerChanged = !Objects.equals(newTaskImpl1.getOwner(), oldTaskImpl.getOwner());
|
||||||
if (isOwnerChanged && oldTaskImpl.getState() != TaskState.READY) {
|
if (isOwnerChanged && oldTaskImpl.getState() != TaskState.READY) {
|
||||||
throw new InvalidStateException(
|
throw new InvalidStateException(
|
||||||
String.format(TASK_WITH_ID_IS_NOT_READY, oldTaskImpl.getId(), oldTaskImpl.getState()));
|
String.format(TASK_WITH_ID_IS_NOT_READY, oldTaskImpl.getId(), oldTaskImpl.getState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateClassificationSummary(TaskImpl newTaskImpl, TaskImpl oldTaskImpl)
|
private void updateClassificationSummary(TaskImpl newTaskImpl, TaskImpl oldTaskImpl)
|
||||||
|
|
|
||||||
|
|
@ -225,14 +225,7 @@ public class UpdateClassificationAccTest extends AbstractAccTest {
|
||||||
classification.setPriority(1000);
|
classification.setPriority(1000);
|
||||||
classification.setServiceLevel("P15D");
|
classification.setServiceLevel("P15D");
|
||||||
|
|
||||||
classificationService.updateClassification(classification);
|
updateClassificationAndRunAssociatedJobs(classification);
|
||||||
Thread.sleep(10);
|
|
||||||
JobRunner runner = new JobRunner(taskanaEngine);
|
|
||||||
// need to run jobs twice, since the first job creates a second one.
|
|
||||||
runner.runJobs();
|
|
||||||
Thread.sleep(10); // otherwise the next runJobs call intermittently doesn't find the Job created
|
|
||||||
// by the previous step (it searches with DueDate < CurrentTime)
|
|
||||||
runner.runJobs();
|
|
||||||
// Get and check the new value
|
// Get and check the new value
|
||||||
Classification updatedClassification =
|
Classification updatedClassification =
|
||||||
classificationService.getClassification("CLI:100000000000000000000000000000000003");
|
classificationService.getClassification("CLI:100000000000000000000000000000000003");
|
||||||
|
|
@ -241,7 +234,7 @@ public class UpdateClassificationAccTest extends AbstractAccTest {
|
||||||
assertFalse(modifiedBefore.isAfter(updatedClassification.getModified()));
|
assertFalse(modifiedBefore.isAfter(updatedClassification.getModified()));
|
||||||
// TODO - resume old behaviour after attachment query is possible.
|
// TODO - resume old behaviour after attachment query is possible.
|
||||||
TaskService taskService = taskanaEngine.getTaskService();
|
TaskService taskService = taskanaEngine.getTaskService();
|
||||||
|
DaysToWorkingDaysConverter.setGermanPublicHolidaysEnabled(true);
|
||||||
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize(Instant.now());
|
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize(Instant.now());
|
||||||
|
|
||||||
List<String> tasksWithP1D =
|
List<String> tasksWithP1D =
|
||||||
|
|
@ -252,15 +245,18 @@ public class UpdateClassificationAccTest extends AbstractAccTest {
|
||||||
"TKI:000000000000000000000000000000000000",
|
"TKI:000000000000000000000000000000000000",
|
||||||
"TKI:000000000000000000000000000000000011",
|
"TKI:000000000000000000000000000000000011",
|
||||||
"TKI:000000000000000000000000000000000053"));
|
"TKI:000000000000000000000000000000000053"));
|
||||||
validateNewTaskProperties(before, tasksWithP1D, taskService, converter, 1);
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithP1D, taskService, converter, 1, 1000);
|
||||||
|
|
||||||
List<String> tasksWithP8D =
|
List<String> tasksWithP8D =
|
||||||
new ArrayList<>(Arrays.asList("TKI:000000000000000000000000000000000008"));
|
new ArrayList<>(Arrays.asList("TKI:000000000000000000000000000000000008"));
|
||||||
validateNewTaskProperties(before, tasksWithP8D, taskService, converter, 8);
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithP8D, taskService, converter, 8, 1000);
|
||||||
|
|
||||||
List<String> tasksWithP14D =
|
List<String> tasksWithP14D =
|
||||||
new ArrayList<>(Arrays.asList("TKI:000000000000000000000000000000000010"));
|
new ArrayList<>(Arrays.asList("TKI:000000000000000000000000000000000010"));
|
||||||
validateNewTaskProperties(before, tasksWithP14D, taskService, converter, 14);
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithP14D, taskService, converter, 14, 1000);
|
||||||
|
|
||||||
List<String> tasksWithP15D =
|
List<String> tasksWithP15D =
|
||||||
new ArrayList<>(
|
new ArrayList<>(
|
||||||
|
|
@ -299,7 +295,8 @@ public class UpdateClassificationAccTest extends AbstractAccTest {
|
||||||
"TKI:000000000000000000000000000000000101",
|
"TKI:000000000000000000000000000000000101",
|
||||||
"TKI:000000000000000000000000000000000102",
|
"TKI:000000000000000000000000000000000102",
|
||||||
"TKI:000000000000000000000000000000000103"));
|
"TKI:000000000000000000000000000000000103"));
|
||||||
validateNewTaskProperties(before, tasksWithP15D, taskService, converter, 15);
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithP15D, taskService, converter, 15, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(
|
@WithAccessId(
|
||||||
|
|
@ -333,29 +330,263 @@ public class UpdateClassificationAccTest extends AbstractAccTest {
|
||||||
classificationService.updateClassification(created);
|
classificationService.updateClassification(created);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateNewTaskProperties(
|
@WithAccessId(
|
||||||
|
userName = "dummy",
|
||||||
|
groupNames = {"admin"})
|
||||||
|
@Test
|
||||||
|
public void testUpdateClassificationChangePriority()
|
||||||
|
throws ClassificationNotFoundException, NotAuthorizedException, ConcurrencyException,
|
||||||
|
InterruptedException, TaskNotFoundException, InvalidArgumentException {
|
||||||
|
final Instant before = Instant.now();
|
||||||
|
Classification classification =
|
||||||
|
classificationService.getClassification("CLI:100000000000000000000000000000000003");
|
||||||
|
final Instant modifiedBefore = classification.getModified();
|
||||||
|
|
||||||
|
classification.setPriority(99);
|
||||||
|
classification.setServiceLevel("P1D");
|
||||||
|
|
||||||
|
updateClassificationAndRunAssociatedJobs(classification);
|
||||||
|
// Get and check the new value
|
||||||
|
Classification updatedClassification =
|
||||||
|
classificationService.getClassification("CLI:100000000000000000000000000000000003");
|
||||||
|
assertNotNull(updatedClassification);
|
||||||
|
assertFalse(modifiedBefore.isAfter(updatedClassification.getModified()));
|
||||||
|
// TODO - resume old behaviour after attachment query is possible.
|
||||||
|
TaskService taskService = taskanaEngine.getTaskService();
|
||||||
|
DaysToWorkingDaysConverter.setGermanPublicHolidaysEnabled(true);
|
||||||
|
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize(Instant.now());
|
||||||
|
|
||||||
|
List<String> tasksWithPrio99 =
|
||||||
|
new ArrayList<>(
|
||||||
|
Arrays.asList(
|
||||||
|
"TKI:000000000000000000000000000000000003",
|
||||||
|
"TKI:000000000000000000000000000000000004",
|
||||||
|
"TKI:000000000000000000000000000000000005",
|
||||||
|
"TKI:000000000000000000000000000000000006",
|
||||||
|
"TKI:000000000000000000000000000000000007",
|
||||||
|
"TKI:000000000000000000000000000000000009",
|
||||||
|
"TKI:000000000000000000000000000000000012",
|
||||||
|
"TKI:000000000000000000000000000000000013",
|
||||||
|
"TKI:000000000000000000000000000000000014",
|
||||||
|
"TKI:000000000000000000000000000000000015",
|
||||||
|
"TKI:000000000000000000000000000000000016",
|
||||||
|
"TKI:000000000000000000000000000000000017",
|
||||||
|
"TKI:000000000000000000000000000000000018",
|
||||||
|
"TKI:000000000000000000000000000000000019",
|
||||||
|
"TKI:000000000000000000000000000000000020",
|
||||||
|
"TKI:000000000000000000000000000000000021",
|
||||||
|
"TKI:000000000000000000000000000000000022",
|
||||||
|
"TKI:000000000000000000000000000000000023",
|
||||||
|
"TKI:000000000000000000000000000000000024",
|
||||||
|
"TKI:000000000000000000000000000000000025",
|
||||||
|
"TKI:000000000000000000000000000000000026",
|
||||||
|
"TKI:000000000000000000000000000000000027",
|
||||||
|
"TKI:000000000000000000000000000000000028",
|
||||||
|
"TKI:000000000000000000000000000000000029",
|
||||||
|
"TKI:000000000000000000000000000000000030",
|
||||||
|
"TKI:000000000000000000000000000000000031",
|
||||||
|
"TKI:000000000000000000000000000000000032",
|
||||||
|
"TKI:000000000000000000000000000000000033",
|
||||||
|
"TKI:000000000000000000000000000000000034",
|
||||||
|
"TKI:000000000000000000000000000000000035",
|
||||||
|
"TKI:000000000000000000000000000000000100",
|
||||||
|
"TKI:000000000000000000000000000000000101",
|
||||||
|
"TKI:000000000000000000000000000000000102",
|
||||||
|
"TKI:000000000000000000000000000000000103",
|
||||||
|
"TKI:200000000000000000000000000000000007",
|
||||||
|
"TKI:000000000000000000000000000000000000",
|
||||||
|
"TKI:000000000000000000000000000000000052",
|
||||||
|
"TKI:000000000000000000000000000000000053",
|
||||||
|
"TKI:000000000000000000000000000000000054",
|
||||||
|
"TKI:000000000000000000000000000000000008",
|
||||||
|
"TKI:000000000000000000000000000000000009",
|
||||||
|
"TKI:000000000000000000000000000000000010"));
|
||||||
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithPrio99, taskService, converter, 1, 99);
|
||||||
|
|
||||||
|
List<String> tasksWithPrio101 =
|
||||||
|
new ArrayList<>(Arrays.asList("TKI:000000000000000000000000000000000011"));
|
||||||
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithPrio101, taskService, converter, 1, 101);
|
||||||
|
|
||||||
|
updatedClassification.setPriority(7);
|
||||||
|
updateClassificationAndRunAssociatedJobs(updatedClassification);
|
||||||
|
|
||||||
|
List<String> tasksWithPrio7 =
|
||||||
|
new ArrayList<>(
|
||||||
|
Arrays.asList(
|
||||||
|
"TKI:000000000000000000000000000000000003",
|
||||||
|
"TKI:000000000000000000000000000000000004",
|
||||||
|
"TKI:000000000000000000000000000000000005",
|
||||||
|
"TKI:000000000000000000000000000000000006",
|
||||||
|
"TKI:000000000000000000000000000000000007",
|
||||||
|
"TKI:000000000000000000000000000000000009",
|
||||||
|
"TKI:000000000000000000000000000000000010",
|
||||||
|
"TKI:000000000000000000000000000000000012",
|
||||||
|
"TKI:000000000000000000000000000000000013",
|
||||||
|
"TKI:000000000000000000000000000000000014",
|
||||||
|
"TKI:000000000000000000000000000000000015",
|
||||||
|
"TKI:000000000000000000000000000000000016",
|
||||||
|
"TKI:000000000000000000000000000000000017",
|
||||||
|
"TKI:000000000000000000000000000000000018",
|
||||||
|
"TKI:000000000000000000000000000000000019",
|
||||||
|
"TKI:000000000000000000000000000000000020",
|
||||||
|
"TKI:000000000000000000000000000000000021",
|
||||||
|
"TKI:000000000000000000000000000000000022",
|
||||||
|
"TKI:000000000000000000000000000000000023",
|
||||||
|
"TKI:000000000000000000000000000000000024",
|
||||||
|
"TKI:000000000000000000000000000000000025",
|
||||||
|
"TKI:000000000000000000000000000000000026",
|
||||||
|
"TKI:000000000000000000000000000000000027",
|
||||||
|
"TKI:000000000000000000000000000000000028",
|
||||||
|
"TKI:000000000000000000000000000000000029",
|
||||||
|
"TKI:000000000000000000000000000000000030",
|
||||||
|
"TKI:000000000000000000000000000000000031",
|
||||||
|
"TKI:000000000000000000000000000000000032",
|
||||||
|
"TKI:000000000000000000000000000000000033",
|
||||||
|
"TKI:000000000000000000000000000000000034",
|
||||||
|
"TKI:000000000000000000000000000000000035",
|
||||||
|
"TKI:000000000000000000000000000000000100",
|
||||||
|
"TKI:000000000000000000000000000000000101",
|
||||||
|
"TKI:000000000000000000000000000000000102",
|
||||||
|
"TKI:000000000000000000000000000000000103",
|
||||||
|
"TKI:000000000000000000000000000000000000",
|
||||||
|
"TKI:000000000000000000000000000000000052",
|
||||||
|
"TKI:000000000000000000000000000000000053",
|
||||||
|
"TKI:000000000000000000000000000000000054",
|
||||||
|
"TKI:000000000000000000000000000000000055",
|
||||||
|
"TKI:200000000000000000000000000000000007"));
|
||||||
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithPrio7, taskService, converter, 1, 7);
|
||||||
|
|
||||||
|
List<String> tasksWithPrio9 =
|
||||||
|
new ArrayList<>(Arrays.asList("TKI:000000000000000000000000000000000008"));
|
||||||
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithPrio9, taskService, converter, 1, 9);
|
||||||
|
|
||||||
|
tasksWithPrio101 = new ArrayList<>(Arrays.asList("TKI:000000000000000000000000000000000011"));
|
||||||
|
|
||||||
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithPrio101, taskService, converter, 1, 101);
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithAccessId(
|
||||||
|
userName = "dummy",
|
||||||
|
groupNames = {"admin"})
|
||||||
|
@Test
|
||||||
|
public void testUpdateClassificationChangeServiceLevel()
|
||||||
|
throws ClassificationNotFoundException, NotAuthorizedException, ConcurrencyException,
|
||||||
|
InterruptedException, TaskNotFoundException, InvalidArgumentException {
|
||||||
|
final Instant before = Instant.now();
|
||||||
|
Classification classification =
|
||||||
|
classificationService.getClassification("CLI:100000000000000000000000000000000003");
|
||||||
|
final Instant modifiedBefore = classification.getModified();
|
||||||
|
|
||||||
|
classification.setPriority(555);
|
||||||
|
classification.setServiceLevel("P12D");
|
||||||
|
|
||||||
|
updateClassificationAndRunAssociatedJobs(classification);
|
||||||
|
// Get and check the new value
|
||||||
|
Classification updatedClassification =
|
||||||
|
classificationService.getClassification("CLI:100000000000000000000000000000000003");
|
||||||
|
assertNotNull(updatedClassification);
|
||||||
|
assertFalse(modifiedBefore.isAfter(updatedClassification.getModified()));
|
||||||
|
// TODO - resume old behaviour after attachment query is possible.
|
||||||
|
TaskService taskService = taskanaEngine.getTaskService();
|
||||||
|
DaysToWorkingDaysConverter.setGermanPublicHolidaysEnabled(true);
|
||||||
|
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize(Instant.now());
|
||||||
|
List<String> tasksWithPD12 =
|
||||||
|
new ArrayList<>(
|
||||||
|
Arrays.asList(
|
||||||
|
"TKI:000000000000000000000000000000000003",
|
||||||
|
"TKI:000000000000000000000000000000000004",
|
||||||
|
"TKI:000000000000000000000000000000000005",
|
||||||
|
"TKI:000000000000000000000000000000000006",
|
||||||
|
"TKI:000000000000000000000000000000000007",
|
||||||
|
"TKI:000000000000000000000000000000000009",
|
||||||
|
"TKI:000000000000000000000000000000000010",
|
||||||
|
"TKI:000000000000000000000000000000000012",
|
||||||
|
"TKI:000000000000000000000000000000000013",
|
||||||
|
"TKI:000000000000000000000000000000000014",
|
||||||
|
"TKI:000000000000000000000000000000000015",
|
||||||
|
"TKI:000000000000000000000000000000000016",
|
||||||
|
"TKI:000000000000000000000000000000000017",
|
||||||
|
"TKI:000000000000000000000000000000000018",
|
||||||
|
"TKI:000000000000000000000000000000000019",
|
||||||
|
"TKI:000000000000000000000000000000000020",
|
||||||
|
"TKI:000000000000000000000000000000000021",
|
||||||
|
"TKI:000000000000000000000000000000000022",
|
||||||
|
"TKI:000000000000000000000000000000000023",
|
||||||
|
"TKI:000000000000000000000000000000000024",
|
||||||
|
"TKI:000000000000000000000000000000000025",
|
||||||
|
"TKI:000000000000000000000000000000000026",
|
||||||
|
"TKI:000000000000000000000000000000000027",
|
||||||
|
"TKI:000000000000000000000000000000000028",
|
||||||
|
"TKI:000000000000000000000000000000000029",
|
||||||
|
"TKI:000000000000000000000000000000000030",
|
||||||
|
"TKI:000000000000000000000000000000000031",
|
||||||
|
"TKI:000000000000000000000000000000000032",
|
||||||
|
"TKI:000000000000000000000000000000000033",
|
||||||
|
"TKI:000000000000000000000000000000000034",
|
||||||
|
"TKI:000000000000000000000000000000000035",
|
||||||
|
"TKI:000000000000000000000000000000000100",
|
||||||
|
"TKI:000000000000000000000000000000000101",
|
||||||
|
"TKI:000000000000000000000000000000000102",
|
||||||
|
"TKI:000000000000000000000000000000000103",
|
||||||
|
"TKI:200000000000000000000000000000000007"));
|
||||||
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithPD12, taskService, converter, 12, 555);
|
||||||
|
|
||||||
|
List<String> tasksWithPD8 =
|
||||||
|
new ArrayList<>(Arrays.asList("TKI:000000000000000000000000000000000008"));
|
||||||
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithPD8, taskService, converter, 8, 555);
|
||||||
|
|
||||||
|
List<String> tasksWithPD1 =
|
||||||
|
new ArrayList<>(
|
||||||
|
Arrays.asList(
|
||||||
|
"TKI:000000000000000000000000000000000000",
|
||||||
|
"TKI:000000000000000000000000000000000011",
|
||||||
|
"TKI:000000000000000000000000000000000052",
|
||||||
|
"TKI:000000000000000000000000000000000053",
|
||||||
|
"TKI:000000000000000000000000000000000054",
|
||||||
|
"TKI:000000000000000000000000000000000055"));
|
||||||
|
validateTaskPropertiesAfterClassificationChange(
|
||||||
|
before, tasksWithPD1, taskService, converter, 1, 555);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateClassificationAndRunAssociatedJobs(Classification classification)
|
||||||
|
throws ClassificationNotFoundException, NotAuthorizedException, ConcurrencyException,
|
||||||
|
InvalidArgumentException, InterruptedException {
|
||||||
|
classificationService.updateClassification(classification);
|
||||||
|
Thread.sleep(10);
|
||||||
|
// run the ClassificationChangedJob
|
||||||
|
JobRunner runner = new JobRunner(taskanaEngine);
|
||||||
|
// run the TaskRefreshJob that was scheduled by the ClassificationChangedJob.
|
||||||
|
runner.runJobs();
|
||||||
|
Thread.sleep(10); // otherwise the next runJobs call intermittently doesn't find the Job created
|
||||||
|
// by the previous step (it searches with DueDate < CurrentTime)
|
||||||
|
runner.runJobs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateTaskPropertiesAfterClassificationChange(
|
||||||
Instant before,
|
Instant before,
|
||||||
List<String> tasksWithP15D,
|
List<String> tasksUpdated,
|
||||||
TaskService taskService,
|
TaskService taskService,
|
||||||
DaysToWorkingDaysConverter converter,
|
DaysToWorkingDaysConverter converter,
|
||||||
int serviceLevel)
|
int serviceLevel,
|
||||||
throws TaskNotFoundException, NotAuthorizedException {
|
int priority)
|
||||||
for (String taskId : tasksWithP15D) {
|
throws TaskNotFoundException, NotAuthorizedException, InvalidArgumentException {
|
||||||
|
for (String taskId : tasksUpdated) {
|
||||||
Task task = taskService.getTask(taskId);
|
Task task = taskService.getTask(taskId);
|
||||||
assertTrue(
|
assertTrue(
|
||||||
task.getModified().isAfter(before), "Task " + task.getId() + " has not been refreshed.");
|
task.getModified().isAfter(before), "Task " + task.getId() + " has not been refreshed.");
|
||||||
assertEquals(1000, task.getPriority());
|
|
||||||
long calendarDays = converter.convertWorkingDaysToDays(task.getPlanned(), serviceLevel);
|
long calendarDays = converter.convertWorkingDaysToDays(task.getPlanned(), serviceLevel);
|
||||||
|
|
||||||
String msg =
|
String msg =
|
||||||
"Task: "
|
String.format(
|
||||||
+ taskId
|
"Task: %s and Due Date: %s do not match planned %s. Calendar days : %s.",
|
||||||
+ ": Due Date "
|
taskId, task.getDue(), task.getPlanned(), calendarDays);
|
||||||
+ task.getDue()
|
|
||||||
+ " does not match planned "
|
|
||||||
+ task.getPlanned()
|
|
||||||
+ " + calendar days "
|
|
||||||
+ calendarDays;
|
|
||||||
assertEquals(task.getDue(), task.getPlanned().plus(Duration.ofDays(calendarDays)), msg);
|
assertEquals(task.getDue(), task.getPlanned().plus(Duration.ofDays(calendarDays)), msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ public class UpdateObjectsUseUtcTimeStampsAccTest extends AbstractAccTest {
|
||||||
|
|
||||||
TaskImpl ti = (TaskImpl) task;
|
TaskImpl ti = (TaskImpl) task;
|
||||||
ti.setCompleted(now.plus(Duration.ofHours(27)));
|
ti.setCompleted(now.plus(Duration.ofHours(27)));
|
||||||
|
|
||||||
TimeZone originalZone = TimeZone.getDefault();
|
TimeZone originalZone = TimeZone.getDefault();
|
||||||
Task updatedTask = taskService.updateTask(task);
|
Task updatedTask = taskService.updateTask(task);
|
||||||
TimeZone.setDefault(TimeZone.getTimeZone("EST"));
|
TimeZone.setDefault(TimeZone.getTimeZone("EST"));
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ public class ServiceLevelPriorityAccTest extends AbstractAccTest {
|
||||||
String tkId1 = "TKI:000000000000000000000000000000000008";
|
String tkId1 = "TKI:000000000000000000000000000000000008";
|
||||||
String tkId2 = "TKI:000000000000000000000000000000000009";
|
String tkId2 = "TKI:000000000000000000000000000000000009";
|
||||||
String tkId3 = "TKI:000000000000000000000000000000000008";
|
String tkId3 = "TKI:000000000000000000000000000000000008";
|
||||||
String tkId4 = "TKI:000000000000000000000000000000000010";
|
String tkId4 = "TKI:000000000000000000000000000000000010"; // all three have P13D
|
||||||
|
|
||||||
List<String> taskIds = Arrays.asList(tkId1, tkId2, tkId3, tkId4);
|
List<String> taskIds = Arrays.asList(tkId1, tkId2, tkId3, tkId4);
|
||||||
Instant planned = getInstant("2020-05-03T07:00:00");
|
Instant planned = getInstant("2020-05-03T07:00:00");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue