Implemented creation of task instances at initial creation of case, and listing of task instances.
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java b/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
index 35a7701..496bd2d 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
@@ -144,35 +144,35 @@
final TaskDefinition taskDefinition);
@RequestMapping(
- value = "/products/{productidentifier}/tasks/{taskdefinitionidentifier}",
+ value = "/products/{productidentifier}/tasks/{taskidentifier}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE
)
TaskDefinition getTaskDefinition(
@PathVariable("productidentifier") final String productIdentifier,
- @PathVariable("taskdefinitionidentifier") final String taskDefinitionIdentifier);
+ @PathVariable("taskidentifier") final String taskDefinitionIdentifier);
@RequestMapping(
- value = "/products/{productidentifier}/tasks/{taskdefinitionidentifier}",
+ value = "/products/{productidentifier}/tasks/{taskidentifier}",
method = RequestMethod.PUT,
produces = MediaType.ALL_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
@ThrowsException(status = HttpStatus.CONFLICT, exception = ProductInUseException.class)
void changeTaskDefinition(
@PathVariable("productidentifier") final String productIdentifier,
- @PathVariable("taskdefinitionidentifier") final String taskDefinitionIdentifier,
+ @PathVariable("taskidentifier") final String taskDefinitionIdentifier,
final TaskDefinition taskDefinition);
@RequestMapping(
- value = "/products/{productidentifier}/tasks/{taskdefinitionidentifier}",
+ value = "/products/{productidentifier}/tasks/{taskidentifier}",
method = RequestMethod.DELETE,
produces = MediaType.ALL_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
@ThrowsException(status = HttpStatus.CONFLICT, exception = ProductInUseException.class)
void deleteTaskDefinition(
@PathVariable("productidentifier") final String productIdentifier,
- @PathVariable("taskdefinitionidentifier") final String taskDefinitionIdentifier);
+ @PathVariable("taskidentifier") final String taskDefinitionIdentifier);
@RequestMapping(
value = "/products/{productidentifier}/charges/",
@@ -299,13 +299,13 @@
consumes = MediaType.APPLICATION_JSON_VALUE
)
List<TaskInstance> getAllTasksForCase(@PathVariable("productidentifier") final String productIdentifier,
- @PathVariable("caseidentifier") final String caseIdentifier,
- @RequestParam(value = "includeExecuted", required = false) final Boolean includeExecuted);
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ @RequestParam(value = "includeExecuted", required = false) final Boolean includeExecuted);
@RequestMapping(
value = "/products/{productidentifier}/cases/{caseidentifier}/tasks/{taskidentifier}",
method = RequestMethod.GET,
- produces = MediaType.ALL_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE
)
TaskInstance getTaskForCase(@PathVariable("productidentifier") final String productIdentifier,
@@ -313,14 +313,26 @@
@PathVariable("taskidentifier") final String taskIdentifier);
@RequestMapping(
+ value = "/products/{productidentifier}/cases/{caseidentifier}/tasks/{taskidentifier}",
+ method = RequestMethod.PUT,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ void changeTaskForCase(@PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ @PathVariable("taskidentifier") final String taskIdentifier,
+ final TaskInstance instance);
+
+ @RequestMapping(
value = "/products/{productidentifier}/cases/{caseidentifier}/tasks/{taskidentifier}/executed",
method = RequestMethod.PUT,
produces = MediaType.ALL_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE
)
- void taskForCaseExecuted(@PathVariable("productidentifier") final String productIdentifier,
- @PathVariable("caseidentifier") final String caseIdentifier,
- @PathVariable("taskidentifier") final String taskIdentifier);
+ void markTaskExecution(@PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ @PathVariable("taskidentifier") final String taskIdentifier,
+ final Boolean executed);
@RequestMapping(
value = "/cases/",
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/domain/TaskInstance.java b/api/src/main/java/io/mifos/portfolio/api/v1/domain/TaskInstance.java
index 5b2aadf..9e0de90 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/domain/TaskInstance.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/domain/TaskInstance.java
@@ -16,39 +16,41 @@
package io.mifos.portfolio.api.v1.domain;
import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+import org.hibernate.validator.constraints.Length;
-import javax.validation.constraints.NotNull;
+import java.util.Objects;
/**
* @author Myrle Krantz
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public final class TaskInstance {
- @NotNull
- private TaskDefinition taskDefinition;
+ @ValidIdentifier
+ private String taskIdentifier;
+ @Length(max = 4096)
private String comment;
+
private String executedOn;
- @ValidIdentifier
private String executedBy;
public TaskInstance() {
}
- public TaskInstance(TaskDefinition taskDefinition, String comment, String executedOn, String executedBy) {
- this.taskDefinition = taskDefinition;
+ public TaskInstance(String taskIdentifier, String comment, String executedOn, String executedBy) {
+ this.taskIdentifier = taskIdentifier;
this.comment = comment;
this.executedOn = executedOn;
this.executedBy = executedBy;
}
- public TaskDefinition getTaskDefinition() {
- return taskDefinition;
+ public String getTaskIdentifier() {
+ return taskIdentifier;
}
- public void setTaskDefinition(TaskDefinition taskDefinition) {
- this.taskDefinition = taskDefinition;
+ public void setTaskIdentifier(String taskIdentifier) {
+ this.taskIdentifier = taskIdentifier;
}
public String getComment() {
@@ -79,29 +81,25 @@
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
-
TaskInstance that = (TaskInstance) o;
-
- return taskDefinition != null ? taskDefinition.equals(that.taskDefinition) : that.taskDefinition == null && (comment != null ? comment.equals(that.comment) : that.comment == null && (executedOn != null ? executedOn.equals(that.executedOn) : that.executedOn == null && (executedBy != null ? executedBy.equals(that.executedBy) : that.executedBy == null)));
-
+ return Objects.equals(taskIdentifier, that.taskIdentifier) &&
+ Objects.equals(comment, that.comment) &&
+ Objects.equals(executedOn, that.executedOn) &&
+ Objects.equals(executedBy, that.executedBy);
}
@Override
public int hashCode() {
- int result = taskDefinition != null ? taskDefinition.hashCode() : 0;
- result = 31 * result + (comment != null ? comment.hashCode() : 0);
- result = 31 * result + (executedOn != null ? executedOn.hashCode() : 0);
- result = 31 * result + (executedBy != null ? executedBy.hashCode() : 0);
- return result;
+ return Objects.hash(taskIdentifier, comment, executedOn, executedBy);
}
@Override
public String toString() {
return "TaskInstance{" +
- "taskDefinition=" + taskDefinition +
- ", comment='" + comment + '\'' +
- ", executedOn='" + executedOn + '\'' +
- ", executedBy='" + executedBy + '\'' +
- '}';
+ "taskIdentifier='" + taskIdentifier + '\'' +
+ ", comment='" + comment + '\'' +
+ ", executedOn='" + executedOn + '\'' +
+ ", executedBy='" + executedBy + '\'' +
+ '}';
}
}
diff --git a/api/src/test/java/io/mifos/portfolio/api/v1/domain/TaskInstanceTest.java b/api/src/test/java/io/mifos/portfolio/api/v1/domain/TaskInstanceTest.java
new file mode 100644
index 0000000..81140d7
--- /dev/null
+++ b/api/src/test/java/io/mifos/portfolio/api/v1/domain/TaskInstanceTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.api.v1.domain;
+
+import io.mifos.core.test.domain.ValidationTest;
+import io.mifos.core.test.domain.ValidationTestCase;
+import org.apache.commons.lang.RandomStringUtils;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @author Myrle Krantz
+ */
+public class TaskInstanceTest extends ValidationTest<TaskInstance> {
+
+ public TaskInstanceTest(ValidationTestCase<TaskInstance> testCase) {
+ super(testCase);
+ }
+
+ @Override
+ protected TaskInstance createValidTestSubject() {
+ final TaskInstance ret = new TaskInstance();
+ ret.setComment("Hey how y'all doin'.");
+ ret.setTaskIdentifier("validIdentifier");
+ return ret;
+ }
+
+ @Parameterized.Parameters
+ public static Collection testCases() {
+ final Collection<ValidationTestCase> ret = new ArrayList<>();
+
+ ret.add(new ValidationTestCase<TaskInstance>("valid")
+ .adjustment(x -> {})
+ .valid(true));
+ ret.add(new ValidationTestCase<TaskInstance>("nullIdentifier")
+ .adjustment(x -> x.setTaskIdentifier(null))
+ .valid(false));
+ ret.add(new ValidationTestCase<TaskInstance>("null Comment")
+ .adjustment(x -> x.setComment(null))
+ .valid(true));
+ ret.add(new ValidationTestCase<TaskInstance>("too long Comment")
+ .adjustment(x -> x.setComment(RandomStringUtils.random(5000)))
+ .valid(false));
+
+ return ret;
+ }
+}
\ No newline at end of file
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestSuite.java b/component-test/src/main/java/io/mifos/portfolio/TestSuite.java
index 4fba15b..e7bd386 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestSuite.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestSuite.java
@@ -30,7 +30,8 @@
TestIndividualLoans.class,
TestPatterns.class,
TestProducts.class,
- TestTaskDefinitions.class
+ TestTaskDefinitions.class,
+ TestTaskInstances.class
})
public class TestSuite extends SuiteTestEnvironment {
}
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java b/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
new file mode 100644
index 0000000..956839c
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio;
+
+import io.mifos.portfolio.api.v1.domain.Case;
+import io.mifos.portfolio.api.v1.domain.Product;
+import io.mifos.portfolio.api.v1.domain.TaskDefinition;
+import io.mifos.portfolio.api.v1.domain.TaskInstance;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * @author Myrle Krantz
+ */
+public class TestTaskInstances extends AbstractPortfolioTest {
+
+ @Test
+ public void shouldListTaskInstances() throws InterruptedException {
+ final Product product = createProduct();
+ final TaskDefinition taskDefinition = createTaskDefinition(product);
+
+ enableProduct(product);
+
+ final Case customerCase = createCase(product.getIdentifier());
+
+ final List<TaskInstance> taskInstances = portfolioManager.getAllTasksForCase(product.getIdentifier(), customerCase.getIdentifier(), false);
+ Assert.assertEquals(1, taskInstances.size());
+ Assert.assertEquals(taskDefinition.getIdentifier(), taskInstances.get(0).getTaskIdentifier());
+ }
+}
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/command/ChangeTaskInstanceCommand.java b/service/src/main/java/io/mifos/portfolio/service/internal/command/ChangeTaskInstanceCommand.java
new file mode 100644
index 0000000..e94ceb4
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/command/ChangeTaskInstanceCommand.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.service.internal.command;
+
+import io.mifos.portfolio.api.v1.domain.TaskInstance;
+
+/**
+ * @author Myrle Krantz
+ */
+public class ChangeTaskInstanceCommand {
+ private final String productIdentifier;
+ private final String caseIdentifier;
+ private final TaskInstance instance;
+
+ public ChangeTaskInstanceCommand(String productIdentifier, String caseIdentifier, TaskInstance instance) {
+ this.productIdentifier = productIdentifier;
+ this.caseIdentifier = caseIdentifier;
+ this.instance = instance;
+ }
+
+ public String getProductIdentifier() {
+ return productIdentifier;
+ }
+
+ public String getCaseIdentifier() {
+ return caseIdentifier;
+ }
+
+ public TaskInstance getInstance() {
+ return instance;
+ }
+
+ @Override
+ public String toString() {
+ return "ChangeTaskInstanceCommand{" +
+ "productIdentifier='" + productIdentifier + '\'' +
+ ", caseIdentifier='" + caseIdentifier + '\'' +
+ ", taskIdentifier=" + instance.getTaskIdentifier() +
+ '}';
+ }
+}
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/command/ExecuteTaskInstanceCommand.java b/service/src/main/java/io/mifos/portfolio/service/internal/command/ExecuteTaskInstanceCommand.java
new file mode 100644
index 0000000..a1e13f7
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/command/ExecuteTaskInstanceCommand.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.service.internal.command;
+
+/**
+ * @author Myrle Krantz
+ */
+public class ExecuteTaskInstanceCommand {
+ private final String productIdentifier;
+ private final String caseIdentifier;
+ private final String taskIdentifier;
+ private final Boolean executed;
+
+ public ExecuteTaskInstanceCommand(String productIdentifier, String caseIdentifier, String taskIdentifier, Boolean executed) {
+ this.productIdentifier = productIdentifier;
+ this.caseIdentifier = caseIdentifier;
+ this.taskIdentifier = taskIdentifier;
+ this.executed = executed;
+ }
+
+ @Override
+ public String toString() {
+ return "ExecuteTaskInstanceCommand{" +
+ "productIdentifier='" + productIdentifier + '\'' +
+ ", caseIdentifier='" + caseIdentifier + '\'' +
+ ", taskIdentifier='" + taskIdentifier + '\'' +
+ ", executed=" + executed +
+ '}';
+ }
+}
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/command/handler/CaseCommandHandler.java b/service/src/main/java/io/mifos/portfolio/service/internal/command/handler/CaseCommandHandler.java
index eabd4b4..a8700c0 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/command/handler/CaseCommandHandler.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/command/handler/CaseCommandHandler.java
@@ -32,7 +32,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
-import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* @author Myrle Krantz
@@ -43,28 +44,34 @@
private final PatternFactoryRegistry patternFactoryRegistry;
private final ProductRepository productRepository;
private final CaseRepository caseRepository;
+ private final TaskDefinitionRepository taskDefinitionRepository;
@Autowired
public CaseCommandHandler(final PatternFactoryRegistry patternFactoryRegistry,
final ProductRepository productRepository,
- final CaseRepository caseRepository) {
+ final CaseRepository caseRepository,
+ final TaskDefinitionRepository taskDefinitionRepository) {
super();
this.patternFactoryRegistry = patternFactoryRegistry;
this.productRepository = productRepository;
this.caseRepository = caseRepository;
+ this.taskDefinitionRepository = taskDefinitionRepository;
}
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
@EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_CASE)
public CaseEvent process(final CreateCaseCommand createCaseCommand) {
- //TODO: Check that all designators are assigned to existing accounts.
- //TODO: Create accounts if necessary.
-
final Case caseInstance = createCaseCommand.getCase();
+ final Stream<TaskDefinitionEntity> tasksToCreate
+ = taskDefinitionRepository.findByProductId(createCaseCommand.getCase().getProductIdentifier());
+
final CaseEntity entity = CaseMapper.map(caseInstance);
entity.setCurrentState(Case.State.CREATED.name());
+ entity.setTaskInstances(tasksToCreate
+ .map(taskDefinition -> instanceOfDefinition(taskDefinition, entity))
+ .collect(Collectors.toSet()));
this.caseRepository.save(entity);
getPatternFactory(caseInstance.getProductIdentifier()).persistParameters(entity.getId(), caseInstance.getParameters());
@@ -76,8 +83,7 @@
private PatternFactory getPatternFactory(String productIdentifier) {
return productRepository.findByIdentifier(productIdentifier)
.map(ProductEntity::getPatternPackage)
- .map(patternFactoryRegistry::getPatternFactoryForPackage)
- .orElse(Optional.empty())
+ .flatMap(patternFactoryRegistry::getPatternFactoryForPackage)
.orElseThrow(() -> new IllegalArgumentException("Case references unsupported product type."));
}
@@ -99,4 +105,13 @@
return new CaseEvent(instance.getProductIdentifier(), instance.getIdentifier());
}
-}
+
+ private static TaskInstanceEntity instanceOfDefinition(final TaskDefinitionEntity definition,
+ final CaseEntity customerCase) {
+ final TaskInstanceEntity ret = new TaskInstanceEntity();
+ ret.setCustomerCase(customerCase);
+ ret.setTaskDefinition(definition);
+ ret.setComment("");
+ return ret;
+ }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/mapper/CaseMapper.java b/service/src/main/java/io/mifos/portfolio/service/internal/mapper/CaseMapper.java
index 10c8452..e6ece90 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/mapper/CaseMapper.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/mapper/CaseMapper.java
@@ -63,8 +63,8 @@
ret.setIdentifier(instance.getIdentifier());
ret.setProductIdentifier(instance.getProductIdentifier());
ret.setAccountAssignments(instance.getAccountAssignments().stream()
- .map(x -> CaseMapper.map(x, ret))
- .collect(Collectors.toSet()));
+ .map(x -> CaseMapper.map(x, ret))
+ .collect(Collectors.toSet()));
ret.setCurrentState(instance.getCurrentState());
final LocalDateTime time = LocalDateTime.now(Clock.systemUTC());
@@ -111,6 +111,7 @@
newEntity.setAccountAssignments(newAccountAssignmentEntities);
+ newEntity.setTaskInstances(oldEntity.getTaskInstances());
return newEntity;
}
}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/mapper/TaskInstanceMapper.java b/service/src/main/java/io/mifos/portfolio/service/internal/mapper/TaskInstanceMapper.java
new file mode 100644
index 0000000..89a899c
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/mapper/TaskInstanceMapper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.service.internal.mapper;
+
+import io.mifos.core.lang.DateConverter;
+import io.mifos.portfolio.api.v1.domain.TaskInstance;
+import io.mifos.portfolio.service.internal.repository.TaskInstanceEntity;
+
+/**
+ * @author Myrle Krantz
+ */
+public interface TaskInstanceMapper {
+ static TaskInstance map(final TaskInstanceEntity from) {
+ final TaskInstance ret = new TaskInstance();
+
+ ret.setTaskIdentifier(from.getTaskDefinition().getIdentifier());
+ ret.setComment(from.getComment());
+ ret.setExecutedBy(from.getExecutedBy());
+ ret.setExecutedOn(from.getExecutedOn() == null ? null : DateConverter.toIsoString(from.getExecutedOn()));
+
+ return ret;
+ }
+}
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/CaseEntity.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/CaseEntity.java
index f86092f..83e023f 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/repository/CaseEntity.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/CaseEntity.java
@@ -20,6 +20,7 @@
import javax.annotation.Nullable;
import javax.persistence.*;
import java.time.LocalDateTime;
+import java.util.Objects;
import java.util.Set;
/**
@@ -43,6 +44,9 @@
@OneToMany(targetEntity = CaseAccountAssignmentEntity.class, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "caseEntity")
private Set<CaseAccountAssignmentEntity> accountAssignments;
+ @OneToMany(targetEntity = TaskInstanceEntity.class, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "customerCase")
+ private Set<TaskInstanceEntity> taskInstances;
+
@Column(name = "current_state", nullable = false)
private String currentState;
@@ -99,6 +103,14 @@
this.accountAssignments = accountAssignments;
}
+ public Set<TaskInstanceEntity> getTaskInstances() {
+ return taskInstances;
+ }
+
+ public void setTaskInstances(Set<TaskInstanceEntity> taskInstances) {
+ this.taskInstances = taskInstances;
+ }
+
public String getCurrentState() {
return currentState;
}
@@ -146,4 +158,18 @@
public void setLastModifiedBy(String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CaseEntity that = (CaseEntity) o;
+ return Objects.equals(identifier, that.identifier) &&
+ Objects.equals(productIdentifier, that.productIdentifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(identifier, productIdentifier);
+ }
}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductEntity.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductEntity.java
index d13d6fc..02ae603 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductEntity.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductEntity.java
@@ -311,13 +311,13 @@
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (o == null || !(o instanceof ProductEntity)) return false;
+ if (o == null || getClass() != o.getClass()) return false;
ProductEntity that = (ProductEntity) o;
- return Objects.equals(getIdentifier(), that.getIdentifier());
+ return Objects.equals(identifier, that.identifier);
}
@Override
public int hashCode() {
- return Objects.hash(getIdentifier());
+ return Objects.hash(identifier);
}
}
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskDefinitionEntity.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskDefinitionEntity.java
index ca8e4bc..f43160d 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskDefinitionEntity.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskDefinitionEntity.java
@@ -125,12 +125,13 @@
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TaskDefinitionEntity that = (TaskDefinitionEntity) o;
- return Objects.equals(id, that.id);
+ return Objects.equals(identifier, that.identifier) &&
+ Objects.equals(product, that.product);
}
@Override
public int hashCode() {
- return Objects.hash(id);
+ return Objects.hash(identifier, product);
}
@Override
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskDefinitionRepository.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskDefinitionRepository.java
index 7c44576..6aec847 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskDefinitionRepository.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskDefinitionRepository.java
@@ -20,8 +20,8 @@
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
-import java.util.List;
import java.util.Optional;
+import java.util.stream.Stream;
/**
* @author Myrle Krantz
@@ -30,7 +30,7 @@
public interface TaskDefinitionRepository extends JpaRepository<TaskDefinitionEntity, Long> {
@SuppressWarnings("JpaQlInspection")
@Query("SELECT t FROM TaskDefinitionEntity t WHERE t.product.identifier = :productIdentifier")
- List<TaskDefinitionEntity> findByProductId(@Param("productIdentifier") String productId);
+ Stream<TaskDefinitionEntity> findByProductId(@Param("productIdentifier") String productId);
@SuppressWarnings("JpaQlInspection")
@Query("SELECT t FROM TaskDefinitionEntity t WHERE t.product.identifier = :productIdentifier AND t.identifier = :taskDefinitionIdentifier")
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskInstanceEntity.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskInstanceEntity.java
new file mode 100644
index 0000000..8ea4780
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskInstanceEntity.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.service.internal.repository;
+
+import io.mifos.core.mariadb.util.LocalDateTimeConverter;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings({"WeakerAccess", "unused"})
+@Entity
+@Table(name = "bastet_c_task_insts")
+public class TaskInstanceEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY, optional = false)
+ @JoinColumn(name = "case_id")
+ private CaseEntity customerCase;
+
+ @ManyToOne(fetch = FetchType.EAGER, optional = false)
+ @JoinColumn(name = "task_def_id")
+ private TaskDefinitionEntity taskDefinition;
+
+ @Column(name = "a_comment")
+ private String comment;
+
+ @Column(name = "executed_on")
+ @Convert(converter = LocalDateTimeConverter.class)
+ private LocalDateTime executedOn;
+
+ @Column(name = "executed_by")
+ private String executedBy;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public CaseEntity getCustomerCase() {
+ return customerCase;
+ }
+
+ public void setCustomerCase(CaseEntity customerCase) {
+ this.customerCase = customerCase;
+ }
+
+ public TaskDefinitionEntity getTaskDefinition() {
+ return taskDefinition;
+ }
+
+ public void setTaskDefinition(TaskDefinitionEntity taskDefinition) {
+ this.taskDefinition = taskDefinition;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(String comment) {
+ this.comment = comment;
+ }
+
+ public LocalDateTime getExecutedOn() {
+ return executedOn;
+ }
+
+ public void setExecutedOn(LocalDateTime executedOn) {
+ this.executedOn = executedOn;
+ }
+
+ public String getExecutedBy() {
+ return executedBy;
+ }
+
+ public void setExecutedBy(String executedBy) {
+ this.executedBy = executedBy;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ TaskInstanceEntity that = (TaskInstanceEntity) o;
+ return Objects.equals(customerCase, that.customerCase) &&
+ Objects.equals(taskDefinition, that.taskDefinition);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(customerCase, taskDefinition);
+ }
+}
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskInstanceRepository.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskInstanceRepository.java
new file mode 100644
index 0000000..a6cf051
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/TaskInstanceRepository.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+/**
+ * @author Myrle Krantz
+ */
+@Repository
+public interface TaskInstanceRepository extends JpaRepository<TaskInstanceEntity, Long> {
+ @SuppressWarnings("JpaQlInspection")
+ @Query("SELECT t FROM TaskInstanceEntity t WHERE t.taskDefinition.product.identifier = :productIdentifier AND t.customerCase.identifier = :caseIdentifier")
+ Stream<TaskInstanceEntity> findByProductIdAndCaseId(@Param("productIdentifier") String productId, @Param("caseIdentifier") String caseId);
+
+ @SuppressWarnings("JpaQlInspection")
+ @Query("SELECT t FROM TaskInstanceEntity t WHERE t.taskDefinition.product.identifier = :productIdentifier AND t.customerCase.identifier = :caseIdentifier AND t.executedOn = NULL")
+ Stream<TaskInstanceEntity> findByProductIdAndCaseIdAndExcludeExecuted(@Param("productIdentifier") String productId, @Param("caseIdentifier") String caseId);
+
+ @SuppressWarnings("JpaQlInspection")
+ @Query("SELECT t FROM TaskInstanceEntity t WHERE t.taskDefinition.product.identifier = :productIdentifier AND t.customerCase.identifier = :caseIdentifier AND t.taskDefinition.identifier = :taskIdentifier")
+ Optional<TaskInstanceEntity> findByProductIdAndCaseIdAndTaskId(@Param("productIdentifier") String productId, @Param("caseIdentifier") String caseId, @Param("taskIdentifier") String taskId);
+}
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/service/TaskDefinitionService.java b/service/src/main/java/io/mifos/portfolio/service/internal/service/TaskDefinitionService.java
index 74ff6b5..40e13d2 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/service/TaskDefinitionService.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/service/TaskDefinitionService.java
@@ -16,18 +16,14 @@
package io.mifos.portfolio.service.internal.service;
import io.mifos.portfolio.api.v1.domain.TaskDefinition;
-import io.mifos.individuallending.api.v1.domain.workflow.Action;
import io.mifos.portfolio.service.internal.mapper.TaskDefinitionMapper;
import io.mifos.portfolio.service.internal.repository.TaskDefinitionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import java.util.AbstractMap;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* @author Myrle Krantz
@@ -43,27 +39,11 @@
}
public List<TaskDefinition> findAllEntities(final String productIdentifier) {
- return taskDefinitionRepository.findByProductId(productIdentifier).stream()
+ return taskDefinitionRepository.findByProductId(productIdentifier)
.map(TaskDefinitionMapper::map)
.collect(Collectors.toList());
}
- public Map<Action, List<TaskDefinition>> getTaskDefinitionsMappedByAction(
- final String productIdentifier)
- {
- final List<TaskDefinition> taskDefinitions = findAllEntities(productIdentifier);
-
- return taskDefinitions.stream().flatMap(this::createMappingsForTaskDefinition)
- .collect(Collectors.groupingBy(Map.Entry::getKey,
- Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
- }
-
- private Stream<AbstractMap.SimpleEntry<Action, TaskDefinition>> createMappingsForTaskDefinition(
- final TaskDefinition taskDefinition)
- {
- return taskDefinition.getActions().stream().map(x -> new AbstractMap.SimpleEntry<>(Action.valueOf(x), taskDefinition));
- }
-
public Optional<TaskDefinition> findByIdentifier(final String productIdentifier, final String identifier) {
return taskDefinitionRepository
.findByProductIdAndTaskIdentifier(productIdentifier, identifier)
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/service/TaskInstanceService.java b/service/src/main/java/io/mifos/portfolio/service/internal/service/TaskInstanceService.java
new file mode 100644
index 0000000..37cfff1
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/service/TaskInstanceService.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.service.internal.service;
+
+import io.mifos.portfolio.api.v1.domain.TaskInstance;
+import io.mifos.portfolio.service.internal.mapper.TaskInstanceMapper;
+import io.mifos.portfolio.service.internal.repository.TaskInstanceEntity;
+import io.mifos.portfolio.service.internal.repository.TaskInstanceRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author Myrle Krantz
+ */
+@Service
+public class TaskInstanceService {
+ private final TaskInstanceRepository taskInstanceRepository;
+
+ @Autowired
+ public TaskInstanceService(final TaskInstanceRepository taskInstanceRepository) {
+ this.taskInstanceRepository = taskInstanceRepository;
+ }
+
+ public List<TaskInstance> findAllEntities(final String productIdentifier,
+ final String caseIdentifier,
+ final Boolean includeExecuted) {
+ final Stream<TaskInstanceEntity> ret;
+ if (includeExecuted)
+ ret = taskInstanceRepository.findByProductIdAndCaseId(productIdentifier, caseIdentifier);
+ else {
+ ret = taskInstanceRepository.findByProductIdAndCaseIdAndExcludeExecuted(productIdentifier, caseIdentifier);
+ }
+
+ return ret.map(TaskInstanceMapper::map)
+ .collect(Collectors.toList());
+ }
+
+ public Optional<TaskInstance> findByIdentifier(final String productIdentifier,
+ final String caseIdentifier,
+ final String taskIdentifier) {
+ return taskInstanceRepository.findByProductIdAndCaseIdAndTaskId(productIdentifier, caseIdentifier, taskIdentifier)
+ .map(TaskInstanceMapper::map);
+ }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/portfolio/service/rest/TaskDefinitionRestController.java b/service/src/main/java/io/mifos/portfolio/service/rest/TaskDefinitionRestController.java
index 18c5439..1e7397d 100644
--- a/service/src/main/java/io/mifos/portfolio/service/rest/TaskDefinitionRestController.java
+++ b/service/src/main/java/io/mifos/portfolio/service/rest/TaskDefinitionRestController.java
@@ -100,14 +100,14 @@
@Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.PRODUCT_MANAGEMENT)
@RequestMapping(
- value = "{taskdefinitionidentifier}",
+ value = "{taskidentifier}",
method = RequestMethod.GET,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public @ResponseBody TaskDefinition getTaskDefinition(
@PathVariable("productidentifier") final String productIdentifier,
- @PathVariable("taskdefinitionidentifier") final String taskDefinitionIdentifier)
+ @PathVariable("taskidentifier") final String taskDefinitionIdentifier)
{
checkProductExists(productIdentifier);
@@ -117,14 +117,14 @@
@Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.PRODUCT_MANAGEMENT)
@RequestMapping(
- value = "{taskdefinitionidentifier}",
+ value = "{taskidentifier}",
method = RequestMethod.PUT,
consumes = MediaType.ALL_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public @ResponseBody ResponseEntity<Void> changeTaskDefinition(
@PathVariable("productidentifier") final String productIdentifier,
- @PathVariable("taskdefinitionidentifier") final String taskDefinitionIdentifier,
+ @PathVariable("taskidentifier") final String taskDefinitionIdentifier,
@RequestBody @Valid final TaskDefinition instance)
{
checkTaskDefinitionExists(productIdentifier, taskDefinitionIdentifier);
@@ -141,14 +141,14 @@
@Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.PRODUCT_MANAGEMENT)
@RequestMapping(
- value = "/{taskdefinitionidentifier}",
+ value = "/{taskidentifier}",
method = RequestMethod.DELETE,
consumes = MediaType.ALL_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public @ResponseBody ResponseEntity<Void> deleteTaskDefinition(
@PathVariable("productidentifier") final String productIdentifier,
- @PathVariable("taskdefinitionidentifier") final String taskDefinitionIdentifier
+ @PathVariable("taskidentifier") final String taskDefinitionIdentifier
)
{
checkTaskDefinitionExists(productIdentifier, taskDefinitionIdentifier);
diff --git a/service/src/main/java/io/mifos/portfolio/service/rest/TaskInstanceRestController.java b/service/src/main/java/io/mifos/portfolio/service/rest/TaskInstanceRestController.java
new file mode 100644
index 0000000..2180b7e
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/rest/TaskInstanceRestController.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.service.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.core.lang.ServiceException;
+import io.mifos.portfolio.api.v1.PermittableGroupIds;
+import io.mifos.portfolio.api.v1.domain.TaskInstance;
+import io.mifos.portfolio.service.internal.command.ChangeTaskInstanceCommand;
+import io.mifos.portfolio.service.internal.command.ExecuteTaskInstanceCommand;
+import io.mifos.portfolio.service.internal.service.CaseService;
+import io.mifos.portfolio.service.internal.service.TaskDefinitionService;
+import io.mifos.portfolio.service.internal.service.TaskInstanceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@RestController
+@RequestMapping("/products/{productidentifier}/cases/{caseidentifier}/tasks/")
+public class TaskInstanceRestController {
+ private final CommandGateway commandGateway;
+ private final TaskDefinitionService taskDefinitionService;
+ private final TaskInstanceService taskInstanceService;
+ private final CaseService caseService;
+
+ @Autowired
+ public TaskInstanceRestController(
+ final CommandGateway commandGateway,
+ final TaskDefinitionService taskDefinitionService,
+ final TaskInstanceService taskInstanceService,
+ final CaseService caseService)
+ {
+ super();
+ this.commandGateway = commandGateway;
+ this.taskDefinitionService = taskDefinitionService;
+ this.taskInstanceService = taskInstanceService;
+ this.caseService = caseService;
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CASE_MANAGEMENT)
+ @RequestMapping(
+ method = RequestMethod.GET,
+ consumes = MediaType.ALL_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ public @ResponseBody
+ List<TaskInstance> getAllTasksForCase(@PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ @RequestParam(value = "includeExecuted", required = false) final Boolean includeExecuted)
+ {
+ checkCaseExists(productIdentifier, caseIdentifier);
+
+ return taskInstanceService.findAllEntities(productIdentifier, caseIdentifier, includeExecuted);
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CASE_MANAGEMENT)
+ @RequestMapping(
+ value = "{taskidentifier}",
+ method = RequestMethod.GET,
+ consumes = MediaType.APPLICATION_JSON_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ public @ResponseBody
+ TaskInstance getTaskForCase(@PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ @PathVariable("taskidentifier") final String taskIdentifier)
+ {
+ checkCaseExists(productIdentifier, caseIdentifier);
+
+ return taskInstanceService.findByIdentifier(productIdentifier, caseIdentifier, taskIdentifier).orElseThrow(
+ () -> ServiceException.notFound("No task instance ''{0}.{1}.{2}'' found.", productIdentifier, caseIdentifier, taskIdentifier));
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CASE_MANAGEMENT)
+ @RequestMapping(
+ value = "{taskidentifier}",
+ method = RequestMethod.PUT,
+ consumes = MediaType.ALL_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ public @ResponseBody
+ ResponseEntity<Void> changeTaskForCase(@PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ @PathVariable("taskidentifier") final String taskIdentifier,
+ @RequestBody @Valid final TaskInstance instance)
+ {
+ checkCaseExists(productIdentifier, caseIdentifier);
+
+ checkTaskDefinitionExists(productIdentifier, taskIdentifier);
+
+ if (!taskIdentifier.equals(instance.getTaskIdentifier()))
+ throw ServiceException.badRequest("Instance identifiers may not be changed.");
+
+ commandGateway.process(new ChangeTaskInstanceCommand(productIdentifier, caseIdentifier, instance));
+
+ return ResponseEntity.accepted().build();
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CASE_MANAGEMENT)
+ @RequestMapping(
+ value = "{taskidentifier}/executed",
+ method = RequestMethod.PUT,
+ consumes = MediaType.ALL_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ public @ResponseBody
+ ResponseEntity<Void> markTaskExecution(@PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ @PathVariable("taskidentifier") final String taskIdentifier,
+ @RequestBody @Valid final Boolean executed)
+ {
+ checkTaskDefinitionExists(productIdentifier, taskIdentifier);
+
+ commandGateway.process(new ExecuteTaskInstanceCommand(productIdentifier, caseIdentifier, taskIdentifier, executed));
+
+ return ResponseEntity.accepted().build();
+ }
+
+ private void checkTaskDefinitionExists(final String productIdentifier,
+ final String taskDefinitionIdentifier) throws ServiceException {
+ taskDefinitionService.findByIdentifier(productIdentifier, taskDefinitionIdentifier)
+ .orElseThrow(() -> ServiceException.notFound("No task with the identifier ''{0}.{1}'' exists.", productIdentifier, taskDefinitionIdentifier));
+ }
+
+ private void checkCaseExists(final String productIdentifier, final String caseIdentifier) throws ServiceException {
+ caseService.findByIdentifier(productIdentifier, caseIdentifier)
+ .orElseThrow(() -> ServiceException.notFound("Case ''{0}.{2}'' does not exist.", productIdentifier, caseIdentifier));
+ }
+}
diff --git a/service/src/main/resources/db/migrations/mariadb/V3__task_instances.sql b/service/src/main/resources/db/migrations/mariadb/V3__task_instances.sql
new file mode 100644
index 0000000..961d820
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V3__task_instances.sql
@@ -0,0 +1,28 @@
+--
+-- Copyright 2017 The Mifos Initiative.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+CREATE TABLE bastet_c_task_insts (
+ id BIGINT NOT NULL AUTO_INCREMENT,
+ case_id BIGINT NOT NULL,
+ task_def_id BIGINT NOT NULL,
+ a_comment VARCHAR(4096) NOT NULL,
+ executed_on TIMESTAMP(3) NULL,
+ executed_by VARCHAR(32) NULL,
+ CONSTRAINT bastet_c_task_inst_pk PRIMARY KEY (id),
+ CONSTRAINT bastet_c_task_inst_uq UNIQUE (case_id, task_def_id),
+ CONSTRAINT bastet_c_task_inst_case_fk FOREIGN KEY (case_id) REFERENCES bastet_cases (id),
+ CONSTRAINT bastet_c_task_inst_def_fk FOREIGN KEY (task_def_id) REFERENCES bastet_p_task_defs (id)
+);
\ No newline at end of file
diff --git a/service/src/test/java/io/mifos/portfolio/service/internal/service/TaskDefinitionServiceTest.java b/service/src/test/java/io/mifos/portfolio/service/internal/service/TaskDefinitionServiceTest.java
index 7c83ccd..f7fb492 100644
--- a/service/src/test/java/io/mifos/portfolio/service/internal/service/TaskDefinitionServiceTest.java
+++ b/service/src/test/java/io/mifos/portfolio/service/internal/service/TaskDefinitionServiceTest.java
@@ -66,7 +66,7 @@
final List<TaskDefinitionEntity> taskDefinitionReturn = findTaskDefinition
? Collections.singletonList(exampleTaskDefinition()) : Collections.emptyList();
- Mockito.doReturn(taskDefinitionReturn).when(testHarness.getTaskDefinitionRepository()).findByProductId("ble");
+ Mockito.doReturn(taskDefinitionReturn.stream()).when(testHarness.getTaskDefinitionRepository()).findByProductId("ble");
final List<TaskDefinition> result = testHarness.getTestSubject().findAllEntities("ble");