This is an automated email from the ASF dual-hosted git repository. myrle pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract-cn-customer.git
commit 3771232db0ed19ec1b05a24fcce78f4270c4a1fa Author: mgeiss <[email protected]> AuthorDate: Thu Jun 29 18:07:15 2017 +0200 added process steps to fetch actions based on customer state --- .../customer/api/v1/client/CustomerManager.java | 12 ++++- .../io/mifos/customer/api/v1/domain/Command.java | 4 +- .../mifos/customer/api/v1/domain/ProcessStep.java | 31 +++++++++--- .../main/java/io/mifos/customer/TestCustomer.java | 45 +++++++++++++++++ .../repository/TaskInstanceRepository.java | 3 ++ .../service/internal/service/CustomerService.java | 59 +++++++++++++++++++++- .../rest/controller/CustomerRestController.java | 59 ++++++++++------------ 7 files changed, 170 insertions(+), 43 deletions(-) diff --git a/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java b/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java index 4634868..bac6bcb 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java +++ b/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java @@ -25,6 +25,7 @@ import io.mifos.customer.api.v1.domain.ContactDetail; import io.mifos.customer.api.v1.domain.IdentificationCard; import io.mifos.customer.api.v1.domain.Customer; import io.mifos.customer.api.v1.domain.CustomerPage; +import io.mifos.customer.api.v1.domain.ProcessStep; import io.mifos.customer.api.v1.domain.TaskDefinition; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.http.HttpStatus; @@ -144,7 +145,7 @@ public interface CustomerManager { ) @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TaskNotFoundException.class) List<TaskDefinition> findTasksForCustomer(@PathVariable("identifier") final String identifier, - @RequestParam(value = "includeExecuted", required = false) final Boolean includeExecuted); + @RequestParam(value = "includeExecuted", required = false) final Boolean includeExecuted); @RequestMapping( value = "/customers/{identifier}/address", @@ -302,4 +303,13 @@ public interface CustomerManager { @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TaskValidationException.class) }) void updateTask(@PathVariable("identifier") final String identifier, @RequestBody final TaskDefinition taskDefinition); + + @RequestMapping( + value = "/customer/{identifier}/actions", + method = RequestMethod.GET, + produces = MediaType.ALL_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE + ) + @ThrowsException(status = HttpStatus.NOT_FOUND, exception = CustomerNotFoundException.class) + List<ProcessStep> fetchProcessSteps(@PathVariable(value = "identifier") final String customerIdentifier); } diff --git a/api/src/main/java/io/mifos/customer/api/v1/domain/Command.java b/api/src/main/java/io/mifos/customer/api/v1/domain/Command.java index 82e2481..6981ee8 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/domain/Command.java +++ b/api/src/main/java/io/mifos/customer/api/v1/domain/Command.java @@ -15,7 +15,7 @@ */ package io.mifos.customer.api.v1.domain; -import org.hibernate.validator.constraints.NotBlank; +import javax.validation.constraints.NotNull; public final class Command { @@ -27,7 +27,7 @@ public final class Command { REOPEN } - @NotBlank + @NotNull private Action action; private String comment; private String createdOn; diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/TaskInstanceRepository.java b/api/src/main/java/io/mifos/customer/api/v1/domain/ProcessStep.java similarity index 53% copy from service/src/main/java/io/mifos/customer/service/internal/repository/TaskInstanceRepository.java copy to api/src/main/java/io/mifos/customer/api/v1/domain/ProcessStep.java index d8e45d2..622f41e 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/repository/TaskInstanceRepository.java +++ b/api/src/main/java/io/mifos/customer/api/v1/domain/ProcessStep.java @@ -13,15 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.mifos.customer.service.internal.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; +package io.mifos.customer.api.v1.domain; import java.util.List; -@Repository -public interface TaskInstanceRepository extends JpaRepository<TaskInstanceEntity, Long> { +public class ProcessStep { + + private Command command; + private List<TaskDefinition> taskDefinitions; + + public ProcessStep() { + super(); + } + + public Command getCommand() { + return this.command; + } + + public void setCommand(final Command command) { + this.command = command; + } + + public List<TaskDefinition> getTaskDefinitions() { + return this.taskDefinitions; + } - List<TaskInstanceEntity> findByCustomer(final CustomerEntity customer); + public void setTaskDefinitions(final List<TaskDefinition> taskDefinitions) { + this.taskDefinitions = taskDefinitions; + } } diff --git a/component-test/src/main/java/io/mifos/customer/TestCustomer.java b/component-test/src/main/java/io/mifos/customer/TestCustomer.java index 58ce486..83e0152 100644 --- a/component-test/src/main/java/io/mifos/customer/TestCustomer.java +++ b/component-test/src/main/java/io/mifos/customer/TestCustomer.java @@ -568,4 +568,49 @@ public class TestCustomer { this.customerManager.getPortrait(customer.getIdentifier()); } + + @Test + public void shouldReturnAvailableProcessSteps() throws Exception { + final Customer customer = CustomerGenerator.createRandomCustomer(); + + this.customerManager.createCustomer(customer); + + this.eventRecorder.wait(CustomerEventConstants.POST_CUSTOMER, customer.getIdentifier()); + + final List<ProcessStep> pendingProcessSteps = this.customerManager.fetchProcessSteps(customer.getIdentifier()); + Assert.assertEquals(2, pendingProcessSteps.size()); + Assert.assertEquals(Command.Action.ACTIVATE.name(), pendingProcessSteps.get(0).getCommand().getAction()); + Assert.assertEquals(Command.Action.CLOSE.name(), pendingProcessSteps.get(1).getCommand().getAction()); + + this.customerManager.customerCommand(customer.getIdentifier(), CommandGenerator.create(Command.Action.ACTIVATE, "Test")); + this.eventRecorder.wait(CustomerEventConstants.ACTIVATE_CUSTOMER, customer.getIdentifier()); + + final List<ProcessStep> activeProcessSteps = this.customerManager.fetchProcessSteps(customer.getIdentifier()); + Assert.assertEquals(2, activeProcessSteps.size()); + Assert.assertEquals(Command.Action.LOCK.name(), activeProcessSteps.get(0).getCommand().getAction()); + Assert.assertEquals(Command.Action.CLOSE.name(), activeProcessSteps.get(1).getCommand().getAction()); + + this.customerManager.customerCommand(customer.getIdentifier(), CommandGenerator.create(Command.Action.LOCK, "Test")); + this.eventRecorder.wait(CustomerEventConstants.LOCK_CUSTOMER, customer.getIdentifier()); + + final List<ProcessStep> lockedProcessSteps = this.customerManager.fetchProcessSteps(customer.getIdentifier()); + Assert.assertEquals(2, lockedProcessSteps.size()); + Assert.assertEquals(Command.Action.UNLOCK.name(), lockedProcessSteps.get(0).getCommand().getAction()); + Assert.assertEquals(Command.Action.CLOSE.name(), lockedProcessSteps.get(1).getCommand().getAction()); + + this.customerManager.customerCommand(customer.getIdentifier(), CommandGenerator.create(Command.Action.UNLOCK, "Test")); + this.eventRecorder.wait(CustomerEventConstants.UNLOCK_CUSTOMER, customer.getIdentifier()); + + final List<ProcessStep> unlockedProcessSteps = this.customerManager.fetchProcessSteps(customer.getIdentifier()); + Assert.assertEquals(2, unlockedProcessSteps.size()); + Assert.assertEquals(Command.Action.LOCK.name(), unlockedProcessSteps.get(0).getCommand().getAction()); + Assert.assertEquals(Command.Action.CLOSE.name(), unlockedProcessSteps.get(1).getCommand().getAction()); + + this.customerManager.customerCommand(customer.getIdentifier(), CommandGenerator.create(Command.Action.CLOSE, "Test")); + this.eventRecorder.wait(CustomerEventConstants.CLOSE_CUSTOMER, customer.getIdentifier()); + + final List<ProcessStep> closedProcessSteps = this.customerManager.fetchProcessSteps(customer.getIdentifier()); + Assert.assertEquals(1, closedProcessSteps.size()); + Assert.assertEquals(Command.Action.REOPEN.name(), closedProcessSteps.get(0).getCommand().getAction()); + } } diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/TaskInstanceRepository.java b/service/src/main/java/io/mifos/customer/service/internal/repository/TaskInstanceRepository.java index d8e45d2..2301f3a 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/repository/TaskInstanceRepository.java +++ b/service/src/main/java/io/mifos/customer/service/internal/repository/TaskInstanceRepository.java @@ -24,4 +24,7 @@ import java.util.List; public interface TaskInstanceRepository extends JpaRepository<TaskInstanceEntity, Long> { List<TaskInstanceEntity> findByCustomer(final CustomerEntity customer); + + List<TaskInstanceEntity> findByCustomerAndTaskDefinition(final CustomerEntity customer, + final TaskDefinitionEntity taskDefinitionEntity); } diff --git a/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java b/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java index 728af4b..5048a4c 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java +++ b/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java @@ -19,6 +19,8 @@ import io.mifos.customer.api.v1.domain.Command; import io.mifos.customer.api.v1.domain.Customer; import io.mifos.customer.api.v1.domain.CustomerPage; import io.mifos.customer.api.v1.domain.IdentificationCard; +import io.mifos.customer.api.v1.domain.ProcessStep; +import io.mifos.customer.api.v1.domain.TaskDefinition; import io.mifos.customer.catalog.api.v1.domain.Value; import io.mifos.customer.catalog.service.internal.repository.FieldEntity; import io.mifos.customer.catalog.service.internal.repository.FieldValueEntity; @@ -28,6 +30,7 @@ import io.mifos.customer.service.internal.mapper.CommandMapper; import io.mifos.customer.service.internal.mapper.ContactDetailMapper; import io.mifos.customer.service.internal.mapper.CustomerMapper; import io.mifos.customer.service.internal.mapper.IdentificationCardMapper; +import io.mifos.customer.service.internal.mapper.TaskDefinitionMapper; import io.mifos.customer.service.internal.repository.*; import io.mifos.customer.service.internal.mapper.AddressMapper; import org.slf4j.Logger; @@ -53,6 +56,8 @@ public class CustomerService { private final ContactDetailRepository contactDetailRepository; private final FieldValueRepository fieldValueRepository; private final CommandRepository commandRepository; + private final TaskDefinitionRepository taskDefinitionRepository; + private final TaskInstanceRepository taskInstanceRepository; @Autowired public CustomerService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger, @@ -61,7 +66,9 @@ public class CustomerService { final PortraitRepository portraitRepository, final ContactDetailRepository contactDetailRepository, final FieldValueRepository fieldValueRepository, - final CommandRepository commandRepository) { + final CommandRepository commandRepository, + final TaskDefinitionRepository taskDefinitionRepository, + final TaskInstanceRepository taskInstanceRepository) { super(); this.logger = logger; this.customerRepository = customerRepository; @@ -70,6 +77,8 @@ public class CustomerService { this.contactDetailRepository = contactDetailRepository; this.fieldValueRepository = fieldValueRepository; this.commandRepository = commandRepository; + this.taskDefinitionRepository = taskDefinitionRepository; + this.taskInstanceRepository = taskInstanceRepository; } public Boolean customerExists(final String identifier) { @@ -185,4 +194,52 @@ public class CustomerService { return identificationCardEntity.map(IdentificationCardMapper::map); } + + public List<ProcessStep> getProcessSteps(final String customerIdentifier) { + final ArrayList<ProcessStep> processSteps = new ArrayList<>(); + final CustomerEntity customerEntity = this.customerRepository.findByIdentifier(customerIdentifier); + + final Customer.State state = Customer.State.valueOf(customerEntity.getCurrentState()); + switch (state) { + case PENDING: + processSteps.add(this.buildProcessStep(customerEntity, Command.Action.ACTIVATE)); + processSteps.add(this.buildProcessStep(customerEntity, Command.Action.CLOSE)); + break; + case ACTIVE: + processSteps.add(this.buildProcessStep(customerEntity, Command.Action.LOCK)); + processSteps.add(this.buildProcessStep(customerEntity, Command.Action.CLOSE)); + break; + case LOCKED: + processSteps.add(this.buildProcessStep(customerEntity, Command.Action.UNLOCK)); + processSteps.add(this.buildProcessStep(customerEntity, Command.Action.CLOSE)); + break; + case CLOSED: + processSteps.add(this.buildProcessStep(customerEntity, Command.Action.REOPEN)); + break; + } + + return processSteps; + } + + private ProcessStep buildProcessStep(final CustomerEntity customerEntity, final Command.Action action) { + final ProcessStep processStep = new ProcessStep(); + + final Command command = new Command(); + command.setAction(action.name()); + processStep.setCommand(command); + + final ArrayList<TaskDefinition> taskDefinitions = new ArrayList<>(); + this.taskDefinitionRepository.findByAssignedCommandsContaining(action.name()) + .forEach(taskDefinitionEntity -> { + this.taskInstanceRepository.findByCustomerAndTaskDefinition(customerEntity, taskDefinitionEntity) + .forEach(taskInstanceEntity -> { + if (taskInstanceEntity.getExecutedBy() == null) { + taskDefinitions.add(TaskDefinitionMapper.map(taskDefinitionEntity)); + } + }); + }); + processStep.setTaskDefinitions(taskDefinitions); + + return processStep; + } } diff --git a/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java b/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java index 31a3959..41546b9 100644 --- a/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java +++ b/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java @@ -182,52 +182,34 @@ public class CustomerRestController { if (customerOptional.isPresent()) { final Customer customer = customerOptional.get(); final Command.Action action = Command.Action.valueOf(command.getAction()); + final String currentState = customer.getCurrentState(); switch (action) { case ACTIVATE: - if (!customer.getCurrentState().equals(Customer.State.PENDING.name())) { - throw ServiceException.badRequest( - "Customer {0} can not be activated, current state is {1}.", - identifier, - customer.getCurrentState()); + if (Customer.State.PENDING.name().equals(currentState)) { + this.commandGateway.process(new ActivateCustomerCommand(identifier, command.getComment())); } - this.commandGateway.process(new ActivateCustomerCommand(identifier, command.getComment())); break; case LOCK: - if (!customer.getCurrentState().equals(Customer.State.ACTIVE.name())) { - throw ServiceException.badRequest( - "Customer {0} can not be locked, current state is {1}.", - identifier, - customer.getCurrentState()); + if (Customer.State.ACTIVE.name().equals(currentState)) { + this.commandGateway.process(new LockCustomerCommand(identifier, command.getComment())); } - this.commandGateway.process(new LockCustomerCommand(identifier, command.getComment())); break; case UNLOCK: - if (!customer.getCurrentState().equals(Customer.State.LOCKED.name())) { - throw ServiceException.badRequest( - "Customer {0} can not be unlocked, current state is {1}.", - identifier, - customer.getCurrentState()); + if (Customer.State.LOCKED.name().equals(currentState)) { + this.commandGateway.process(new UnlockCustomerCommand(identifier, command.getComment())); } - this.commandGateway.process(new UnlockCustomerCommand(identifier, command.getComment())); break; case CLOSE: - if (!customer.getCurrentState().equals(Customer.State.ACTIVE.name()) - && !customer.getCurrentState().equals(Customer.State.LOCKED.name())) { - throw ServiceException.badRequest( - "Customer {0} can not be closed, current state is {1}.", - identifier, - customer.getCurrentState()); + if (Customer.State.ACTIVE.name().equals(currentState) + || Customer.State.LOCKED.name().equals(currentState) + || Customer.State.PENDING.name().equals(currentState)) { + this.commandGateway.process(new CloseCustomerCommand(identifier, command.getComment())); } - this.commandGateway.process(new CloseCustomerCommand(identifier, command.getComment())); break; case REOPEN: - if (!customer.getCurrentState().equals(Customer.State.CLOSED.name())) { - throw ServiceException.badRequest( - "Customer {0} can not be reopened, current state is {1}.", - identifier, - customer.getCurrentState()); + if (Customer.State.CLOSED.name().equals(currentState)) { + this.commandGateway.process(new ReopenCustomerCommand(identifier, command.getComment())); } - this.commandGateway.process(new ReopenCustomerCommand(identifier, command.getComment())); break; default: throw ServiceException.badRequest("Unsupported action {0}.", command.getAction()); @@ -607,6 +589,20 @@ public class CustomerRestController { return ResponseEntity.accepted().build(); } + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CUSTOMER) + @RequestMapping( + value = "/customer/{identifier}/actions", + method = RequestMethod.GET, + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.ALL_VALUE + ) + public + @ResponseBody + ResponseEntity<List<ProcessStep>> fetchProcessSteps(@PathVariable(value = "identifier") final String customerIdentifier) { + this.throwIfCustomerNotExists(customerIdentifier); + return ResponseEntity.ok(this.customerService.getProcessSteps(customerIdentifier)); + } + private Pageable createPageRequest(final Integer pageIndex, final Integer size, final String sortColumn, final String sortDirection) { final Integer pageIndexToUse = pageIndex != null ? pageIndex : 0; final Integer sizeToUse = size != null ? size : 20; @@ -632,5 +628,4 @@ public class CustomerRestController { throw ServiceException.notFound("Identification card {0} not found.", number); } } - } -- To stop receiving notification emails like this one, please contact [email protected].
