diff --git a/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java b/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java index 0339cee1b98..f3104b54345 100644 --- a/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java +++ b/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java @@ -52,7 +52,6 @@ import org.apache.fineract.batch.exception.ErrorInfo; import org.apache.fineract.batch.service.ResolutionHelper.BatchRequestNode; import org.apache.fineract.infrastructure.core.domain.BatchRequestContextHolder; -import org.apache.fineract.infrastructure.core.exception.AbstractIdempotentCommandException; import org.apache.fineract.infrastructure.core.exception.ErrorHandler; import org.apache.fineract.infrastructure.core.filters.BatchCallHandler; import org.apache.fineract.infrastructure.core.filters.BatchFilter; @@ -62,10 +61,8 @@ import org.springframework.dao.NonTransientDataAccessException; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionExecution; -import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionSystemException; import org.springframework.transaction.support.TransactionTemplate; @@ -104,8 +101,7 @@ public class BatchApiServiceImpl implements BatchApiService { */ @Override public List handleBatchRequestsWithoutEnclosingTransaction(final List requestList, UriInfo uriInfo) { - BatchRequestContextHolder.setEnclosingTransaction(Optional.empty()); - return handleBatchRequests(false, requestList, uriInfo); + return handleBatchRequests(requestList, uriInfo, false); } /** @@ -117,7 +113,18 @@ public List handleBatchRequestsWithoutEnclosingTransaction(final */ @Override public List handleBatchRequestsWithEnclosingTransaction(final List requestList, final UriInfo uriInfo) { - return callInTransaction(Function.identity()::apply, () -> handleBatchRequests(true, requestList, uriInfo)); + return handleBatchRequests(requestList, uriInfo, true); + } + + private List handleBatchRequests(final List requestList, final UriInfo uriInfo, + boolean enclosingTransaction) { + BatchRequestContextHolder.setIsEnclosingTransaction(enclosingTransaction); + try { + return enclosingTransaction ? callInTransaction(Function.identity()::apply, () -> handleRequestNodes(requestList, uriInfo)) + : handleRequestNodes(requestList, uriInfo); + } finally { + BatchRequestContextHolder.resetIsEnclosingTransaction(); + } } /** @@ -136,18 +143,15 @@ private List callInTransaction(Consumer tran TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); transactionConfigurator.accept(transactionTemplate); return transactionTemplate.execute(status -> { - BatchRequestContextHolder.setEnclosingTransaction(Optional.of(status)); + BatchRequestContextHolder.setEnclosingTransaction(status); try { responseList.addAll(request.get()); return responseList; } catch (BatchExecutionException ex) { - status.setRollbackOnly(); - return List.of(buildErrorResponse(ex.getCause(), ex.getRequest())); - } catch (RuntimeException ex) { - status.setRollbackOnly(); - return buildErrorResponses(ex, responseList); + responseList.add(buildErrorResponse(ex.getCause(), ex.getRequest())); + return responseList; } finally { - BatchRequestContextHolder.setEnclosingTransaction(Optional.empty()); + BatchRequestContextHolder.resetTransaction(); } }); } catch (TransactionException | NonTransientDataAccessException ex) { @@ -163,24 +167,17 @@ private List callInTransaction(Consumer tran * @param uriInfo * @return {@code List} */ - private List handleBatchRequests(boolean enclosingTransaction, final List requestList, - final UriInfo uriInfo) { + private List handleRequestNodes(final List requestList, final UriInfo uriInfo) { final List rootNodes; try { rootNodes = this.resolutionHelper.buildNodesTree(requestList); } catch (BatchReferenceInvalidException e) { - return List.of(buildErrorResponse(e)); + return List.of(buildOrThrowErrorResponse(e, null)); } final ArrayList responseList = new ArrayList<>(requestList.size()); for (BatchRequestNode rootNode : rootNodes) { - if (enclosingTransaction) { - this.callRequestRecursive(rootNode.getRequest(), rootNode, responseList, uriInfo, enclosingTransaction); - } else { - ArrayList localResponseList = new ArrayList<>(); - this.callRequestRecursive(rootNode.getRequest(), rootNode, localResponseList, uriInfo, enclosingTransaction); - responseList.addAll(localResponseList); - } + this.callRequestRecursive(rootNode.getRequest(), rootNode, responseList, uriInfo); } responseList.sort(Comparator.comparing(BatchResponse::getRequestId)); return responseList; @@ -197,18 +194,10 @@ private List handleBatchRequests(boolean enclosingTransaction, fi * the collected responses * @return {@code BatchResponse} */ - private void callRequestRecursive(BatchRequest request, BatchRequestNode requestNode, List responseList, UriInfo uriInfo, - boolean enclosingTransaction) { + private void callRequestRecursive(BatchRequest request, BatchRequestNode requestNode, List responseList, + UriInfo uriInfo) { // run current node - BatchResponse response; - if (enclosingTransaction) { - response = executeRequest(request, uriInfo); - } else { - List transactionResponse = callInTransaction( - transactionTemplate -> transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW), - () -> List.of(executeRequest(request, uriInfo))); - response = transactionResponse.get(0); - } + BatchResponse response = executeRequest(request, uriInfo); responseList.add(response); if (response.getStatusCode() != null && response.getStatusCode() == SC_OK) { // run child nodes @@ -217,13 +206,10 @@ private void callRequestRecursive(BatchRequest request, BatchRequestNode request BatchRequest resolvedChildRequest; try { resolvedChildRequest = this.resolutionHelper.resolveRequest(childRequest, response); + callRequestRecursive(resolvedChildRequest, childNode, responseList, uriInfo); } catch (JsonPathException jpex) { - responseList.add(buildErrorResponse(jpex, childRequest)); - return; - } catch (RuntimeException ex) { - throw new BatchExecutionException(childRequest, ex); + responseList.add(buildOrThrowErrorResponse(jpex, childRequest)); } - callRequestRecursive(resolvedChildRequest, childNode, responseList, uriInfo, enclosingTransaction); }); } else { responseList.addAll(parentRequestFailedRecursive(request, requestNode, response, null)); @@ -245,7 +231,7 @@ private BatchResponse executeRequest(BatchRequest request, UriInfo uriInfo) { log.debug("Batch request: method [{}], relative url [{}]", request.getMethod(), request.getRelativeUrl()); Either preprocessorResult = runPreprocessors(request); if (preprocessorResult.isLeft()) { - throw new BatchExecutionException(request, preprocessorResult.getLeft()); + return buildOrThrowErrorResponse(preprocessorResult.getLeft(), request); } else { request = preprocessorResult.get(); } @@ -253,19 +239,16 @@ private BatchResponse executeRequest(BatchRequest request, UriInfo uriInfo) { BatchRequestContextHolder.setRequestAttributes(new HashMap<>(Optional.ofNullable(request.getHeaders()) .map(list -> list.stream().collect(Collectors.toMap(Header::getName, Header::getValue))) .orElse(Collections.emptyMap()))); - BatchCallHandler callHandler = new BatchCallHandler(this.batchFilters, commandStrategy::execute); - Optional transaction = BatchRequestContextHolder.getEnclosingTransaction(); - if (transaction.isPresent()) { + if (BatchRequestContextHolder.isEnclosingTransaction()) { entityManager.flush(); } + BatchCallHandler callHandler = new BatchCallHandler(this.batchFilters, commandStrategy::execute); final BatchResponse rootResponse = callHandler.serviceCall(request, uriInfo); log.debug("Batch response: status code [{}], method [{}], relative url [{}]", rootResponse.getStatusCode(), request.getMethod(), request.getRelativeUrl()); return rootResponse; - } catch (AbstractIdempotentCommandException idempotentException) { - return buildErrorResponse(idempotentException, request); } catch (RuntimeException ex) { - throw new BatchExecutionException(request, ex); + return buildOrThrowErrorResponse(ex, request); } finally { BatchRequestContextHolder.resetRequestAttributes(); } @@ -313,11 +296,6 @@ private List parentRequestFailedRecursive(@NotNull BatchRequest r return responseList; } - @NotNull - private BatchResponse buildErrorResponse(@NotNull Throwable ex) { - return buildErrorResponse(ex, null); - } - /** * Return the response when any exception raised * @@ -346,6 +324,15 @@ private BatchResponse buildErrorResponse(Throwable ex, BatchRequest request) { return buildErrorResponse(requestId, statusCode, body, headers); } + private BatchResponse buildOrThrowErrorResponse(RuntimeException ex, BatchRequest request) { + BatchResponse response = buildErrorResponse(ex, request); + if (response.getStatusCode() != SC_OK && BatchRequestContextHolder.isEnclosingTransaction()) { + BatchRequestContextHolder.getTransaction().ifPresent(TransactionExecution::setRollbackOnly); + throw new BatchExecutionException(request, ex); + } + return response; + } + @NotNull private List buildErrorResponses(Throwable ex, @NotNull List responseList) { BatchResponse response = responseList.isEmpty() ? null @@ -368,9 +355,10 @@ private List buildErrorResponses(Throwable ex, @NotNull List new CommandNotFoundException(jsonCommand.commandId())); - commandSourceResult.markAsChecked(maker); - } else { - commandSourceResult = CommandSource.fullEntryFrom(wrapper, jsonCommand, maker, idempotencyKey, UNDER_PROCESSING.getValue()); - } + CommandSource commandSourceResult = CommandSource.fullEntryFrom(wrapper, jsonCommand, maker, idempotencyKey, + UNDER_PROCESSING.getValue()); if (commandSourceResult.getCommandJson() == null) { commandSourceResult.setCommandJson("{}"); } return commandSourceResult; } + + @Transactional + public CommandProcessingResult processCommand(NewCommandSourceHandler handler, JsonCommand command, CommandSource commandSource, + AppUser user, boolean isApprovedByChecker, boolean isMakerChecker) { + final CommandProcessingResult result = handler.processCommand(command); + boolean isRollback = !isApprovedByChecker && !user.isCheckerSuperUser() && (isMakerChecker || result.isRollbackTransaction()); + if (isRollback) { + commandSource.markAsAwaitingApproval(); + throw new RollbackTransactionNotApprovedException(commandSource.getId(), commandSource.getResourceId()); + } + return result; + } } diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java index 225c25f88a1..fcd17c3f679 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java @@ -19,6 +19,7 @@ package org.apache.fineract.commands.service; import com.google.gson.JsonElement; +import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.commands.domain.CommandSource; @@ -26,6 +27,8 @@ import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.exception.CommandNotAwaitingApprovalException; import org.apache.fineract.commands.exception.CommandNotFoundException; +import org.apache.fineract.commands.exception.UnsupportedCommandException; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; @@ -45,10 +48,10 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio private final FromJsonHelper fromApiJsonHelper; private final CommandProcessingService processAndLogCommandService; private final SchedulerJobRunnerReadService schedulerJobRunnerReadService; + private final ConfigurationDomainService configurationService; @Override public CommandProcessingResult logCommandSource(final CommandWrapper wrapper) { - boolean isApprovedByChecker = false; // check if is update of own account details @@ -77,7 +80,6 @@ public CommandProcessingResult logCommandSource(final CommandWrapper wrapper) { @Override public CommandProcessingResult approveEntry(final Long makerCheckerId) { - final CommandSource commandSourceInput = validateMakerCheckerTransaction(makerCheckerId); validateIsUpdateAllowed(); @@ -111,16 +113,24 @@ public Long deleteEntry(final Long makerCheckerId) { } private CommandSource validateMakerCheckerTransaction(final Long makerCheckerId) { - - final CommandSource commandSourceInput = this.commandSourceRepository.findById(makerCheckerId) + final CommandSource commandSource = this.commandSourceRepository.findById(makerCheckerId) .orElseThrow(() -> new CommandNotFoundException(makerCheckerId)); - if (!commandSourceInput.isMarkedAsAwaitingApproval()) { + if (!commandSource.isMarkedAsAwaitingApproval()) { throw new CommandNotAwaitingApprovalException(makerCheckerId); } - - this.context.authenticatedUser().validateHasCheckerPermissionTo(commandSourceInput.getPermissionCode()); - - return commandSourceInput; + AppUser appUser = this.context.authenticatedUser(); + String permissionCode = commandSource.getPermissionCode(); + appUser.validateHasCheckerPermissionTo(permissionCode); + if (!configurationService.isSameMakerCheckerEnabled() && !appUser.isCheckerSuperUser()) { + AppUser maker = commandSource.getMaker(); + if (maker == null) { + throw new UnsupportedCommandException(permissionCode, "Maker user is missing."); + } + if (Objects.equals(appUser.getId(), maker.getId())) { + throw new UnsupportedCommandException(permissionCode, "Can not be checked by the same user."); + } + } + return commandSource; } private void validateIsUpdateAllowed() { diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java index b0ac361718c..6b3a6ae8839 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java @@ -35,14 +35,12 @@ import org.apache.fineract.commands.domain.CommandProcessingResultType; import org.apache.fineract.commands.domain.CommandSource; import org.apache.fineract.commands.domain.CommandWrapper; -import org.apache.fineract.commands.exception.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.apache.fineract.commands.exception.UnsupportedCommandException; import org.apache.fineract.commands.handler.NewCommandSourceHandler; import org.apache.fineract.commands.provider.CommandHandlerProvider; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.domain.BatchRequestContextHolder; import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder; import org.apache.fineract.infrastructure.core.exception.ErrorHandler; @@ -58,7 +56,6 @@ import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; @Service @Slf4j @@ -76,9 +73,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer private final ConfigurationDomainService configurationDomainService; private final CommandHandlerProvider commandHandlerProvider; private final IdempotencyKeyResolver idempotencyKeyResolver; - private final IdempotencyKeyGenerator idempotencyKeyGenerator; private final CommandSourceService commandSourceService; - private final ErrorHandler errorHandler; private final FineractRequestContextHolder fineractRequestContextHolder; private final Gson gson = GoogleGsonSerializerHelper.createSimpleGson(); @@ -92,73 +87,68 @@ public CommandProcessingResult executeCommand(final CommandWrapper wrapper, fina Long commandId = (Long) fineractRequestContextHolder.getAttribute(COMMAND_SOURCE_ID, null); boolean isRetry = commandId != null; + boolean isEnclosingTransaction = BatchRequestContextHolder.isEnclosingTransaction(); CommandSource commandSource = null; String idempotencyKey; if (isRetry) { commandSource = commandSourceService.getCommandSource(commandId); idempotencyKey = commandSource.getIdempotencyKey(); + } else if ((commandId = command.commandId()) != null) { // action on the command itself + commandSource = commandSourceService.getCommandSource(commandId); + idempotencyKey = commandSource.getIdempotencyKey(); } else { idempotencyKey = idempotencyKeyResolver.resolve(wrapper); } exceptionWhenTheRequestAlreadyProcessed(wrapper, idempotencyKey, isRetry); - boolean sameTransaction = BatchRequestContextHolder.getEnclosingTransaction().isPresent(); + AppUser user = context.authenticatedUser(wrapper); if (commandSource == null) { - AppUser user = context.authenticatedUser(wrapper); - if (sameTransaction) { + if (isEnclosingTransaction) { commandSource = commandSourceService.getInitialCommandSource(wrapper, command, user, idempotencyKey); } else { commandSource = commandSourceService.saveInitialNewTransaction(wrapper, command, user, idempotencyKey); - storeCommandIdInContext(commandSource); // Store command id as a request attribute + commandId = commandSource.getId(); } } + if (commandId != null) { + storeCommandIdInContext(commandSource); // Store command id as a request attribute + } + + boolean isMakerChecker = configurationDomainService.isMakerCheckerEnabledForTask(wrapper.taskPermissionName()); + if (isApprovedByChecker || (isMakerChecker && user.isCheckerSuperUser())) { + commandSource.markAsChecked(user); + } setIdempotencyKeyStoreFlag(true); final CommandProcessingResult result; try { - result = findCommandHandler(wrapper).processCommand(command); + result = commandSourceService.processCommand(findCommandHandler(wrapper), command, commandSource, user, isApprovedByChecker, + isMakerChecker); } catch (Throwable t) { // NOSONAR RuntimeException mappable = ErrorHandler.getMappable(t); ErrorInfo errorInfo = commandSourceService.generateErrorInfo(mappable); - commandSource.setResultStatusCode(errorInfo.getStatusCode()); + Integer statusCode = errorInfo.getStatusCode(); + commandSource.setResultStatusCode(statusCode); commandSource.setResult(errorInfo.getMessage()); - commandSource.setStatus(ERROR); - if (!sameTransaction) { // TODO: temporary solution + if (statusCode != SC_OK) { + commandSource.setStatus(ERROR); + } + if (!isEnclosingTransaction) { // TODO: temporary solution commandSource = commandSourceService.saveResultNewTransaction(commandSource); } - publishHookErrorEvent(wrapper, command, errorInfo); // TODO must be performed in a new transaction + // must not throw any exception; must persist in new transaction as the current transaction was already + // marked as rollback + publishHookErrorEvent(wrapper, command, errorInfo); throw mappable; } - commandSource.updateForAudit(result); commandSource.setResultStatusCode(SC_OK); + commandSource.updateForAudit(result); commandSource.setResult(toApiJsonSerializer.serializeResult(result)); commandSource.setStatus(PROCESSED); - - boolean isRollback = !isApprovedByChecker && (result.isRollbackTransaction() - || configurationDomainService.isMakerCheckerEnabledForTask(wrapper.taskPermissionName())); - // TODO: this should be removed, can not override audit information (and maker-checker does not work) - if (!isRollback && result.hasChanges()) { - commandSource.setCommandJson(toApiJsonSerializer.serializeResult(result.getChanges())); - } - commandSource = commandSourceService.saveResultSameTransaction(commandSource); - if (sameTransaction) { - storeCommandIdInContext(commandSource); // Store command id as a request attribute - } - - if (isRollback) { - /* - * JournalEntry will generate a new transactionId every time. Updating the transactionId with old - * transactionId, because as there are no entries are created with new transactionId, will throw an error - * when checker approves the transaction - */ - commandSource.setTransactionId(command.getTransactionId()); - // TODO: this should be removed together with lines 147-149 - commandSource.setCommandJson(command.json()); // Set back CommandSource json data - throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(commandSource); - } + storeCommandIdInContext(commandSource); // Store command id as a request attribute result.setRollbackTransaction(null); publishHookEvent(wrapper.entityName(), wrapper.actionName(), command, result); // TODO must be performed in a @@ -201,24 +191,8 @@ private void setIdempotencyKeyStoreFlag(boolean flag) { fineractRequestContextHolder.setAttribute(IDEMPOTENCY_KEY_STORE_FLAG, flag); } - @Transactional - @Override - public CommandProcessingResult logCommand(CommandSource commandSource) { - commandSource.markAsAwaitingApproval(); - if (commandSource.getIdempotencyKey() == null) { - commandSource.setIdempotencyKey(idempotencyKeyGenerator.create()); - } - commandSource = commandSourceService.saveResultSameTransaction(commandSource); - - return new CommandProcessingResultBuilder().withCommandId(commandSource.getId()).withEntityId(commandSource.getResourceId()) - .build(); - } - @SuppressWarnings("unused") public CommandProcessingResult fallbackExecuteCommand(Exception e) { - if (e instanceof RollbackTransactionAsCommandIsNotApprovedByCheckerException ex) { - return logCommand(ex.getCommandSourceResult()); - } throw ErrorHandler.getMappable(e); } @@ -281,10 +255,10 @@ private NewCommandSourceHandler findCommandHandler(final CommandWrapper wrapper) } @Override - public boolean validateCommand(final CommandWrapper commandWrapper, final AppUser user) { - boolean rollbackTransaction = configurationDomainService.isMakerCheckerEnabledForTask(commandWrapper.taskPermissionName()); + public boolean validateRollbackCommand(final CommandWrapper commandWrapper, final AppUser user) { user.validateHasPermissionTo(commandWrapper.getTaskPermissionName()); - return rollbackTransaction; + boolean isMakerChecker = configurationDomainService.isMakerCheckerEnabledForTask(commandWrapper.taskPermissionName()); + return isMakerChecker && !user.isCheckerSuperUser(); } private void publishHookEvent(final String entityName, final String actionName, JsonCommand command, final Object result) { diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java index 06969ef9a7a..d2bf2c2b94f 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java @@ -25,6 +25,8 @@ public interface ConfigurationDomainService { boolean isMakerCheckerEnabledForTask(String taskPermissionCode); + boolean isSameMakerCheckerEnabled(); + boolean isAmazonS3Enabled(); boolean isRescheduleFutureRepaymentsEnabled(); diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/BatchRequestContextHolder.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/BatchRequestContextHolder.java index 3776fb3de37..59202329358 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/BatchRequestContextHolder.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/BatchRequestContextHolder.java @@ -27,15 +27,16 @@ public final class BatchRequestContextHolder { private BatchRequestContextHolder() {} - private static final ThreadLocal> batchAttributes = new NamedThreadLocal<>("BatchAttributesForProcessing"); + private static final ThreadLocal> batchAttributes = new NamedThreadLocal<>("batchAttributes"); - private static final ThreadLocal> enclosingTransaction = new NamedThreadLocal<>("EnclosingTransaction") { + private static final ThreadLocal> batchTransaction = new NamedThreadLocal<>("batchTransaction") { @Override protected Optional initialValue() { return Optional.empty(); } }; + private static final ThreadLocal isEnclosingTransaction = new NamedThreadLocal<>("isEnclosingTransaction"); /** * True if the batch attributes are set @@ -47,12 +48,12 @@ public static boolean isBatchRequest() { } /** - * True if the batch attributes are set and the enclosing transaction is set to true + * Returns the batch attributes for the current thread. * - * @return + * @return the batch attributes for the current thread, cna be null */ - public static Optional getEnclosingTransaction() { - return enclosingTransaction.get(); + public static Map getRequestAttributes() { + return batchAttributes.get(); } /** @@ -66,27 +67,73 @@ public static void setRequestAttributes(Map requestAttributes) { } /** - * Returns the batch attributes for the current thread. + * Reset the batch attributes for the current thread. + */ + public static void resetRequestAttributes() { + batchAttributes.remove(); + } + + /** + * True if the batch attributes are set and the enclosing transaction is set to true * - * @return the batch attributes for the current thread, cna be null + * @return */ - public static Map getRequestAttributes() { - return batchAttributes.get(); + public static boolean isEnclosingTransaction() { + return Boolean.TRUE.equals(isEnclosingTransaction.get()); } /** - * Reset the batch attributes for the current thread. + * Set the isEnclosingTransaction flag for the current thread. + * + * @param isEnclosingTransaction */ - public static void resetRequestAttributes() { - batchAttributes.remove(); + public static void setIsEnclosingTransaction(boolean isEnclosingTransaction) { + BatchRequestContextHolder.isEnclosingTransaction.set(isEnclosingTransaction); + } + + public static void resetIsEnclosingTransaction() { + isEnclosingTransaction.remove(); + } + + /** + * Return the transaction + * + * @return + */ + public static Optional getTransaction() { + return batchTransaction.get(); + } + + /** + * Return the enclosing transaction + * + * @return + */ + public static Optional getEnclosingTransaction() { + return isEnclosingTransaction() ? getTransaction() : Optional.empty(); + } + + /** + * Set the transaction for the current thread. + * + * @param enclosingTransaction + */ + public static void setTransaction(TransactionStatus enclosingTransaction) { + batchTransaction.set(Optional.ofNullable(enclosingTransaction)); } /** - * Set the enclosing transaction flag for the current thread. + * Set the enclosing transaction for the current thread. * * @param enclosingTransaction */ - public static void setEnclosingTransaction(Optional enclosingTransaction) { - BatchRequestContextHolder.enclosingTransaction.set(enclosingTransaction); + public static void setEnclosingTransaction(TransactionStatus enclosingTransaction) { + if (isEnclosingTransaction()) { + setTransaction(enclosingTransaction); + } + } + + public static void resetTransaction() { + batchTransaction.set(Optional.empty()); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/RollbackTransactionNotApprovedExceptionMapper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/RollbackTransactionNotApprovedExceptionMapper.java new file mode 100644 index 00000000000..dfa2d3da862 --- /dev/null +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/RollbackTransactionNotApprovedExceptionMapper.java @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.fineract.infrastructure.core.exceptionmapper; + +import com.google.gson.Gson; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.commands.exception.RollbackTransactionNotApprovedException; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * An {@link ExceptionMapper} to map {@link PlatformApiDataValidationException} thrown by platform into a HTTP API + * friendly format. + * + * The {@link PlatformApiDataValidationException} is typically thrown in data validation of the parameters passed in + * with an api request. + */ +@Provider +@Component +@Scope("singleton") +@Slf4j +public class RollbackTransactionNotApprovedExceptionMapper + implements FineractExceptionMapper, ExceptionMapper { + + @Override + public Response toResponse(final RollbackTransactionNotApprovedException exception) { + log.warn("Exception: {}", exception.getClass().getName()); + return Response.ok().entity(new Gson().toJson(exception.getResult())).type(MediaType.APPLICATION_JSON).build(); + } + + @Override + public int errorCode() { + return 2000; + } +} diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/UnsupportedCommandExceptionMapper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/UnsupportedCommandExceptionMapper.java index 9743e64d044..39021b96cc6 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/UnsupportedCommandExceptionMapper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/UnsupportedCommandExceptionMapper.java @@ -47,8 +47,12 @@ public Response toResponse(final UnsupportedCommandException exception) { final List errors = new ArrayList<>(); final StringBuilder validationErrorCode = new StringBuilder("error.msg.command.unsupported"); + String message = exception.getMessage(); final StringBuilder defaultEnglishMessage = new StringBuilder("The command ").append(exception.getUnsupportedCommandName()) .append(" is not supported."); + if (message != null) { + defaultEnglishMessage.append(" ").append(message); + } log.warn("Exception: {}, Message: {}", exception.getClass().getName(), defaultEnglishMessage); final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), exception.getUnsupportedCommandName(), exception.getUnsupportedCommandName()); diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/filters/IdempotencyStoreHelper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/filters/IdempotencyStoreHelper.java index f2670fec4f0..c014ab73430 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/filters/IdempotencyStoreHelper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/filters/IdempotencyStoreHelper.java @@ -25,7 +25,6 @@ import org.apache.fineract.commands.domain.CommandSourceRepository; import org.apache.fineract.commands.service.CommandSourceService; import org.apache.fineract.commands.service.SynchronousCommandProcessingService; -import org.apache.fineract.infrastructure.core.domain.BatchRequestContextHolder; import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder; import org.springframework.stereotype.Component; @@ -39,11 +38,9 @@ public class IdempotencyStoreHelper { public void storeCommandResult(Integer response, String body, Long commandId) { commandSourceRepository.findById(commandId).ifPresent(commandSource -> { - boolean sameTransaction = BatchRequestContextHolder.getEnclosingTransaction().isPresent(); commandSource.setResultStatusCode(response); commandSource.setResult(body); - commandSource = sameTransaction ? commandSourceService.saveResultSameTransaction(commandSource) - : commandSourceService.saveResultNewTransaction(commandSource); + commandSourceService.saveResultSameTransaction(commandSource); }); } diff --git a/fineract-core/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java b/fineract-core/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java index db2972cfbb6..cce8954dead 100644 --- a/fineract-core/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java +++ b/fineract-core/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java @@ -657,6 +657,10 @@ public void validateHasCheckerPermissionTo(final String function) { } } + public boolean isCheckerSuperUser() { + return hasPermissionTo("CHECKER_SUPER_USER"); + } + public void validateHasDatatableReadPermission(final String datatable) { if (hasNotPermissionForDatatable(datatable, "READ")) { throw new NoAuthorizationException("Not authorised to read datatable: " + datatable); diff --git a/fineract-core/src/test/java/org/apache/fineract/infrastructure/core/exception/IdempotencyCommandProcessFailedExceptionTest.java b/fineract-core/src/test/java/org/apache/fineract/infrastructure/core/exception/IdempotencyCommandProcessFailedExceptionTest.java index 91e4095a16c..04ba9aa541f 100644 --- a/fineract-core/src/test/java/org/apache/fineract/infrastructure/core/exception/IdempotencyCommandProcessFailedExceptionTest.java +++ b/fineract-core/src/test/java/org/apache/fineract/infrastructure/core/exception/IdempotencyCommandProcessFailedExceptionTest.java @@ -34,6 +34,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.exceptionmapper.IdempotentCommandExceptionMapper; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -48,6 +49,11 @@ public void setUp() { ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, actualDate))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void testInconsistentStatus() { IdempotentCommandExceptionMapper mapper = new IdempotentCommandExceptionMapper(); diff --git a/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java b/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java index bd1eab0fc16..8286eed6f22 100644 --- a/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java +++ b/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java @@ -54,6 +54,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary; import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -90,6 +91,11 @@ public void setUp() { externalAssetOwnerTransferLoanMappingRepository, accountingService, businessEventNotifierService); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void givenLoanNoTransfer() { // given diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/savings/SavingsImportHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/savings/SavingsImportHandler.java index d375ad3dabb..42d16b395e1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/savings/SavingsImportHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/savings/SavingsImportHandler.java @@ -38,6 +38,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; +import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType; import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData; import org.apache.fineract.portfolio.savings.data.SavingsAccountData; import org.apache.fineract.portfolio.savings.data.SavingsActivation; @@ -147,7 +148,9 @@ private SavingsAccountData readSavings(final Workbook workbook, final Row row, f Long interestPostingPeriodTypeId = null; EnumOptionData interestPostingPeriodTypeEnum = null; if (interestPostingPeriodType != null) { - if (interestPostingPeriodType.equalsIgnoreCase(MONTHLY)) { + if (interestPostingPeriodType.equalsIgnoreCase(DAILY)) { + interestPostingPeriodTypeId = SavingsPostingInterestPeriodType.DAILY.getValue().longValue(); + } else if (interestPostingPeriodType.equalsIgnoreCase(MONTHLY)) { interestPostingPeriodTypeId = 4L; } else if (interestPostingPeriodType.equalsIgnoreCase(QUARTERLY)) { interestPostingPeriodTypeId = 5L; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java index b176a2a415e..3cb8a4b6b8f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.configuration.domain; +import jakarta.validation.constraints.NotNull; import java.time.LocalDate; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -74,6 +75,11 @@ public boolean isMakerCheckerEnabledForTask(final String taskPermissionCode) { return false; } + @Override + public boolean isSameMakerCheckerEnabled() { + return getGlobalConfigurationPropertyData("enable-same-maker-checker").isEnabled(); + } + @Override public boolean isAmazonS3Enabled() { return getGlobalConfigurationPropertyData("amazon-S3").isEnabled(); @@ -379,18 +385,14 @@ public Long retrieveRelaxingDaysConfigForPivotDate() { return property.getValue(); } + @NotNull private GlobalConfigurationPropertyData getGlobalConfigurationPropertyData(final String propertyName) { return globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName).toData(); } @Override public boolean isSubRatesEnabled() { - GlobalConfigurationPropertyData configuration = getGlobalConfigurationPropertyData("sub-rates"); - if (configuration == null) { - return false; - } else { - return configuration.isEnabled(); - } + return getGlobalConfigurationPropertyData("sub-rates").isEnabled(); } @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 6bfdf307975..9cb152acf72 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -294,7 +294,7 @@ public CommandProcessingResult createClient(final JsonCommand command) { validateParentGroupRulesBeforeClientActivation(newClient); runEntityDatatableCheck(newClient.getId(), newClient.getLegalForm()); final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateClient(null).build(); - rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser); + rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser); } this.clientRepository.saveAndFlush(newClient); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java index 22f9db63f11..646108a989d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java @@ -172,16 +172,16 @@ private CommandProcessingResult createGroupingType(final JsonCommand command, fi if (newGroup.isCenter()) { final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateCenter(null).build(); - rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser); + rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser); } else { final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateGroup(null).build(); - rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser); + rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser); } } if (!newGroup.isCenter() && newGroup.hasActiveClients()) { final CommandWrapper commandWrapper = new CommandWrapperBuilder().associateClientsToGroup(newGroup.getId()).build(); - rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser); + rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser); } // pre-save to generate id for use in group hierarchy diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java index 57464a89489..e9c4fa0c2a4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java @@ -656,7 +656,8 @@ private void checkClientOrGroupActive(final SavingsAccount account) { public CommandProcessingResult createActiveApplication(final SavingsAccountDataDTO savingsAccountDataDTO) { final CommandWrapper commandWrapper = new CommandWrapperBuilder().savingsAccountActivation(null).build(); - boolean rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, savingsAccountDataDTO.getAppliedBy()); + boolean rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, + savingsAccountDataDTO.getAppliedBy()); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsAccountDataDTO.getClient(), savingsAccountDataDTO.getGroup(), savingsAccountDataDTO.getSavingsProduct(), savingsAccountDataDTO.getApplicationDate(), diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index b71677198a7..1c67c77181f 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -150,4 +150,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0131_add_configuration_maker_checker.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0131_add_configuration_maker_checker.xml new file mode 100644 index 00000000000..a400511b8b5 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0131_add_configuration_maker_checker.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/listener/LoanItemListenerStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/listener/LoanItemListenerStepDefinitions.java index e3f4ca94ad5..6899a21e529 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/listener/LoanItemListenerStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/listener/LoanItemListenerStepDefinitions.java @@ -66,7 +66,11 @@ public LoanItemListenerStepDefinitions() { }); When("LoanItemListener.onReadError method executed", () -> { - loanItemListener.onReadError(exception); + try { + loanItemListener.onReadError(exception); + } finally { + ThreadLocalContextUtil.reset(); + } }); Then("LoanItemListener.onReadError result should match", () -> { @@ -87,7 +91,11 @@ public LoanItemListenerStepDefinitions() { }); When("LoanItemListener.onProcessError method executed", () -> { - loanItemListener.onProcessError(loan, exception); + try { + loanItemListener.onProcessError(loan, exception); + } finally { + ThreadLocalContextUtil.reset(); + } }); Then("LoanItemListener.onProcessError result should match", () -> { @@ -108,7 +116,11 @@ public LoanItemListenerStepDefinitions() { }); When("LoanItemListener.onWriteError method executed", () -> { - loanItemListener.onWriteError(exception, new Chunk<>(List.of(loan))); + try { + loanItemListener.onWriteError(exception, new Chunk<>(List.of(loan))); + } finally { + ThreadLocalContextUtil.reset(); + } }); Then("LoanItemListener.onWriteError result should match", () -> { diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStepTest.java index 0e9cef6b2f6..84d0e956ac1 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStepTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStepTest.java @@ -42,6 +42,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualPlatformService; import org.junit.Assert; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -66,6 +67,11 @@ public void setUp() { underTest = new AddPeriodicAccrualEntriesBusinessStep(loanAccrualPlatformService); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void givenLoanWithAccrual() throws MultiException { // given diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java index 7f4393e0509..6e077b5e82e 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java @@ -122,7 +122,11 @@ public ApplyLoanLockTaskletStepDefinitions() { }); When("ApplyLoanLockTasklet.execute method executed", () -> { - resultItem = applyLoanLockTasklet.execute(stepContribution, null); + try { + resultItem = applyLoanLockTasklet.execute(stepContribution, null); + } finally { + ThreadLocalContextUtil.reset(); + } }); Then("ApplyLoanLockTasklet.execute result should match", () -> { diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java index 6b193ad7cd5..727cbdd51fa 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java @@ -46,6 +46,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -72,6 +73,11 @@ public void setUp() { underTest = new CheckLoanRepaymentDueBusinessStep(configurationDomainService, businessEventNotifierService); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void givenLoanWithInstallmentDueAfterConfiguredDaysWhenStepExecutionThenBusinessEventIsRaised() { ArgumentCaptor loanRepaymentDueEvent = ArgumentCaptor.forClass(LoanRepaymentDueBusinessEvent.class); diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java index 41f76b602e1..974d0d0ac23 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java @@ -43,6 +43,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -69,6 +70,11 @@ public void setUp() { underTest = new CheckLoanRepaymentOverdueBusinessStep(configurationDomainService, businessEventNotifierService); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void givenLoanWithInstallmentOverdueAfterConfiguredDaysWhenStepExecutionThenBusinessEventIsRaised() { ArgumentCaptor loanRepaymentDueBusinessEventArgumentCaptor = ArgumentCaptor @@ -169,5 +175,4 @@ public void givenLoanWithInstallmentOverdueAfterConfiguredDaysInLoanProductWhenS assertEquals(repaymentInstallment, loanPayloadForEvent); assertEquals(processedLoan, loanForProcessing); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderTest.java index 2ebe0efbb77..cdd22a08240 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderTest.java @@ -40,6 +40,7 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -73,6 +74,11 @@ class LoanItemReaderTest { @Mock private Loan loan; + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void testLoanItemReaderSimple() throws Exception { // given @@ -163,5 +169,4 @@ public void testLoanItemReaderMultiThreadRead() throws Exception { Mockito.verifyNoMoreInteractions(loanRepository); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStepTest.java index bdb22dd654f..6976991ce17 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStepTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStepTest.java @@ -47,6 +47,7 @@ import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -100,6 +101,11 @@ public void setUp() { delinquencyReadPlatformService, businessEventNotifierService); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + /** * Tests {@link SetLoanDelinquencyTagsBusinessStep#execute(Loan)} success scenario. * diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/service/COBBulkEventConfigurationTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/service/COBBulkEventConfigurationTest.java index 055009be197..19a47b1f932 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/service/COBBulkEventConfigurationTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/service/COBBulkEventConfigurationTest.java @@ -85,7 +85,7 @@ public void setUp() throws Exception { @AfterEach public void tearDown() { - ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); + ThreadLocalContextUtil.reset(); } @Test diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java index af2cec6022b..bb3a855ff8e 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java @@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.core.config.FineractProperties; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -73,6 +74,11 @@ class InlineLoanCOBExecutorServiceImplTest { @Mock private FineractProperties.FineractBodyItemSizeLimitProperties fineractBodyItemSizeLimitProperties; + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test void shouldExceptionThrownIfLoanIsAlreadyLocked() { JsonCommand command = mock(JsonCommand.class); diff --git a/fineract-provider/src/test/java/org/apache/fineract/commands/jobs/PurgeProcessedCommandsTaskletTest.java b/fineract-provider/src/test/java/org/apache/fineract/commands/jobs/PurgeProcessedCommandsTaskletTest.java index cacf22032ca..fa4ef94028f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/commands/jobs/PurgeProcessedCommandsTaskletTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/commands/jobs/PurgeProcessedCommandsTaskletTest.java @@ -37,6 +37,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -71,6 +72,11 @@ public void setUp() { underTest = new PurgeProcessedCommandsTasklet(repository, configurationDomainService); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void givenEventsForPurgeWhenTaskExecutionThenEventsPurgeForDaysCriteria() { // given @@ -97,5 +103,4 @@ public void givenEventsForPurgeWhenExceptionOccursThenJobExecutionFinishesSucces // then assertEquals(RepeatStatus.FINISHED, resultStatus); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandServiceStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandServiceStepDefinitions.java index 818e6d95f7e..c4d694e9da4 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandServiceStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandServiceStepDefinitions.java @@ -25,13 +25,10 @@ import io.cucumber.java8.En; import io.github.resilience4j.retry.RetryRegistry; import io.github.resilience4j.retry.event.RetryEvent; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.fineract.commands.domain.CommandSource; import org.apache.fineract.commands.domain.CommandWrapper; -import org.apache.fineract.commands.exception.RollbackTransactionAsCommandIsNotApprovedByCheckerException; +import org.apache.fineract.commands.exception.RollbackTransactionNotApprovedException; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder; @@ -69,7 +66,7 @@ public CommandServiceStepDefinitions() { ReflectionTestUtils.setField(processAndLogCommandService, "fineractRequestContextHolder", contextHolder); Mockito.when(contextHolder.getAttribute(any(), any())).thenThrow(new CannotAcquireLockException("BLOW IT UP!!!")) .thenThrow(new ObjectOptimisticLockingFailureException("Dummy", new RuntimeException("BLOW IT UP!!!"))) - .thenThrow(new RollbackTransactionAsCommandIsNotApprovedByCheckerException(new DummyCommandSource())); + .thenThrow(new RollbackTransactionNotApprovedException(1L, null)); this.retryRegistry.retry("executeCommand").getEventPublisher().onRetry(event -> { log.warn("... retry event: {}", event); @@ -147,13 +144,4 @@ public Long deleteEntry(Long makerCheckerId) { return null; } } - - @Entity - @Table(name = "m_portfolio_command_source") - public static class DummyCommandSource extends CommandSource { - - public DummyCommandSource() { - setId(1L); - } - } } diff --git a/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandSourceServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandSourceServiceTest.java index 04c30e48353..c38ee5c3a95 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandSourceServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandSourceServiceTest.java @@ -89,24 +89,12 @@ public void testCreateFromWrapper() { @Test public void testCreateFromExisting() { - CommandWrapper wrapper = CommandWrapper.wrap("act", "ent", 1L, 1L); long commandId = 1L; - JsonCommand jsonCommand = JsonCommand.fromExistingCommand(commandId, "", null, null, null, 1L, null, null, null, null, null, null, - null, null, null, null, null); CommandSource commandMock = Mockito.mock(CommandSource.class); - Mockito.when(commandSourceRepository.saveAndFlush(commandMock)).thenReturn(commandMock); Mockito.when(commandSourceRepository.findById(commandId)).thenReturn(Optional.of(commandMock)); - AppUser appUser = Mockito.mock(AppUser.class); - - ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "t1", "n1", ZoneId.systemDefault().toString(), null)); - - CommandSource actual = underTest.saveInitialNewTransaction(wrapper, jsonCommand, appUser, "idk"); - ArgumentCaptor commandSourceArgumentCaptor = ArgumentCaptor.forClass(CommandSource.class); - Mockito.verify(commandSourceRepository).saveAndFlush(commandSourceArgumentCaptor.capture()); - - CommandSource captured = commandSourceArgumentCaptor.getValue(); - Assertions.assertEquals(actual, captured); + CommandSource actual = underTest.getCommandSource(commandId); + Assertions.assertEquals(commandMock, actual); } @Test diff --git a/fineract-provider/src/test/java/org/apache/fineract/commands/service/SynchronousCommandProcessingServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/commands/service/SynchronousCommandProcessingServiceTest.java index 9fdcf694dee..4e6e0c43649 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/commands/service/SynchronousCommandProcessingServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/commands/service/SynchronousCommandProcessingServiceTest.java @@ -67,8 +67,6 @@ public class SynchronousCommandProcessingServiceTest { @Mock private IdempotencyKeyResolver idempotencyKeyResolver; @Mock - private IdempotencyKeyGenerator idempotencyKeyGenerator; - @Mock private CommandSourceService commandSourceService; @Spy @@ -93,19 +91,21 @@ public void testExecuteCommandSuccess() { when(commandWrapper.isNoteResource()).thenReturn(false); when(commandWrapper.isSurveyResource()).thenReturn(false); when(commandWrapper.isLoanDisburseDetailResource()).thenReturn(false); + + long commandId = 1L; JsonCommand jsonCommand = Mockito.mock(JsonCommand.class); + when(jsonCommand.commandId()).thenReturn(commandId); - NewCommandSourceHandler newCommandSourceHandler = Mockito.mock(NewCommandSourceHandler.class); + NewCommandSourceHandler commandHandler = Mockito.mock(NewCommandSourceHandler.class); CommandProcessingResult commandProcessingResult = Mockito.mock(CommandProcessingResult.class); when(commandProcessingResult.isRollbackTransaction()).thenReturn(false); - when(newCommandSourceHandler.processCommand(jsonCommand)).thenReturn(commandProcessingResult); - when(commandHandlerProvider.getHandler(Mockito.any(), Mockito.any())).thenReturn(newCommandSourceHandler); + when(commandHandler.processCommand(jsonCommand)).thenReturn(commandProcessingResult); + when(commandHandlerProvider.getHandler(Mockito.any(), Mockito.any())).thenReturn(commandHandler); when(configurationDomainService.isMakerCheckerEnabledForTask(Mockito.any())).thenReturn(false); String idk = "idk"; when(idempotencyKeyResolver.resolve(commandWrapper)).thenReturn(idk); CommandSource commandSource = Mockito.mock(CommandSource.class); - long commandId = 1L; when(commandSource.getId()).thenReturn(commandId); when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(null); when(commandSourceService.getCommandSource(commandId)).thenReturn(commandSource); @@ -116,9 +116,12 @@ public void testExecuteCommandSuccess() { when(commandSource.getStatus()).thenReturn(CommandProcessingResultType.PROCESSED.getValue()); when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser); + when(commandSourceService.processCommand(commandHandler, jsonCommand, commandSource, appUser, false, false)) + .thenReturn(commandProcessingResult); + CommandProcessingResult actualCommandProcessingResult = underTest.executeCommand(commandWrapper, jsonCommand, false); - verify(commandSourceService).saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk); + verify(commandSourceService).getCommandSource(commandId); assertEquals(CommandProcessingResultType.PROCESSED.getValue(), commandSource.getStatus()); verify(commandSourceService).saveResultSameTransaction(commandSource); @@ -133,19 +136,21 @@ public void testExecuteCommandFails() { when(commandWrapper.isSurveyResource()).thenReturn(false); when(commandWrapper.isLoanDisburseDetailResource()).thenReturn(false); JsonCommand jsonCommand = Mockito.mock(JsonCommand.class); + Long commandId = jsonCommand.commandId(); - NewCommandSourceHandler newCommandSourceHandler = Mockito.mock(NewCommandSourceHandler.class); + NewCommandSourceHandler commandHandler = Mockito.mock(NewCommandSourceHandler.class); CommandProcessingResult commandProcessingResult = Mockito.mock(CommandProcessingResult.class); CommandSource commandSource = Mockito.mock(CommandSource.class); when(commandProcessingResult.isRollbackTransaction()).thenReturn(false); RuntimeException runtimeException = new RuntimeException("foo"); - when(newCommandSourceHandler.processCommand(jsonCommand)).thenThrow(runtimeException); - when(commandHandlerProvider.getHandler(Mockito.any(), Mockito.any())).thenReturn(newCommandSourceHandler); + when(commandHandler.processCommand(jsonCommand)).thenThrow(runtimeException); + when(commandHandlerProvider.getHandler(Mockito.any(), Mockito.any())).thenReturn(commandHandler); when(configurationDomainService.isMakerCheckerEnabledForTask(Mockito.any())).thenReturn(false); String idk = "idk"; when(idempotencyKeyResolver.resolve(commandWrapper)).thenReturn(idk); when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(null); + when(commandSourceService.getCommandSource(commandId)).thenReturn(commandSource); AppUser appUser = Mockito.mock(AppUser.class); when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser); @@ -155,11 +160,14 @@ public void testExecuteCommandFails() { when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(initialCommandSource); + when(commandSourceService.processCommand(commandHandler, jsonCommand, commandSource, appUser, false, false)) + .thenThrow(runtimeException); + Assertions.assertThrows(RuntimeException.class, () -> { underTest.executeCommand(commandWrapper, jsonCommand, false); }); - verify(commandSourceService).saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk); + verify(commandSourceService).getCommandSource(commandId); verify(commandSourceService).generateErrorInfo(runtimeException); } } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/service/BusinessDateWritePlatformServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/service/BusinessDateWritePlatformServiceTest.java index 9fdcb129db2..eaabf63932e 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/service/BusinessDateWritePlatformServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/service/BusinessDateWritePlatformServiceTest.java @@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -79,6 +80,11 @@ public void init() { ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void businessDateIsNotEnabled() { JsonCommand command = JsonCommand.from(""); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/auditing/CustomAuditingHandlerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/auditing/CustomAuditingHandlerTest.java index 6bdcb6433ae..52844609d54 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/auditing/CustomAuditingHandlerTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/auditing/CustomAuditingHandlerTest.java @@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -48,6 +49,11 @@ public void init() { .setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.of("Asia/Kolkata"))))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void markCreated() { MappingContext mappingContext = Mockito.mock(MappingContext.class); @@ -111,5 +117,4 @@ public void markCreatedOldDateTimeProvider() { assertEquals(now.getHour(), targetObject.getCreatedDate().get().getHour()); assertEquals(now.getMinute(), targetObject.getCreatedDate().get().getMinute()); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/auditing/CustomDateTimeProviderTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/auditing/CustomDateTimeProviderTest.java index ae59614f189..1dec4df7a2c 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/auditing/CustomDateTimeProviderTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/auditing/CustomDateTimeProviderTest.java @@ -28,6 +28,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,6 +39,11 @@ public void init() { ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void instanceDateProvider() { Optional dateTimeProvider = CustomDateTimeProvider.INSTANCE.getNow(); @@ -65,5 +71,4 @@ public void tenantDateProvider() { assertEquals(now.getHour(), ((OffsetDateTime) dateTimeProvider.get()).getHour()); assertEquals(now.getMinute(), ((OffsetDateTime) dateTimeProvider.get()).getMinute()); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/service/DateUtilsTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/service/DateUtilsTest.java index c5b78065bb0..ee7ef37f2f9 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/service/DateUtilsTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/service/DateUtilsTest.java @@ -32,6 +32,7 @@ import java.util.TimeZone; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,6 +44,11 @@ public void init() { ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 12)))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void getSystemZoneIdTest() { TimeZone.setDefault(TimeZone.getTimeZone("GMT+02:00")); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableExportUtilTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableExportUtilTest.java index 1ff9c2944f0..d6ea10e359f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableExportUtilTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableExportUtilTest.java @@ -21,12 +21,26 @@ import java.util.Collections; import java.util.Map; import java.util.TreeMap; +import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.dataqueries.service.export.DatatableExportUtil; import org.junit.Assert; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class DatatableExportUtilTest { + @BeforeEach + public void setUp() { + ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); + } + + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void emptyFolderTest() { Assert.assertEquals("", DatatableExportUtil.normalizeFolderName("")); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/PurgeExternalEventsTaskletTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/PurgeExternalEventsTaskletTest.java index a956ba405c6..2bfbaf3828f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/PurgeExternalEventsTaskletTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/PurgeExternalEventsTaskletTest.java @@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.event.external.repository.ExternalEventRepository; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -69,6 +70,11 @@ public void setUp() { underTest = new PurgeExternalEventsTasklet(repository, configurationDomainService); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void givenEventsForPurgeWhenTaskExecutionThenEventsPurgeForDaysCriteria() { // given @@ -95,5 +101,4 @@ public void givenEventsForPurgeWhenExceptionOccursThenJobExecutionFinishesSucces // then assertEquals(RepeatStatus.FINISHED, resultStatus); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java index a2fe79b9706..df7e3215b8b 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java @@ -47,6 +47,7 @@ import org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEventView; import org.apache.fineract.infrastructure.event.external.service.message.MessageFactory; import org.apache.fineract.infrastructure.event.external.service.support.ByteBufferConverter; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -97,6 +98,11 @@ public void setUp() { configurationDomainService); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + private void configureExternalEventsProducerReadBatchSizeProperty() { FineractProperties.FineractEventsProperties eventsProperties = new FineractProperties.FineractEventsProperties(); FineractProperties.FineractExternalEventsProperties externalProperties = new FineractProperties.FineractExternalEventsProperties(); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/repository/domain/ExternalEventTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/repository/domain/ExternalEventTest.java index 02f12a8d950..39bb3b780d2 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/repository/domain/ExternalEventTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/repository/domain/ExternalEventTest.java @@ -26,10 +26,16 @@ import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; class ExternalEventTest { + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void testConstructorWorks() { // given @@ -56,6 +62,5 @@ public void testConstructorWorks() { assertThat(result.getBusinessDate()).isEqualTo(currentBusinessDate); assertThat(result.getCreatedAt()).isNotNull(); assertThat(result.getSentAt()).isNull(); - } } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventServiceTest.java index b89b0ca2a9f..8aaea6ff88f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventServiceTest.java @@ -57,6 +57,7 @@ import org.apache.fineract.investor.enricher.LoanAccountDataV1Enricher; import org.apache.fineract.investor.enricher.LoanTransactionAdjustmentDataV1Enricher; import org.apache.fineract.investor.enricher.LoanTransactionDataV1Enricher; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -110,6 +111,11 @@ public void setUp() { .setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault())))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void testPostEventShouldFailWhenNullEventIsGiven() { // given diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java index 0002caec360..22a9aa3784e 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java @@ -70,6 +70,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService; import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -105,6 +106,11 @@ public void setUp() { .setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault())))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void testLoanDelinquencyRangeEventPayloadSerialization() throws IOException { // given @@ -340,5 +346,4 @@ private LoanCharge buildLoanCharge(Loan loan, BigDecimal amount, Charge charge) ReflectionTestUtils.setField(loanCharge, "id", 1L); return loanCharge; } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAdjustTransactionBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAdjustTransactionBusinessEventSerializerTest.java index f3b724c83a9..9bb321ec934 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAdjustTransactionBusinessEventSerializerTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAdjustTransactionBusinessEventSerializerTest.java @@ -47,6 +47,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanChargePaidByReadPlatformService; import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService; import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -78,6 +79,11 @@ public void setUp() { .setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault())))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test void loanTransactionReversedOnDateSerializationTest() { Loan loanForProcessing = Mockito.mock(Loan.class); @@ -107,5 +113,4 @@ void loanTransactionReversedOnDateSerializationTest() { .toAvroDTO(businessEvent); assertEquals(reversedLocalDate, loanTransactionAdjustmentDataV1.getTransactionToAdjust().getReversedOnDate()); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java index be9215866e6..5e50faa2e7f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java @@ -90,6 +90,7 @@ public void setUp() { @AfterEach public void reset() { + ThreadLocalContextUtil.reset(); moneyHelper.close(); } @@ -181,5 +182,4 @@ public void testLoanRepaymentEventLoanIdMandatoryFieldValidation() { AvroRuntimeException exceptionThrown = assertThrows(AvroRuntimeException.class, () -> serializer.toAvroDTO(event)); assertTrue(exceptionThrown.getMessage().contains("does not accept null values")); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java index f1597f27f26..361310230ca 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java @@ -56,6 +56,7 @@ import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository; import org.apache.fineract.useradministration.domain.AppUser; import org.apache.http.HttpStatus; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -99,6 +100,11 @@ public void setUp() { testObj = new LoanCOBApiFilter(helper); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test void shouldLoanAndExternalMatchToo() { String externalId = UUID.randomUUID().toString(); diff --git a/fineract-provider/src/test/java/org/apache/fineract/investor/event/EnricherTest.java b/fineract-provider/src/test/java/org/apache/fineract/investor/event/EnricherTest.java index 8e11b5e0a3b..8d931f4517e 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/investor/event/EnricherTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/investor/event/EnricherTest.java @@ -45,6 +45,7 @@ import org.apache.fineract.investor.enricher.LoanAccountDataV1Enricher; import org.apache.fineract.investor.enricher.LoanChargeDataV1Enricher; import org.apache.fineract.investor.enricher.LoanTransactionDataV1Enricher; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -66,6 +67,11 @@ public void setUp() { } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void testLoanAccountDataEnricher() { LoanAccountDataV1Enricher loanAccountDataV1Enricher = mock(LoanAccountDataV1Enricher.class); @@ -178,5 +184,4 @@ public void testAllEventEnricherWorksCorrectly() { assertEquals(PURCHASE_PRICE_RATIO, data.getPurchasePriceRatio()); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java index 67ad3e7f77e..7bd0c22c562 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java @@ -76,6 +76,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -130,6 +131,11 @@ public void setUp() { .setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault())))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void givenLoanAccountWithDelinquencyBucketWhenRangeChangeThenEventIsRaised() { ArgumentCaptor loanDeliquencyRangeChangeEvent = ArgumentCaptor @@ -614,5 +620,4 @@ public void givenLoanAccountWhenBackdatedPauseActionThenLoanDelinquencyRangeChan Loan loanPayloadForEvent = loanDelinquencyRangeChangeEvent.getValue().get(); assertEquals(loanForProcessing, loanPayloadForEvent); } - } diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java index 1e2b5d27be3..67cd74e7140 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java @@ -105,6 +105,7 @@ public void setUp() { @AfterEach public void deregister() { + ThreadLocalContextUtil.reset(); moneyHelperStatic.close(); } diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTest.java index d5c8401a59a..a62e1f2dcca 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTest.java @@ -27,16 +27,23 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.domain.ExternalId; +import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType; import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode; import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.test.util.ReflectionTestUtils; @@ -46,11 +53,21 @@ */ public class LoanTest { + private final LocalDate actualDate = LocalDate.now(ZoneId.systemDefault()); + + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + /** * Tests {@link Loan#getCharges()} with charges. */ @Test public void testGetChargesWithCharges() { + ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); + ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, actualDate))); + Loan loan = new Loan(); ReflectionTestUtils.setField(loan, "charges", Collections.singleton(buildLoanCharge())); diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java index 7cffe275e5a..be3f43f5bc1 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java @@ -48,6 +48,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTransactionType; import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -83,6 +84,11 @@ public void setUp() { ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, transactionDate))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + @Test public void chargePaymentTransactionTestWithExactAmount() { final BigDecimal chargeAmount = BigDecimal.valueOf(100); diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorTest.java index 6f3b8993298..19213fdf149 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorTest.java @@ -44,6 +44,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -104,6 +105,11 @@ public void setUp() { ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, transactionDate))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + // IN ADVANCE @Test public void inAdvancePaymentOfPrincipal() { diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorTest.java index f817bab0037..b566bb29d7f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorTest.java @@ -44,6 +44,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -105,6 +106,11 @@ public void setUp() { ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, transactionDate))); } + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + // IN ADVANCE @Test public void inAdvancePaymentOfPrincipal() { diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanCalculateRepaymentPastDueServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanCalculateRepaymentPastDueServiceTest.java index eae0bfa6928..def517ca903 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanCalculateRepaymentPastDueServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanCalculateRepaymentPastDueServiceTest.java @@ -69,6 +69,7 @@ public void setUp() { @AfterEach public void reset() { + ThreadLocalContextUtil.reset(); moneyHelper.close(); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java index b040ea45ff3..24b59b2331a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java @@ -2153,12 +2153,7 @@ public void shouldNotFindAnyDatatableEntryByQueryAPIAndFailsToUpdateItsColumn() LOG.info("Batch Response : {}", new Gson().toJson(responseOfQueryAndUpdateDatatableBatch)); - final BatchResponse queryResponse = responseOfQueryAndUpdateDatatableBatch.get(0); - - Assertions.assertEquals(1L, queryResponse.getRequestId()); - Assertions.assertEquals(HttpStatus.SC_OK, queryResponse.getStatusCode(), "Verify Status Code 200 for query datatable entry"); - - final BatchResponse updateResponse = responseOfQueryAndUpdateDatatableBatch.get(1); + final BatchResponse updateResponse = responseOfQueryAndUpdateDatatableBatch.get(0); Assertions.assertEquals(2L, updateResponse.getRequestId()); Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, updateResponse.getStatusCode(), diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java index 3dd2c5586b6..b8898ce0025 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java @@ -21,6 +21,7 @@ import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.PAUSE; import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.RESUME; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -109,8 +110,10 @@ public void testCreateDelinquencyRanges() { // then assertNotNull(delinquencyRangeResponse01); assertNotNull(ranges); - assertEquals(1, ranges.get(0).getMinimumAgeDays(), "Expected Min Age Days to 1"); - assertEquals(3, ranges.get(0).getMaximumAgeDays(), "Expected Max Age Days to 3"); + assertFalse(ranges.isEmpty()); + GetDelinquencyRangesResponse range = ranges.get(ranges.size() - 1); + assertEquals(1, range.getMinimumAgeDays(), "Expected Min Age Days to 1"); + assertEquals(3, range.getMaximumAgeDays(), "Expected Max Age Days to 3"); } @Test diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/IdempotencyTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/IdempotencyTest.java index ee2b2c1a646..70e7534975d 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/IdempotencyTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/IdempotencyTest.java @@ -19,22 +19,25 @@ package org.apache.fineract.integrationtests; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; import io.restassured.response.Response; +import io.restassured.response.ResponseBody; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.UUID; import org.apache.fineract.cob.data.BusinessStep; import org.apache.fineract.cob.data.JobBusinessStepConfigData; import org.apache.fineract.infrastructure.core.exception.AbstractIdempotentCommandException; import org.apache.fineract.integrationtests.common.IdempotencyHelper; import org.apache.fineract.integrationtests.common.Utils; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -70,9 +73,9 @@ public void shouldUpdateStepOrder() { IdempotencyHelper.toJsonString(requestBody), idempotencyKeyHeader); Response responseSecond = IdempotencyHelper.updateBusinessStepOrder(requestSpec, updateResponseSpec, LOAN_JOB_NAME, IdempotencyHelper.toJsonString(requestBody), idempotencyKeyHeader); - Assertions.assertEquals(response.getBody().asString(), responseSecond.getBody().asString()); - Assertions.assertNull(response.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - Assertions.assertNotNull(responseSecond.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertEquals(response.getBody().asString(), responseSecond.getBody().asString()); + assertNull(response.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertNotNull(responseSecond.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); idempotencyKeyHeader = UUID.randomUUID().toString(); @@ -89,9 +92,9 @@ public void shouldUpdateStepOrder() { IdempotencyHelper.toJsonString(requestBody), idempotencyKeyHeader); Response updateSecond = IdempotencyHelper.updateBusinessStepOrder(requestSpec, updateResponseSpec, LOAN_JOB_NAME, IdempotencyHelper.toJsonString(requestBody), idempotencyKeyHeader); - Assertions.assertNull(update.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - Assertions.assertNotNull(updateSecond.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - Assertions.assertEquals(update.getBody().asString(), updateSecond.getBody().asString()); + assertNull(update.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertNotNull(updateSecond.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertEquals(update.getBody().asString(), updateSecond.getBody().asString()); newStepConfig = IdempotencyHelper.getConfiguredBusinessStepsByJobName(requestSpec, responseSpec, LOAN_JOB_NAME); applyChargeStep = newStepConfig.getBusinessSteps().stream() @@ -109,9 +112,9 @@ public void shouldUpdateStepOrder() { updateSecond = IdempotencyHelper.updateBusinessStepOrder(requestSpec, updateResponseSpec, LOAN_JOB_NAME, IdempotencyHelper.toJsonString(requestBody), idempotencyKeyHeader); - Assertions.assertNull(update.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - Assertions.assertNotNull(updateSecond.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - Assertions.assertEquals(update.getBody().asString(), updateSecond.getBody().asString()); + assertNull(update.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertNotNull(updateSecond.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertEquals(update.getBody().asString(), updateSecond.getBody().asString()); newStepConfig = IdempotencyHelper.getConfiguredBusinessStepsByJobName(requestSpec, responseSpec, LOAN_JOB_NAME); applyChargeStep = newStepConfig.getBusinessSteps().stream() @@ -126,14 +129,14 @@ public void shouldUpdateStepOrder() { updateSecond = IdempotencyHelper.updateBusinessStepOrder(requestSpec, updateResponseSpec, LOAN_JOB_NAME, IdempotencyHelper.toJsonString(originalStepConfig.getBusinessSteps()), idempotencyKeyHeader); - Assertions.assertNull(update.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - Assertions.assertNotNull(updateSecond.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - Assertions.assertEquals(update.getBody().asString(), updateSecond.getBody().asString()); + assertNull(update.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertNotNull(updateSecond.header(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertEquals(update.getBody().asString(), updateSecond.getBody().asString()); } @Test - public void shoudTheSecondRequestWithSameIdempotencyKeyWillFailureToo() { + public void shouldTheSecondRequestWithSameIdempotencyKeyWillFailureToo() { ResponseSpecification responseSpecForError = new ResponseSpecBuilder().expectStatusCode(400).build(); List requestBody = new ArrayList<>(); String idempotencyKey = UUID.randomUUID().toString(); @@ -141,13 +144,14 @@ public void shoudTheSecondRequestWithSameIdempotencyKeyWillFailureToo() { Response response1 = IdempotencyHelper.updateBusinessStepOrderWithError(requestSpec, responseSpecForError, LOAN_JOB_NAME, IdempotencyHelper.toJsonString(requestBody), idempotencyKey); - Assertions.assertNull(response1.getHeader(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - String originalBody = response1.getBody().asString(); + assertNull(response1.getHeader(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + ResponseBody body1 = response1.getBody(); + assertNotNull(body1); Response response2 = IdempotencyHelper.updateBusinessStepOrderWithError(requestSpec, responseSpecForError, LOAN_JOB_NAME, IdempotencyHelper.toJsonString(requestBody), idempotencyKey); - Assertions.assertNotNull(response2.getHeader(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); - Assertions.assertEquals(originalBody, response2.getBody().asString()); + assertNotNull(response2.getHeader(AbstractIdempotentCommandException.IDEMPOTENT_CACHE_HEADER)); + assertEquals((Map) body1.jsonPath().get(""), response2.getBody().jsonPath().get("")); } private BusinessStep getBusinessSteps(Long order, String stepName) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java index 4cdc88609a7..34f20611fe9 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java @@ -181,8 +181,8 @@ public void feeAndPenaltyChargePaymentWithDefaultAllocationRuleTest() { new PostLoansLoanIdRequest().actualDisbursementDate("01 January 2023").dateFormat(DATETIME_PATTERN) .transactionAmount(BigDecimal.valueOf(1000.00)).locale("en")); - final float feePortion = 50.0f; - final float penaltyPortion = 100.0f; + final double feePortion = 50.0d; + final double penaltyPortion = 100.0d; Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper.getLoanSpecifiedDueDateWithAccountTransferJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, @@ -209,8 +209,8 @@ public void feeAndPenaltyChargePaymentWithDefaultAllocationRuleTest() { assertEquals(feePortion, loanDetails.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding()); assertEquals(penaltyPortion, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesDue()); assertEquals(penaltyPortion, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding()); - assertEquals(400.0f, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalDueForPeriod()); - assertEquals(400.0f, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalOutstandingForPeriod()); + assertEquals(400.0d, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalDueForPeriod()); + assertEquals(400.0d, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalOutstandingForPeriod()); assertEquals(LocalDate.of(2023, 1, 16), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); scheduleJobHelper.executeAndAwaitJob(jobName); @@ -218,11 +218,11 @@ public void feeAndPenaltyChargePaymentWithDefaultAllocationRuleTest() { loanDetails = loanTransactionHelper.getLoanDetails((long) loanId); assertEquals(5, loanDetails.getRepaymentSchedule().getPeriods().size()); assertEquals(feePortion, loanDetails.getRepaymentSchedule().getPeriods().get(2).getFeeChargesDue()); - assertEquals(0, loanDetails.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding()); + assertEquals(0.0d, loanDetails.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding()); assertEquals(penaltyPortion, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesDue()); - assertEquals(0, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding()); - assertEquals(400, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalDueForPeriod()); - assertEquals(250, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalOutstandingForPeriod()); + assertEquals(0.0d, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding()); + assertEquals(400.0d, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalDueForPeriod()); + assertEquals(250.0d, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalOutstandingForPeriod()); assertEquals(LocalDate.of(2023, 1, 16), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); } finally { GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/MakercheckerTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/MakercheckerTest.java index 1b7faf84eef..b3480ce59e4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/MakercheckerTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/MakercheckerTest.java @@ -18,17 +18,31 @@ */ package org.apache.fineract.integrationtests; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; -import java.util.ArrayList; -import org.apache.fineract.client.models.GetMakerCheckerResponse; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.fineract.client.models.GlobalConfigurationPropertyData; +import org.apache.fineract.client.models.PutPermissionsRequest; +import org.apache.fineract.integrationtests.common.AuditHelper; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.CommonConstants; +import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.commands.MakercheckersHelper; +import org.apache.fineract.integrationtests.common.organisation.StaffHelper; +import org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper; +import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper; +import org.apache.fineract.integrationtests.useradministration.roles.RolesHelper; +import org.apache.fineract.integrationtests.useradministration.users.UserHelper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,6 +52,12 @@ public class MakercheckerTest { private ResponseSpecification responseSpec; private RequestSpecification requestSpec; private MakercheckersHelper makercheckersHelper; + private RolesHelper rolesHelper; + private AuditHelper auditHelper; + private SavingsProductHelper savingsProductHelper; + private SavingsAccountHelper savingsAccountHelper; + private static final String START_DATE_STRING = "03 June 2023"; + private static final String TRANSACTION_DATE_STRING = "05 June 2023"; @BeforeEach public void setup() { @@ -46,14 +66,151 @@ public void setup() { this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); this.makercheckersHelper = new MakercheckersHelper(this.requestSpec, this.responseSpec); + this.rolesHelper = new RolesHelper(); + this.auditHelper = new AuditHelper(requestSpec, responseSpec); + this.savingsProductHelper = new SavingsProductHelper(); + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); } @Test - public void testMakerchekerInboxList() { + public void testMakercheckerInboxList() { // given // when - final ArrayList makerCheckerList = this.makercheckersHelper.getMakerCheckerList(); - + List> makerCheckerList = this.makercheckersHelper.getMakerCheckerList(null); assertNotNull(makerCheckerList); } + + @Test + public void testMakerCheckerOn() { + GlobalConfigurationPropertyData mcConfig = GlobalConfigurationHelper.getGlobalConfigurationByName(requestSpec, responseSpec, + "maker-checker"); + Long mcConfigId = mcConfig.getId(); + boolean mcConfigUpdate = false; + if (!Boolean.TRUE.equals(mcConfig.getEnabled())) { + GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, mcConfigId, true); + mcConfigUpdate = true; + } + GlobalConfigurationPropertyData sameMcConfig = GlobalConfigurationHelper.getGlobalConfigurationByName(requestSpec, responseSpec, + "enable-same-maker-checker"); + Long sameMcConfigId = mcConfig.getId(); + boolean sameMcConfigUpdate = false; + if (Boolean.TRUE.equals(sameMcConfig.getEnabled())) { + GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, sameMcConfigId, false); + sameMcConfigUpdate = true; + } + + try { + // client permission - maker-checker disabled + PutPermissionsRequest putPermissionsRequest = new PutPermissionsRequest().putPermissionsItem("CREATE_CLIENT", false); + rolesHelper.updatePermissions(putPermissionsRequest); + putPermissionsRequest = new PutPermissionsRequest().putPermissionsItem("ACTIVATE_CLIENT", false); + rolesHelper.updatePermissions(putPermissionsRequest); + + Integer roleId = RolesHelper.createRole(requestSpec, responseSpec); + Map permissionMap = Map.of("CREATE_CLIENT", true, "CREATE_CLIENT_CHECKER", true, "ACTIVATE_CLIENT", true, + "ACTIVATE_CLIENT_CHECKER", true, "WITHDRAWAL_SAVINGSACCOUNT", true, "WITHDRAWAL_SAVINGSACCOUNT_CHECKER", true); + RolesHelper.addPermissionsToRole(requestSpec, responseSpec, roleId, permissionMap); + final Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec); + // create maker user + String maker = Utils.uniqueRandomStringGenerator("user", 8); + final Integer makerUserId = (Integer) UserHelper.createUser(this.requestSpec, this.responseSpec, roleId, staffId, maker, + "P4ssw0rd", "resourceId"); + + // create client - maker-checker disabled + RequestSpecification makerRequestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build() + .header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(maker, "P4ssw0rd")); + Integer clientId = ClientHelper.createClient(makerRequestSpec, this.responseSpec); + assertNotNull(clientId); + ClientHelper.verifyClientCreatedOnServer(requestSpec, this.responseSpec, clientId); + + final Integer savingsId = createApproveActivateSavingsAccountDailyPosting(clientId, START_DATE_STRING); + assertNotNull(savingsId); + Integer transactionId = (Integer) savingsAccountHelper.depositToSavingsAccount(savingsId, "1000", TRANSACTION_DATE_STRING, + CommonConstants.RESPONSE_RESOURCE_ID); + assertNotNull(transactionId); + + // client and saving permission - maker-checker enabled + putPermissionsRequest = new PutPermissionsRequest().putPermissionsItem("ACTIVATE_CLIENT", true); + rolesHelper.updatePermissions(putPermissionsRequest); + putPermissionsRequest = new PutPermissionsRequest().putPermissionsItem("WITHDRAWAL_SAVINGSACCOUNT", true); + rolesHelper.updatePermissions(putPermissionsRequest); + + // create client - maker-checker enabled + clientId = ClientHelper.createClient(makerRequestSpec, this.responseSpec); + assertNull(clientId, "Client is created on the server"); + + List> auditDetails = makercheckersHelper + .getMakerCheckerList(Map.of("actionName", "CREATE", "entityName", "CLIENT", "makerId", makerUserId.toString())); + assertEquals(1, auditDetails.size(), "More than one command exists"); + Long clientCommandId = ((Double) auditDetails.get(0).get("id")).longValue(); + + // savings withdrawal - maker-checker enabled + SavingsAccountHelper makerSavingsHelper = new SavingsAccountHelper(makerRequestSpec, this.responseSpec); + Integer withdrawalId = (Integer) makerSavingsHelper.withdrawalFromSavingsAccount(savingsId, "100", TRANSACTION_DATE_STRING, + CommonConstants.RESPONSE_RESOURCE_ID); + assertNull(withdrawalId, "Withdrawal performed on the server"); + + auditDetails = makercheckersHelper.getMakerCheckerList( + Map.of("actionName", "WITHDRAWAL", "entityName", "SAVINGSACCOUNT", "makerId", makerUserId.toString())); + assertEquals(1, auditDetails.size(), "More than one command exists"); + Long savingCommandId = ((Double) auditDetails.get(0).get("id")).longValue(); + + // check by the same user should fail + ResponseSpecification failedResponseSpec = new ResponseSpecBuilder().expectStatusCode(400).build(); + MakercheckersHelper.approveMakerCheckerEntry(makerRequestSpec, failedResponseSpec, clientCommandId); + MakercheckersHelper.approveMakerCheckerEntry(makerRequestSpec, failedResponseSpec, savingCommandId); + + // create checker user + String checker = Utils.uniqueRandomStringGenerator("user", 8); + final Integer checkerUserId = (Integer) UserHelper.createUser(this.requestSpec, this.responseSpec, roleId, staffId, checker, + "P4ssw0rd", "resourceId"); + RequestSpecification checkerRequestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build() + .header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(checker, "P4ssw0rd")); + + // check by another checker user should succeed + HashMap response = MakercheckersHelper.approveMakerCheckerEntry(checkerRequestSpec, responseSpec, clientCommandId); + assertNotNull(response); + clientId = (Integer) response.get("clientId"); + assertNotNull(clientId); + ClientHelper.verifyClientCreatedOnServer(requestSpec, responseSpec, clientId); + + response = MakercheckersHelper.approveMakerCheckerEntry(checkerRequestSpec, responseSpec, savingCommandId); + assertNotNull(response); + withdrawalId = (Integer) response.get("resourceId"); + assertNotNull(withdrawalId); + + // add checker superuser permission - actions are performed in one step + permissionMap = Map.of("CHECKER_SUPER_USER", true); + RolesHelper.addPermissionsToRole(requestSpec, responseSpec, roleId, permissionMap); + clientId = ClientHelper.createClient(makerRequestSpec, this.responseSpec); + assertNotNull(clientId); + ClientHelper.verifyClientCreatedOnServer(requestSpec, this.responseSpec, clientId); + + withdrawalId = (Integer) makerSavingsHelper.withdrawalFromSavingsAccount(savingsId, "100", TRANSACTION_DATE_STRING, + CommonConstants.RESPONSE_RESOURCE_ID); + assertNotNull(withdrawalId); + } finally { + if (mcConfigUpdate) { + GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, mcConfigId, false); + } + if (sameMcConfigUpdate) { + GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, sameMcConfigId, true); + } + PutPermissionsRequest putPermissionsRequest = new PutPermissionsRequest().putPermissionsItem("WITHDRAWAL_SAVINGSACCOUNT", + false); + rolesHelper.updatePermissions(putPermissionsRequest); + } + } + + private Integer createSavingsProductDailyPosting() { + final String savingsProductJSON = this.savingsProductHelper.withInterestCompoundingPeriodTypeAsDaily() + .withInterestPostingPeriodTypeAsDaily().withInterestCalculationPeriodTypeAsDailyBalance().build(); + return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); + } + + private Integer createApproveActivateSavingsAccountDailyPosting(final Integer clientID, final String startDate) { + final Integer savingsProductID = createSavingsProductDailyPosting(); + assertNotNull(savingsProductID); + return savingsAccountHelper.createApproveActivateSavingsAccount(clientID, savingsProductID, startDate); + } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java index ea5f63b9aa1..d643d23ff00 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.integrationtests; +import static org.apache.fineract.integrationtests.common.CommonConstants.RESPONSE_RESOURCE_ID; import static org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper.PAYMENT_TYPE_ID; import static org.apache.fineract.integrationtests.common.system.DatatableHelper.addDatatableColumn; import static org.apache.http.HttpStatus.SC_CONFLICT; @@ -60,7 +61,6 @@ import org.apache.fineract.integrationtests.common.BatchHelper; import org.apache.fineract.integrationtests.common.BusinessDateHelper; import org.apache.fineract.integrationtests.common.ClientHelper; -import org.apache.fineract.integrationtests.common.CommonConstants; import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper; @@ -118,7 +118,7 @@ public void verifySavingsTransactionSubmittedOnDateAndTransactionDate() throws J final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDateString); assertNotNull(clientID); - final Integer savingsId = createSavingsAccountDailyPosting(clientID, startDateString); + final Integer savingsId = createApproveActivateSavingsAccountDailyPosting(clientID, startDateString); assertNotNull(savingsId); performSavingsTransaction(savingsId, "100", depositDate, true); @@ -176,7 +176,7 @@ public void testConcurrentSavingsBatchTransactions() { // creating datatable for client entity final HashMap columnMap = new HashMap<>(); - String datatableName = Utils.uniqueRandomStringGenerator("savings_transaction" + "_", 5).toLowerCase(); + String datatableName = Utils.uniqueRandomStringGenerator("dt_savings_transaction_", 5).toLowerCase(); columnMap.put("datatableName", datatableName); columnMap.put("apptableName", "m_savings_account_transaction"); columnMap.put("multiRow", false); @@ -284,10 +284,9 @@ private void enableBusinessDate(RequestSpecification requestSpec, ResponseSpecif private void performSavingsTransaction(Integer savingsId, String amount, LocalDate transactionDate, boolean isDeposit) { String transactionType = isDeposit ? "Deposit" : "Withdrawal"; Integer transactionId = isDeposit - ? (Integer) this.savingsAccountHelper.depositToSavingsAccount(savingsId, amount, depositDateString, - CommonConstants.RESPONSE_RESOURCE_ID) + ? (Integer) this.savingsAccountHelper.depositToSavingsAccount(savingsId, amount, depositDateString, RESPONSE_RESOURCE_ID) : (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, amount, withdrawDateString, - CommonConstants.RESPONSE_RESOURCE_ID); + RESPONSE_RESOURCE_ID); assertNotNull(transactionId); @@ -311,17 +310,10 @@ private LocalDate extractLocalDate(HashMap transactionMap, String fieldName) { return extractedDate; } - private Integer createSavingsAccountDailyPosting(final Integer clientID, final String startDate) { + private Integer createApproveActivateSavingsAccountDailyPosting(final Integer clientID, final String startDate) { final Integer savingsProductID = createSavingsProductDailyPosting(); assertNotNull(savingsProductID); - final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplicationOnDate(clientID, savingsProductID, - ACCOUNT_TYPE_INDIVIDUAL, startDate); - assertNotNull(savingsId); - HashMap savingsStatusHashMap = this.savingsAccountHelper.approveSavingsOnDate(savingsId, startDate); - SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap); - savingsStatusHashMap = this.savingsAccountHelper.activateSavingsAccount(savingsId, startDate); - SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); - return savingsId; + return savingsAccountHelper.createApproveActivateSavingsAccount(clientID, savingsProductID, startDate); } private Integer createSavingsProductDailyPosting() { @@ -382,28 +374,31 @@ public void run() { final List responses = enclosingTransaction ? BatchHelper.postBatchRequestsWithEnclosingTransaction(requestSpec, responseSpec, json) : BatchHelper.postBatchRequestsWithoutEnclosingTransaction(requestSpec, responseSpec, json); - assertNotNull(responses); + assertNotNull(responses, "Responses"); if (enclosingTransaction) { Integer statusCode1 = responses.get(0).getStatusCode(); - assertNotNull(statusCode1); + assertNotNull(statusCode1, "First enlosingTransaction response status code"); assertTrue(SC_OK == statusCode1 || SC_CONFLICT == statusCode1, "Status code: " + statusCode1); if (SC_OK == statusCode1) { - assertEquals(4, responses.size()); + assertEquals(4, responses.size(), "Response size for enlosingTransaction OK response"); Integer statusCode4 = responses.get(3).getStatusCode(); - assertNotNull(statusCode4); - assertEquals(SC_OK, statusCode4); + assertNotNull(statusCode4, "Last enlosingTransaction OK response status code"); + assertEquals(SC_OK, statusCode4, "Last enlosingTransaction OK response status code"); } else { - assertEquals(1, responses.size()); + assertEquals(1, responses.size(), "Response size for enlosingTransaction failed response"); } } else { - assertEquals(4, responses.size()); + assertEquals(4, responses.size(), "Response size for without-enlosingTransaction response"); Integer statusCode1 = responses.get(0).getStatusCode(); - assertNotNull(statusCode1); - assertTrue(SC_OK == statusCode1 || SC_CONFLICT == statusCode1, "Status code: " + statusCode1); + assertNotNull(statusCode1, "First without-enlosingTransaction response status code"); + assertTrue(SC_OK == statusCode1 || SC_CONFLICT == statusCode1, + "First without-enlosingTransaction response status code: " + statusCode1); Integer statusCode4 = responses.get(3).getStatusCode(); - assertNotNull(statusCode4); - assertTrue(SC_OK == statusCode1 ? (SC_OK == statusCode4 || SC_CONFLICT == statusCode4) - : (SC_FORBIDDEN == statusCode4 || SC_CONFLICT == statusCode4), "Status code: " + statusCode4); + assertNotNull(statusCode4, "Last without-enlosingTransaction response status code"); + assertTrue( + SC_OK == statusCode1 ? (SC_OK == statusCode4 || SC_CONFLICT == statusCode4) + : (SC_FORBIDDEN == statusCode4 || SC_CONFLICT == statusCode4), + "Last without-enlosingTransaction response status code: " + statusCode4); } } else { String json = transactionData.getJson(); @@ -417,14 +412,14 @@ public void run() { } private static boolean checkConcurrentResponse(String response) { - assertNotNull(response); + assertNotNull(response, "Single response"); JsonPath res = JsonPath.from(response); String statusCode = res.get("httpStatusCode"); if (statusCode == null) { - assertNotNull(res.get(CommonConstants.RESPONSE_RESOURCE_ID)); + assertNotNull(res.get(RESPONSE_RESOURCE_ID), "Single response " + RESPONSE_RESOURCE_ID); return true; } - assertEquals(String.valueOf(SC_CONFLICT), statusCode); + assertEquals(String.valueOf(SC_CONFLICT), statusCode, "Single response status code"); return false; } } @@ -439,22 +434,22 @@ private void runDeadlockBatch(SavingsAccountHelper savingsHelper, Integer saving RequestSpecification requestSpec = savingsHelper.getRequestSpec(); ResponseSpecification responseSpec = savingsHelper.getResponseSpec(); final List responses = BatchHelper.postBatchRequestsWithEnclosingTransaction(requestSpec, responseSpec, json); - assertNotNull(responses); + assertNotNull(responses, "Responses"); BatchResponse response1 = responses.get(0); Integer statusCode = response1.getStatusCode(); String msg = Strings.nullToEmpty(response1.getBody()); - assertNotNull(statusCode); + assertNotNull(statusCode, "First response status code"); assertTrue( SC_OK == statusCode || SC_CONFLICT == statusCode || (SC_FORBIDDEN == statusCode && msg.contains("Cannot add or update a child row")), "Status code: " + statusCode + ", message: " + msg); if (SC_OK == statusCode) { - assertEquals(4, responses.size()); + assertEquals(4, responses.size(), "Response size for OK response"); Integer statusCode4 = responses.get(3).getStatusCode(); - assertNotNull(statusCode4); - assertEquals(SC_OK, statusCode4); + assertNotNull(statusCode4, "Last OK response status code"); + assertEquals(SC_OK, statusCode4, "Last OK response status code"); } else { - assertEquals(1, responses.size()); + assertEquals(1, responses.size(), "Response size for failed response"); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/AuditHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/AuditHelper.java index 48687b48ee6..526028b7c09 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/AuditHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/AuditHelper.java @@ -20,6 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import com.google.gson.Gson; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.util.Collections; @@ -27,6 +28,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import org.apache.fineract.client.util.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,13 +40,15 @@ public class AuditHelper { - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private static final Logger LOG = LoggerFactory.getLogger(AuditHelper.class); private static final String AUDIT_BASE_URL = "/fineract-provider/api/v1/audits?" + Utils.TENANT_IDENTIFIER; private static final String AUDITSEARCH_BASE_URL = "/fineract-provider/api/v1/audits/searchtemplate?" + Utils.TENANT_IDENTIFIER; + private static final Gson GSON = new JSON().getGson(); + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + public AuditHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { this.requestSpec = requestSpec; this.responseSpec = responseSpec; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java index 4fe95872769..a44b571fbbd 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java @@ -119,8 +119,8 @@ public static void verifyAllDefaultGlobalConfigurations(final RequestSpecificati ArrayList expectedGlobalConfigurations = getAllDefaultGlobalConfigurations(); ArrayList actualGlobalConfigurations = getAllGlobalConfigurations(requestSpec, responseSpec); - Assertions.assertEquals(52, expectedGlobalConfigurations.size()); - Assertions.assertEquals(52, actualGlobalConfigurations.size()); + Assertions.assertEquals(53, expectedGlobalConfigurations.size()); + Assertions.assertEquals(53, actualGlobalConfigurations.size()); for (int i = 0; i < expectedGlobalConfigurations.size(); i++) { @@ -571,9 +571,16 @@ private static ArrayList getAllDefaultGlobalConfigurations() { assetExternalizationOfNonActiveLoans.put("value", 0); assetExternalizationOfNonActiveLoans.put("enabled", true); assetExternalizationOfNonActiveLoans.put("trapDoor", false); - assetExternalizationOfNonActiveLoans.put("string_value", "due-date"); defaults.add(assetExternalizationOfNonActiveLoans); + HashMap enableSameMakerChecker = new HashMap<>(); + enableSameMakerChecker.put("id", 58); + enableSameMakerChecker.put("name", "enable-same-maker-checker"); + enableSameMakerChecker.put("value", 0); + enableSameMakerChecker.put("enabled", false); + enableSameMakerChecker.put("trapDoor", false); + defaults.add(enableSameMakerChecker); + return defaults; } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/commands/MakercheckersHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/commands/MakercheckersHelper.java index 27996ce4598..5a36b99934a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/commands/MakercheckersHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/commands/MakercheckersHelper.java @@ -23,8 +23,9 @@ import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.lang.reflect.Type; -import java.util.ArrayList; -import org.apache.fineract.client.models.GetMakerCheckerResponse; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.fineract.client.util.JSON; import org.apache.fineract.integrationtests.common.Utils; @@ -32,7 +33,7 @@ public class MakercheckersHelper { private static final Gson GSON = new JSON().getGson(); - private static final String MAKERCHECKER_URL = "/fineract-provider/api/v1/makercheckers?" + Utils.TENANT_IDENTIFIER; + private static final String MAKERCHECKER_URL = "/fineract-provider/api/v1/makercheckers"; private final RequestSpecification requestSpec; private final ResponseSpecification responseSpec; @@ -42,10 +43,25 @@ public MakercheckersHelper(final RequestSpecification requestSpec, final Respons this.responseSpec = responseSpec; } - public ArrayList getMakerCheckerList() { - final String response = Utils.performServerGet(this.requestSpec, this.responseSpec, MAKERCHECKER_URL); - Type makerCheckerList = new TypeToken>() {}.getType(); + public List> getMakerCheckerList(Map queryParams) { + StringBuilder url = new StringBuilder(MAKERCHECKER_URL).append("?").append(Utils.TENANT_IDENTIFIER); + if (queryParams != null) { + for (Map.Entry entry : queryParams.entrySet()) { + url.append("&").append(entry.getKey()).append("=").append(entry.getValue()); + } + } + final String response = Utils.performServerGet(this.requestSpec, this.responseSpec, url.toString()); + Type makerCheckerList = new TypeToken>>() {}.getType(); return GSON.fromJson(response, makerCheckerList); } + public void approveMakerCheckerEntry(Long auditId) { + approveMakerCheckerEntry(this.requestSpec, this.responseSpec, auditId); + } + + public static HashMap approveMakerCheckerEntry(RequestSpecification requestSpec, ResponseSpecification responseSpec, + Long auditId) { + String url = MAKERCHECKER_URL + "/" + auditId + "?command=approve&" + Utils.TENANT_IDENTIFIER; + return Utils.performServerPost(requestSpec, responseSpec, url, "", ""); + } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java index a0b7d9cfff6..98b60457421 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java @@ -20,6 +20,7 @@ import static org.apache.fineract.integrationtests.common.Utils.DEFAULT_TENANT; import static org.apache.fineract.integrationtests.common.Utils.TENANT_PARAM_NAME; +import static org.junit.jupiter.api.Assertions.assertNotNull; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; @@ -174,6 +175,16 @@ public Object applyForSavingsApplicationWithFailure(final Integer id, final Inte savingsApplicationJSON, responseAttribute); } + public Integer createApproveActivateSavingsAccount(final Integer clientId, Integer savingsProductId, final String startDate) { + final Integer savingsId = applyForSavingsApplicationOnDate(clientId, savingsProductId, ACCOUNT_TYPE_INDIVIDUAL, startDate); + assertNotNull(savingsId); + HashMap savingsStatusHashMap = approveSavingsOnDate(savingsId, startDate); + SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap); + savingsStatusHashMap = activateSavingsAccount(savingsId, startDate); + SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); + return savingsId; + } + public HashMap updateSavingsAccount(final Integer id, final Integer savingsProductID, final Integer savingsId, final String accountType) { final String savingsApplicationJSON = new SavingsApplicationTestBuilder() // diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/useradministration/roles/RolesHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/useradministration/roles/RolesHelper.java index c019275fa9c..f71cc48a265 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/useradministration/roles/RolesHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/useradministration/roles/RolesHelper.java @@ -19,24 +19,36 @@ package org.apache.fineract.integrationtests.useradministration.roles; import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; +import java.lang.reflect.Type; import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.fineract.client.models.CommandProcessingResult; +import org.apache.fineract.client.models.PutPermissionsRequest; +import org.apache.fineract.client.util.JSON; +import org.apache.fineract.integrationtests.client.IntegrationTest; import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.useradministration.data.PermissionData; -public final class RolesHelper { +public final class RolesHelper extends IntegrationTest { public static final long SUPER_USER_ROLE_ID = 1L; // This is hardcoded into the initial Liquibase migration - private RolesHelper() { + public RolesHelper() { } private static final String CREATE_ROLE_URL = "/fineract-provider/api/v1/roles?" + Utils.TENANT_IDENTIFIER; private static final String ROLE_URL = "/fineract-provider/api/v1/roles"; + private static final String PERMISSIONS_URL = "/fineract-provider/api/v1/permissions"; private static final String DISABLE_ROLE_COMMAND = "disable"; private static final String ENABLE_ROLE_COMMAND = "enable"; + private static final Gson GSON = new JSON().getGson(); + public static Integer createRole(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { return Utils.performServerPost(requestSpec, responseSpec, CREATE_ROLE_URL, getTestCreateRoleAsJSON(), "resourceId"); } @@ -70,13 +82,25 @@ public static Integer deleteRole(final RequestSpecification requestSpec, final R } public static String addPermissionsToRole(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, - final Integer roleId, final HashMap permissionMap) { + final Integer roleId, final Map permissionMap) { return Utils.performServerPut(requestSpec, responseSpec, ROLE_URL + "/" + roleId + "/permissions?" + Utils.TENANT_IDENTIFIER, getAddPermissionsToRoleJSON(permissionMap)); } - private static String getAddPermissionsToRoleJSON(HashMap permissionMap) { - final HashMap> map = new HashMap<>(); + public static List getPermissions(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + boolean makerCheckerable) { + String response = Utils.performServerGet(requestSpec, responseSpec, + PERMISSIONS_URL + "?" + makerCheckerable + "=" + makerCheckerable); + final Type listType = new TypeToken>() {}.getType(); + return GSON.fromJson(response, listType); + } + + public CommandProcessingResult updatePermissions(PutPermissionsRequest request) { + return ok(fineract().permissions.updatePermissionsDetails(request)); + } + + private static String getAddPermissionsToRoleJSON(Map permissionMap) { + final HashMap> map = new HashMap<>(); map.put("permissions", permissionMap); return new Gson().toJson(map); } @@ -84,5 +108,4 @@ private static String getAddPermissionsToRoleJSON(HashMap permi private static String createRoleOperationURL(final String command, final Integer roleId) { return ROLE_URL + "/" + roleId + "?command=" + command + "&" + Utils.TENANT_IDENTIFIER; } - }