TSK-926: Intertwine planned and due Date for task creation
This commit is contained in:
parent
25668e1324
commit
4e095f4580
|
@ -25,6 +25,7 @@ public interface Task {
|
||||||
* @return external Id
|
* @return external Id
|
||||||
*/
|
*/
|
||||||
String getExternalId();
|
String getExternalId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the external Id. It can be used to correlate the task to a task in an external system.
|
* Sets the external Id. It can be used to correlate the task to a task in an external system.
|
||||||
* The external Id is enforced to be unique. An attempt to create a task with
|
* The external Id is enforced to be unique. An attempt to create a task with
|
||||||
|
@ -36,7 +37,7 @@ public interface Task {
|
||||||
*/
|
*/
|
||||||
void setExternalId(String externalId);
|
void setExternalId(String externalId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the UserId of the task-creator.
|
* Gets the UserId of the task-creator.
|
||||||
*
|
*
|
||||||
* @return creator
|
* @return creator
|
||||||
|
@ -93,6 +94,14 @@ public interface Task {
|
||||||
*/
|
*/
|
||||||
Instant getDue();
|
Instant getDue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the time when the work on this task should be finished.
|
||||||
|
*
|
||||||
|
* @param due
|
||||||
|
* as exact {@link Instant}
|
||||||
|
*/
|
||||||
|
void setDue(Instant due);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the name of the current task.
|
* Return the name of the current task.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.LongStream;
|
import java.util.stream.LongStream;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
@ -96,6 +97,10 @@ public final class DaysToWorkingDaysConverter {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<DaysToWorkingDaysConverter> getLastCreatedInstance() {
|
||||||
|
return Optional.ofNullable(instance);
|
||||||
|
}
|
||||||
|
|
||||||
public static void setGermanPublicHolidaysEnabled(boolean germanPublicHolidaysEnabled) {
|
public static void setGermanPublicHolidaysEnabled(boolean germanPublicHolidaysEnabled) {
|
||||||
germanHolidaysEnabled = germanPublicHolidaysEnabled;
|
germanHolidaysEnabled = germanPublicHolidaysEnabled;
|
||||||
}
|
}
|
||||||
|
@ -179,8 +184,10 @@ public final class DaysToWorkingDaysConverter {
|
||||||
public long convertWorkingDaysToDays(Instant startTime, long numberOfDays) {
|
public long convertWorkingDaysToDays(Instant startTime, long numberOfDays) {
|
||||||
int days = 0;
|
int days = 0;
|
||||||
int workingDays = 0;
|
int workingDays = 0;
|
||||||
while (workingDays < numberOfDays) {
|
int direction = numberOfDays > 0 ? 1 : -1;
|
||||||
workingDays += isWorkingDay(++days, startTime) ? 1 : 0;
|
while (workingDays < numberOfDays * direction) {
|
||||||
|
days += direction;
|
||||||
|
workingDays += isWorkingDay(days, startTime) ? 1 : 0;
|
||||||
}
|
}
|
||||||
return days;
|
return days;
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,6 +146,7 @@ public class TaskImpl implements Task {
|
||||||
return due;
|
return due;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setDue(Instant due) {
|
public void setDue(Instant due) {
|
||||||
this.due = due;
|
this.due = due;
|
||||||
}
|
}
|
||||||
|
|
|
@ -637,18 +637,46 @@ public class TaskServiceImpl implements TaskService {
|
||||||
}
|
}
|
||||||
task.setCreator(creator);
|
task.setCreator(creator);
|
||||||
|
|
||||||
if (task.getPlanned() == null) {
|
|
||||||
task.setPlanned(now);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 (task.getBusinessProcessId() == null) {
|
||||||
task.setBusinessProcessId(IdGenerator.generateWithPrefix(ID_PREFIX_BUSINESS_PROCESS));
|
task.setBusinessProcessId(IdGenerator.generateWithPrefix(ID_PREFIX_BUSINESS_PROCESS));
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert Classification specifications if Classification is given.
|
// insert Classification specifications if Classification is given.
|
||||||
|
if (classification == null) {
|
||||||
|
if (task.getPlanned() == null) {
|
||||||
|
task.setPlanned(now);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get duration in days from planned to due
|
||||||
|
PrioDurationHolder finalPrioDuration = getNewPrioDuration(prioDurationFromAttachments,
|
||||||
|
classification.getPriority(), classification.getServiceLevel());
|
||||||
|
Duration finalDuration = finalPrioDuration.getDuration();
|
||||||
|
if (finalDuration != null && !MAX_DURATION.equals(finalDuration)) {
|
||||||
|
// if we have a due date we need to go x days backwards,
|
||||||
|
// else we take the planned date (or now as fallback) and add x Days
|
||||||
|
if (task.getDue() != null) {
|
||||||
|
long days = converter.convertWorkingDaysToDays(task.getDue(), -finalDuration.toDays());
|
||||||
|
//days < 0 -> so we ne need to add, not substract
|
||||||
|
Instant planned = task.getDue().plus(Duration.ofDays(days));
|
||||||
|
task.setPlanned(planned);
|
||||||
|
} else {
|
||||||
|
task.setPlanned(task.getPlanned() == null ? now : task.getPlanned());
|
||||||
|
long days = converter.convertWorkingDaysToDays(task.getPlanned(), finalDuration.toDays());
|
||||||
|
Instant due = task.getPlanned().plus(Duration.ofDays(days));
|
||||||
|
task.setDue(due);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task.setPriority(finalPrioDuration.getPrio());
|
||||||
|
}
|
||||||
|
|
||||||
processStandardSettingsForConfiguration(task, classification, prioDurationFromAttachments);
|
if (task.getName() == null && classification != null) {
|
||||||
|
task.setName(classification.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task.getDescription() == null && classification != null) {
|
||||||
|
task.setDescription(classification.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
// insert Attachments if needed
|
// insert Attachments if needed
|
||||||
List<Attachment> attachments = task.getAttachments();
|
List<Attachment> attachments = task.getAttachments();
|
||||||
|
@ -665,32 +693,6 @@ public class TaskServiceImpl implements TaskService {
|
||||||
LOGGER.debug("exit from standardSettings()");
|
LOGGER.debug("exit from standardSettings()");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processStandardSettingsForConfiguration(TaskImpl task, Classification classification,
|
|
||||||
PrioDurationHolder prioDurationFromAttachments) {
|
|
||||||
LOGGER.debug("entry to processStandardSettingsForConfiguration()");
|
|
||||||
if (classification != null) {
|
|
||||||
PrioDurationHolder finalPrioDuration = getNewPrioDuration(prioDurationFromAttachments,
|
|
||||||
classification.getPriority(), classification.getServiceLevel());
|
|
||||||
Duration finalDuration = finalPrioDuration.getDuration();
|
|
||||||
if (finalDuration != null && !MAX_DURATION.equals(finalDuration)) {
|
|
||||||
long days = converter.convertWorkingDaysToDays(task.getPlanned(), finalDuration.toDays());
|
|
||||||
Instant due = task.getPlanned().plus(Duration.ofDays(days));
|
|
||||||
task.setDue(due);
|
|
||||||
}
|
|
||||||
task.setPriority(finalPrioDuration.getPrio());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task.getName() == null && classification != null) {
|
|
||||||
task.setName(classification.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task.getDescription() == null && classification != null) {
|
|
||||||
task.setDescription(classification.getDescription());
|
|
||||||
}
|
|
||||||
LOGGER.debug("exit from processStandardSettingsForConfiguration()");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCallbackStateOnTaskCreation(TaskImpl task) throws InvalidArgumentException {
|
private void setCallbackStateOnTaskCreation(TaskImpl task) throws InvalidArgumentException {
|
||||||
Map<String, String> callbackInfo = task.getCallbackInfo();
|
Map<String, String> callbackInfo = task.getCallbackInfo();
|
||||||
if (callbackInfo != null && callbackInfo.containsKey(Task.CALLBACK_STATE)) {
|
if (callbackInfo != null && callbackInfo.containsKey(Task.CALLBACK_STATE)) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.apache.ibatis.session.Configuration;
|
import org.apache.ibatis.session.Configuration;
|
||||||
|
@ -24,6 +25,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
import acceptance.AbstractAccTest;
|
import acceptance.AbstractAccTest;
|
||||||
import pro.taskana.Attachment;
|
import pro.taskana.Attachment;
|
||||||
|
import pro.taskana.Classification;
|
||||||
|
import pro.taskana.ClassificationService;
|
||||||
import pro.taskana.ObjectReference;
|
import pro.taskana.ObjectReference;
|
||||||
import pro.taskana.Task;
|
import pro.taskana.Task;
|
||||||
import pro.taskana.TaskService;
|
import pro.taskana.TaskService;
|
||||||
|
@ -332,6 +335,84 @@ class CreateTaskAccTest extends AbstractAccTest {
|
||||||
assertNotNull(readTask.getAttachments().get(0).getObjectReference());
|
assertNotNull(readTask.getAttachments().get(0).getObjectReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WithAccessId(
|
||||||
|
userName = "user_1_1",
|
||||||
|
groupNames = {"group_1"})
|
||||||
|
@Test
|
||||||
|
void testCalculationOfDueDateAtCreate()
|
||||||
|
throws NotAuthorizedException, InvalidArgumentException, ClassificationNotFoundException,
|
||||||
|
WorkbasketNotFoundException, TaskAlreadyExistException, TaskNotFoundException {
|
||||||
|
|
||||||
|
TaskService taskService = taskanaEngine.getTaskService();
|
||||||
|
ClassificationService classificationService = taskanaEngine.getClassificationService();
|
||||||
|
|
||||||
|
//SL P16D
|
||||||
|
Classification classification = classificationService.getClassification("L110105", "DOMAIN_A");
|
||||||
|
long serviceLevelDays = Duration.parse(classification.getServiceLevel()).toDays();
|
||||||
|
assertTrue(serviceLevelDays > 5);
|
||||||
|
|
||||||
|
Task newTask = taskService.newTask("USER_1_1", classification.getDomain());
|
||||||
|
newTask.setClassificationKey(classification.getKey());
|
||||||
|
newTask.setPrimaryObjRef(createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
|
||||||
|
|
||||||
|
Instant planned = Instant.now().plus(10, ChronoUnit.DAYS);
|
||||||
|
newTask.setPlanned(planned);
|
||||||
|
Task createdTask = taskService.createTask(newTask);
|
||||||
|
assertNotNull(createdTask.getId());
|
||||||
|
|
||||||
|
Task readTask = taskService.getTask(createdTask.getId());
|
||||||
|
assertNotNull(readTask);
|
||||||
|
assertEquals(planned, readTask.getPlanned());
|
||||||
|
|
||||||
|
Optional<Instant> shouldBeDueDate = DaysToWorkingDaysConverter.getLastCreatedInstance()
|
||||||
|
.map(converter -> converter.convertWorkingDaysToDays(readTask.getPlanned(), serviceLevelDays))
|
||||||
|
.map(
|
||||||
|
calendarDays -> readTask.getPlanned().plus(Duration.ofDays(calendarDays)));
|
||||||
|
assertTrue(shouldBeDueDate.isPresent());
|
||||||
|
assertEquals(readTask.getDue(), shouldBeDueDate.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithAccessId(
|
||||||
|
userName = "user_1_1",
|
||||||
|
groupNames = {"group_1"})
|
||||||
|
@Test
|
||||||
|
void testCalculationOfPlannedDateAtCreate()
|
||||||
|
throws NotAuthorizedException, InvalidArgumentException, ClassificationNotFoundException,
|
||||||
|
WorkbasketNotFoundException, TaskAlreadyExistException, TaskNotFoundException {
|
||||||
|
|
||||||
|
TaskService taskService = taskanaEngine.getTaskService();
|
||||||
|
ClassificationService classificationService = taskanaEngine.getClassificationService();
|
||||||
|
|
||||||
|
//SL P16D
|
||||||
|
Classification classification = classificationService.getClassification("L110105", "DOMAIN_A");
|
||||||
|
long serviceLevelDays = Duration.parse(classification.getServiceLevel()).toDays();
|
||||||
|
assertTrue(serviceLevelDays > 5);
|
||||||
|
|
||||||
|
Task newTask = taskService.newTask("USER_1_1", classification.getDomain());
|
||||||
|
newTask.setClassificationKey(classification.getKey());
|
||||||
|
newTask.setPrimaryObjRef(createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
|
||||||
|
|
||||||
|
Instant due = Instant.now().plus(40, ChronoUnit.DAYS);
|
||||||
|
newTask.setDue(due);
|
||||||
|
Task createdTask = taskService.createTask(newTask);
|
||||||
|
assertNotNull(createdTask.getId());
|
||||||
|
|
||||||
|
Task readTask = taskService.getTask(createdTask.getId());
|
||||||
|
assertNotNull(readTask);
|
||||||
|
assertEquals(due, readTask.getDue());
|
||||||
|
|
||||||
|
|
||||||
|
Optional<Long> calendarDaysToSubstract = DaysToWorkingDaysConverter.getLastCreatedInstance()
|
||||||
|
.map(converter -> converter.convertWorkingDaysToDays(readTask.getPlanned(), -serviceLevelDays));
|
||||||
|
|
||||||
|
assertTrue(calendarDaysToSubstract.isPresent());
|
||||||
|
assertTrue(calendarDaysToSubstract.get() < 0);
|
||||||
|
assertTrue(calendarDaysToSubstract.get() <= -serviceLevelDays);
|
||||||
|
|
||||||
|
Instant shouldBePlannedDate = due.plus(Duration.ofDays(calendarDaysToSubstract.get()));
|
||||||
|
assertEquals(readTask.getPlanned(), shouldBePlannedDate);
|
||||||
|
}
|
||||||
|
|
||||||
@WithAccessId(
|
@WithAccessId(
|
||||||
userName = "user_1_1",
|
userName = "user_1_1",
|
||||||
groupNames = {"group_1"})
|
groupNames = {"group_1"})
|
||||||
|
|
|
@ -49,7 +49,21 @@ class DaysToWorkingDaysConverterTest {
|
||||||
Instant thursday0201 = Instant.parse("2018-02-01T07:00:00.000Z");
|
Instant thursday0201 = Instant.parse("2018-02-01T07:00:00.000Z");
|
||||||
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize(reportItems, thursday0201);
|
DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter.initialize(reportItems, thursday0201);
|
||||||
|
|
||||||
long days = converter.convertWorkingDaysToDays(thursday0201, 0); // = thursday
|
long days = converter.convertWorkingDaysToDays(thursday0201, -7); // = tuesday (sat + sun)
|
||||||
|
assertEquals(-9, days);
|
||||||
|
days = converter.convertWorkingDaysToDays(thursday0201, -6); // = wednesday (sat + sun)
|
||||||
|
assertEquals(-8, days);
|
||||||
|
days = converter.convertWorkingDaysToDays(thursday0201, -5); // = thursday (sat + sun)
|
||||||
|
assertEquals(-7, days);
|
||||||
|
days = converter.convertWorkingDaysToDays(thursday0201, -4); // = friday
|
||||||
|
assertEquals(-6, days);
|
||||||
|
days = converter.convertWorkingDaysToDays(thursday0201, -3); // monday
|
||||||
|
assertEquals(-3, days);
|
||||||
|
days = converter.convertWorkingDaysToDays(thursday0201, -2); // tuesday
|
||||||
|
assertEquals(-2, days);
|
||||||
|
days = converter.convertWorkingDaysToDays(thursday0201, -1); // wednesday
|
||||||
|
assertEquals(-1, days);
|
||||||
|
days = converter.convertWorkingDaysToDays(thursday0201, 0); // = thursday
|
||||||
assertEquals(0, days);
|
assertEquals(0, days);
|
||||||
days = converter.convertWorkingDaysToDays(thursday0201, 1); // fri
|
days = converter.convertWorkingDaysToDays(thursday0201, 1); // fri
|
||||||
assertEquals(1, days);
|
assertEquals(1, days);
|
||||||
|
|
Loading…
Reference in New Issue