This is an automated email from the ASF dual-hosted git repository.

arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 80bcb27b0 FINERACT-1921: BatchAPI - status code mismatch
80bcb27b0 is described below

commit 80bcb27b0acf380bb00cf62053eeb04017fbe128
Author: jmarta <marta.jankov...@dpc.hu>
AuthorDate: Mon Sep 25 07:28:32 2023 +0200

    FINERACT-1921: BatchAPI - status code mismatch
---
 .../fineract/batch/exception/ErrorHandler.java     | 12 ++++++--
 .../batch/service/BatchApiServiceImpl.java         | 15 +++++-----
 .../domain/CommandProcessingResultType.java        | 11 ++++++++
 .../commands/service/CommandWrapperBuilder.java    |  1 -
 .../SynchronousCommandProcessingService.java       | 32 ++++++++++------------
 .../core/data/ApiGlobalErrorResponse.java          |  5 ++--
 .../IdempotentCommandProcessFailedException.java   | 15 +++++-----
 .../IdempotentCommandProcessSucceedException.java  |  7 +++--
 ...tentCommandProcessUnderProcessingException.java |  4 +--
 .../ConcurrencyFailureExceptionMapper.java         |  7 +++--
 .../IdempotentCommandExceptionMapper.java          |  6 ++--
 .../OptimisticLockExceptionMapper.java             |  7 +++--
 ...empotencyCommandProcessFailedExceptionTest.java |  2 +-
 .../CreateDatatableEntryCommandStrategy.java       | 22 ++++-----------
 .../service/ReadWriteNonCoreDataServiceImpl.java   | 16 +++++------
 .../SavingsAccountTransactionTest.java             | 14 +++++-----
 16 files changed, 93 insertions(+), 83 deletions(-)

diff --git 
a/fineract-core/src/main/java/org/apache/fineract/batch/exception/ErrorHandler.java
 
b/fineract-core/src/main/java/org/apache/fineract/batch/exception/ErrorHandler.java
index 6bf566fea..0f3491120 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/batch/exception/ErrorHandler.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/batch/exception/ErrorHandler.java
@@ -76,10 +76,14 @@ public final class ErrorHandler {
             Set<String> exceptionMappers = 
createSet(ctx.getBeanNamesForType(forClassWithGenerics(ExceptionMapper.class, 
clazz)));
             Set<String> fineractErrorMappers = 
createSet(ctx.getBeanNamesForType(FineractExceptionMapper.class));
             SetUtils.SetView<String> intersection = 
SetUtils.intersection(exceptionMappers, fineractErrorMappers);
-            if (intersection.size() > 0) {
+            if (!intersection.isEmpty()) {
                 // noinspection unchecked
                 return (ExceptionMapper<T>) 
ctx.getBean(intersection.iterator().next());
             }
+            if (!exceptionMappers.isEmpty()) {
+                // noinspection unchecked
+                return (ExceptionMapper<T>) 
ctx.getBean(exceptionMappers.iterator().next());
+            }
             clazz = clazz.getSuperclass();
         } while (!clazz.equals(Exception.class));
         // noinspection unchecked
@@ -98,8 +102,10 @@ public final class ErrorHandler {
         MultivaluedMap<String, Object> headers = response.getHeaders();
         Set<Header> batchHeaders = headers == null ? null
                 : headers.keySet().stream().map(e -> new Header(e, 
response.getHeaderString(e))).collect(Collectors.toSet());
-        return new ErrorInfo(response.getStatus(), ((FineractExceptionMapper) 
exceptionMapper).errorCode(),
-                JSON_HELPER.toJson(response.getEntity()), batchHeaders);
+        Integer errorCode = exceptionMapper instanceof FineractExceptionMapper 
? ((FineractExceptionMapper) exceptionMapper).errorCode()
+                : null;
+        Object msg = response.getEntity();
+        return new ErrorInfo(response.getStatus(), errorCode, msg instanceof 
String ? (String) msg : JSON_HELPER.toJson(msg), batchHeaders);
     }
 
     public RuntimeException getMappable(@NotNull Throwable thr) {
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 c23dce152..834002fe0 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
@@ -223,7 +223,7 @@ public class BatchApiServiceImpl implements BatchApiService 
{
                 callRequestRecursive(resolvedChildRequest, childNode, 
responseList, uriInfo, enclosingTransaction);
             });
         } else {
-            responseList.addAll(parentRequestFailedRecursive(request, 
requestNode, response, true));
+            responseList.addAll(parentRequestFailedRecursive(request, 
requestNode, response, null));
         }
         // If the current request fails, then all the child requests are not 
executed. If we want to write out all the
         // child requests, here is the place.
@@ -296,16 +296,17 @@ public class BatchApiServiceImpl implements 
BatchApiService {
      *            the current request node
      * @return {@code BatchResponse} list of the generated batch responses
      */
-    private List<BatchResponse> parentRequestFailedRecursive(BatchRequest 
request, BatchRequestNode requestNode, BatchResponse response,
-            boolean root) {
+    private List<BatchResponse> parentRequestFailedRecursive(@NotNull 
BatchRequest request, @NotNull BatchRequestNode requestNode,
+            @NotNull BatchResponse response, Long parentId) {
         List<BatchResponse> responseList = new ArrayList<>();
-        if (root) {
+        if (parentId == null) { // root
             
BatchRequestContextHolder.getEnclosingTransaction().ifPresent(TransactionExecution::setRollbackOnly);
         } else {
-            responseList.add(buildErrorResponse(request.getRequestId(), 
response.getStatusCode(), response.getBody(), null));
+            responseList.add(buildErrorResponse(request.getRequestId(), 
response.getStatusCode(),
+                    "Parent request with id " + parentId + " was erroneous!", 
null));
         }
-        requestNode.getChildNodes().forEach(
-                childNode -> 
responseList.addAll(parentRequestFailedRecursive(childNode.getRequest(), 
childNode, response, false)));
+        requestNode.getChildNodes().forEach(childNode -> responseList
+                .addAll(parentRequestFailedRecursive(childNode.getRequest(), 
childNode, response, request.getRequestId())));
         return responseList;
     }
 
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandProcessingResultType.java
 
b/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandProcessingResultType.java
index 770f579d0..299c1a0e2 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandProcessingResultType.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandProcessingResultType.java
@@ -18,6 +18,9 @@
  */
 package org.apache.fineract.commands.domain;
 
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 
@@ -32,6 +35,14 @@ public enum CommandProcessingResultType {
     UNDER_PROCESSING(4, "commandProcessingResultType.underProcessing"), //
     ERROR(5, "commandProcessingResultType.error");
 
+    private static final Map<Integer, CommandProcessingResultType> BY_ID = 
Arrays.stream(values())
+            .collect(Collectors.toMap(CommandProcessingResultType::getValue, v 
-> v));
+
     private final Integer value;
     private final String code;
+
+    public static CommandProcessingResultType fromInt(final Integer value) {
+        CommandProcessingResultType transactionType = BY_ID.get(value);
+        return transactionType == null ? INVALID : transactionType;
+    }
 }
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
 
b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
index 08af2792f..22fcc7237 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
@@ -737,7 +737,6 @@ public class CommandWrapperBuilder {
     }
 
     private void commonDatatableSettings(final String datatable, final Long 
apptableId, final Long datatableId) {
-
         this.entityName = datatable;
         this.entityId = apptableId;
         this.subentityId = datatableId;
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 3eff8ba55..e45814a91 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
@@ -30,7 +30,6 @@ import java.lang.reflect.Type;
 import java.time.Instant;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.function.Function;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.batch.exception.ErrorHandler;
@@ -48,7 +47,6 @@ 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.AbstractIdempotentCommandException;
 import 
org.apache.fineract.infrastructure.core.exception.IdempotentCommandProcessFailedException;
 import 
org.apache.fineract.infrastructure.core.exception.IdempotentCommandProcessSucceedException;
 import 
org.apache.fineract.infrastructure.core.exception.IdempotentCommandProcessUnderProcessingException;
@@ -174,23 +172,21 @@ public class SynchronousCommandProcessingService 
implements CommandProcessingSer
     }
 
     private void exceptionWhenTheRequestAlreadyProcessed(CommandWrapper 
wrapper, String idempotencyKey, boolean retry) {
-        CommandSource existingCommand = 
commandSourceService.findCommandSource(wrapper, idempotencyKey);
-        if (existingCommand != null) {
-            idempotentExceptionByStatus(UNDER_PROCESSING, existingCommand,
-                    command -> new 
IdempotentCommandProcessUnderProcessingException(wrapper));
-            if (!retry) {
-                idempotentExceptionByStatus(ERROR, existingCommand,
-                        command -> new 
IdempotentCommandProcessFailedException(wrapper, command));
-            }
-            idempotentExceptionByStatus(PROCESSED, existingCommand,
-                    command -> new 
IdempotentCommandProcessSucceedException(wrapper, command.getResult(), 
command.getResultStatusCode()));
+        CommandSource command = 
commandSourceService.findCommandSource(wrapper, idempotencyKey);
+        if (command == null) {
+            return;
         }
-    }
-
-    private void idempotentExceptionByStatus(CommandProcessingResultType 
status, CommandSource command,
-            Function<CommandSource, AbstractIdempotentCommandException> 
exceptionMapper) {
-        if (status.getValue().equals(command.getStatus())) {
-            throw exceptionMapper.apply(command);
+        CommandProcessingResultType status = 
CommandProcessingResultType.fromInt(command.getStatus());
+        switch (status) {
+            case UNDER_PROCESSING -> throw new 
IdempotentCommandProcessUnderProcessingException(wrapper, idempotencyKey);
+            case PROCESSED -> throw new 
IdempotentCommandProcessSucceedException(wrapper, idempotencyKey, command);
+            case ERROR -> {
+                if (!retry) {
+                    throw new IdempotentCommandProcessFailedException(wrapper, 
idempotencyKey, command);
+                }
+            }
+            default -> {
+            }
         }
     }
 
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java
index e2ed84968..259f8dfd4 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java
@@ -23,6 +23,7 @@ import static org.apache.http.HttpStatus.SC_BAD_REQUEST;
 import static org.apache.http.HttpStatus.SC_CONFLICT;
 import static org.apache.http.HttpStatus.SC_FORBIDDEN;
 import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
+import static org.apache.http.HttpStatus.SC_LOCKED;
 import static org.apache.http.HttpStatus.SC_METHOD_NOT_ALLOWED;
 import static org.apache.http.HttpStatus.SC_NOT_FOUND;
 import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE;
@@ -106,7 +107,7 @@ public class ApiGlobalErrorResponse {
         return create(SC_CONFLICT, "error.msg.loan.locked", msg, msg);
     }
 
-    public static ApiGlobalErrorResponse conflict(String type, String 
identifier) {
+    public static ApiGlobalErrorResponse locked(String type, String 
identifier) {
         String details = "";
         if (type == null) {
             type = "unknown";
@@ -117,7 +118,7 @@ public class ApiGlobalErrorResponse {
             details += " [" + identifier + ']';
         }
         String msg = "The server is currently unable to handle the request due 
to concurrent modification" + details + ", please try again";
-        return create(SC_CONFLICT, "error.msg.platform.service." + type + 
".conflict", msg, msg);
+        return create(SC_LOCKED, "error.msg.platform.service." + type + 
".conflict", msg, msg);
     }
 
     public static ApiGlobalErrorResponse unAuthorized(final String 
defaultUserMessage) {
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java
index a08b2d9b9..0ea52b8fb 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java
@@ -18,6 +18,9 @@
  */
 package org.apache.fineract.infrastructure.core.exception;
 
+import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
+
+import jakarta.validation.constraints.NotNull;
 import org.apache.fineract.commands.domain.CommandSource;
 import org.apache.fineract.commands.domain.CommandWrapper;
 
@@ -28,16 +31,14 @@ public class IdempotentCommandProcessFailedException 
extends AbstractIdempotentC
 
     private final Integer statusCode;
 
-    public IdempotentCommandProcessFailedException(CommandWrapper wrapper, 
CommandSource commandSource) {
-        super(wrapper.actionName(), wrapper.entityName(), 
wrapper.getIdempotencyKey(), commandSource.getResult());
-        this.statusCode = commandSource.getResultStatusCode();
+    public IdempotentCommandProcessFailedException(CommandWrapper wrapper, 
String idempotencyKey, CommandSource command) {
+        super(wrapper.actionName(), wrapper.actionName(), idempotencyKey, 
command.getResult());
+        this.statusCode = command.getResultStatusCode();
     }
 
+    @NotNull
     public Integer getStatusCode() {
         // If the database inconsistent we return http 500 instead of null 
pointer exception
-        if (statusCode == null) {
-            return 500;
-        }
-        return statusCode;
+        return statusCode == null ? SC_INTERNAL_SERVER_ERROR : statusCode;
     }
 }
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessSucceedException.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessSucceedException.java
index d7437275b..0542b8b0d 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessSucceedException.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessSucceedException.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.infrastructure.core.exception;
 
+import org.apache.fineract.commands.domain.CommandSource;
 import org.apache.fineract.commands.domain.CommandWrapper;
 
 /**
@@ -27,9 +28,9 @@ public class IdempotentCommandProcessSucceedException extends 
AbstractIdempotent
 
     private final Integer statusCode;
 
-    public IdempotentCommandProcessSucceedException(CommandWrapper wrapper, 
String response, Integer statusCode) {
-        super(wrapper.actionName(), wrapper.entityName(), 
wrapper.getIdempotencyKey(), response);
-        this.statusCode = statusCode;
+    public IdempotentCommandProcessSucceedException(CommandWrapper wrapper, 
String idempotencyKey, CommandSource command) {
+        super(wrapper.actionName(), wrapper.entityName(), idempotencyKey, 
command.getResult());
+        this.statusCode = command.getResultStatusCode();
     }
 
     public Integer getStatusCode() {
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessUnderProcessingException.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessUnderProcessingException.java
index 4e6b3f611..7e608e4be 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessUnderProcessingException.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessUnderProcessingException.java
@@ -25,7 +25,7 @@ import org.apache.fineract.commands.domain.CommandWrapper;
  */
 public class IdempotentCommandProcessUnderProcessingException extends 
AbstractIdempotentCommandException {
 
-    public IdempotentCommandProcessUnderProcessingException(CommandWrapper 
wrapper) {
-        super(wrapper.actionName(), wrapper.entityName(), 
wrapper.getIdempotencyKey(), wrapper.getJson());
+    public IdempotentCommandProcessUnderProcessingException(CommandWrapper 
wrapper, String idempotencyKey) {
+        super(wrapper.actionName(), wrapper.entityName(), idempotencyKey, 
wrapper.getJson());
     }
 }
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/ConcurrencyFailureExceptionMapper.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/ConcurrencyFailureExceptionMapper.java
index 41d7b6d85..665a3ef33 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/ConcurrencyFailureExceptionMapper.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/ConcurrencyFailureExceptionMapper.java
@@ -18,9 +18,10 @@
  */
 package org.apache.fineract.infrastructure.core.exceptionmapper;
 
+import static org.apache.http.HttpStatus.SC_LOCKED;
+
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Response.Status;
 import jakarta.ws.rs.ext.ExceptionMapper;
 import jakarta.ws.rs.ext.Provider;
 import lombok.extern.slf4j.Slf4j;
@@ -49,8 +50,8 @@ public class ConcurrencyFailureExceptionMapper implements 
FineractExceptionMappe
             type = olex.getPersistentClassName();
             identifier = olex.getIdentifier() == null ? null : 
String.valueOf(olex.getIdentifier());
         }
-        final ApiGlobalErrorResponse dataIntegrityError = 
ApiGlobalErrorResponse.conflict(type, identifier);
-        return 
Response.status(Status.CONFLICT).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build();
+        final ApiGlobalErrorResponse dataIntegrityError = 
ApiGlobalErrorResponse.locked(type, identifier);
+        return 
Response.status(SC_LOCKED).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build();
     }
 
     @Override
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/IdempotentCommandExceptionMapper.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/IdempotentCommandExceptionMapper.java
index 5bc1846d3..4facc0976 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/IdempotentCommandExceptionMapper.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/IdempotentCommandExceptionMapper.java
@@ -48,8 +48,10 @@ public class IdempotentCommandExceptionMapper implements 
FineractExceptionMapper
         log.warn("Processing {} request: {}", exception.getClass().getName(), 
exception.getMessage());
         Status status = null;
         if (exception instanceof IdempotentCommandProcessSucceedException pse) 
{
-            status = Status.fromStatusCode(pse.getStatusCode());
-        } else if (exception instanceof 
IdempotentCommandProcessUnderProcessingException) {
+            Integer statusCode = pse.getStatusCode();
+            status = statusCode == null ? Status.OK : 
Status.fromStatusCode(statusCode);
+        }
+        if (exception instanceof 
IdempotentCommandProcessUnderProcessingException) {
             status = Status.CONFLICT;
         } else if (exception instanceof 
IdempotentCommandProcessFailedException pfe) {
             status = Status.fromStatusCode(pfe.getStatusCode());
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/OptimisticLockExceptionMapper.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/OptimisticLockExceptionMapper.java
index 5b1ee011a..b4af9e3ff 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/OptimisticLockExceptionMapper.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/OptimisticLockExceptionMapper.java
@@ -18,9 +18,10 @@
  */
 package org.apache.fineract.infrastructure.core.exceptionmapper;
 
+import static org.apache.http.HttpStatus.SC_LOCKED;
+
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Response.Status;
 import jakarta.ws.rs.ext.ExceptionMapper;
 import jakarta.ws.rs.ext.Provider;
 import lombok.extern.slf4j.Slf4j;
@@ -45,8 +46,8 @@ public class OptimisticLockExceptionMapper implements 
FineractExceptionMapper, E
         log.warn("Exception: {}, Message: {}", exception.getClass().getName(), 
exception.getMessage());
         String type = exception.getQuery() == null ? "unknown" : "query";
         String identifier = "unknown";
-        final ApiGlobalErrorResponse dataIntegrityError = 
ApiGlobalErrorResponse.conflict(type, identifier);
-        return 
Response.status(Status.CONFLICT).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build();
+        final ApiGlobalErrorResponse dataIntegrityError = 
ApiGlobalErrorResponse.locked(type, identifier);
+        return 
Response.status(SC_LOCKED).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build();
     }
 
     @Override
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 dc7ab739a..91e4095a1 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
@@ -54,7 +54,7 @@ public class IdempotencyCommandProcessFailedExceptionTest {
         CommandWrapper command = new CommandWrapper(null, null, null, null, 
null, null, null, null, null, null, null, null, null, null,
                 null, null, null, null);
         CommandSource source = CommandSource.fullEntryFrom(command, 
JsonCommand.from("{}"), null, "dummy-key", null);
-        IdempotentCommandProcessFailedException exception = new 
IdempotentCommandProcessFailedException(command, source);
+        IdempotentCommandProcessFailedException exception = new 
IdempotentCommandProcessFailedException(command, null, source);
         Response result = mapper.toResponse(exception);
         assertEquals(500, result.getStatus());
         assertEquals("true", result.getHeaderString(IDEMPOTENT_CACHE_HEADER));
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java
 
b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java
index c6f69a0b4..b37c7d749 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java
@@ -48,27 +48,17 @@ public class CreateDatatableEntryCommandStrategy implements 
CommandStrategy {
 
     @Override
     public BatchResponse execute(BatchRequest request, 
@SuppressWarnings("unused") UriInfo uriInfo) {
-
-        final BatchResponse response = new BatchResponse();
-        final String responseBody;
-
-        response.setRequestId(request.getRequestId());
-        response.setHeaders(request.getHeaders());
-
         final List<String> pathParameters = 
Splitter.on('/').splitToList(relativeUrlWithoutVersion(request));
         // Pluck out the datatable name & loanId out of the relative path
         final String datatableName = pathParameters.get(1);
         final Long loanId = Long.parseLong(pathParameters.get(2));
 
-        // Calls 'createDatatableEntry' function from
-        // 'DatatablesApiResource' to create a datatable entry on an existing 
loan
-        responseBody = 
datatablesApiResource.createDatatableEntry(datatableName, loanId, 
request.getBody());
-
-        response.setStatusCode(HttpStatus.SC_OK);
-        // Sets the body of the response after datatable entry is successfully
-        // created
-        response.setBody(responseBody);
+        // Calls 'createDatatableEntry' function from 'DatatablesApiResource' 
to create a datatable entry on an existing
+        // loan
+        final String responseBody = 
datatablesApiResource.createDatatableEntry(datatableName, loanId, 
request.getBody());
 
-        return response;
+        // Create the response after datatable entry is successfully created
+        return new 
BatchResponse().setRequestId(request.getRequestId()).setStatusCode(HttpStatus.SC_OK).setBody(responseBody)
+                .setHeaders(request.getHeaders());
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
index a5ccb9331..2ff1f24f0 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
@@ -1587,13 +1587,13 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
         if (!rs.next()) {
             throw new DatatableNotFoundException(entityTable, appTableId);
         }
-        final Long officeId = rs.getLong("officeId");
-        final Long groupId = rs.getLong("groupId");
-        final Long clientId = rs.getLong("clientId");
-        final Long savingsId = rs.getLong("savingsId");
-        final Long loanId = rs.getLong("loanId");
-        final Long transactionId = rs.getLong("transactionId");
-        final Long entityId = rs.getLong("entityId");
+        final Long officeId = (Long) rs.getObject("officeId");
+        final Long groupId = (Long) rs.getObject("groupId");
+        final Long clientId = (Long) rs.getObject("clientId");
+        final Long savingsId = (Long) rs.getObject("savingsId");
+        final Long loanId = (Long) rs.getObject("loanId");
+        final Long transactionId = (Long) rs.getObject("transactionId");
+        final Long entityId = (Long) rs.getObject("entityId");
 
         if (rs.next()) {
             throw new DatatableSystemErrorException("System Error: More than 
one row returned from data scoping query");
@@ -1604,7 +1604,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 .withGroupId(groupId) //
                 .withClientId(clientId) //
                 .withSavingsId(savingsId) //
-                
.withLoanId(loanId).withTransactionId(String.valueOf(transactionId)).withEntityId(entityId)//
+                .withLoanId(loanId).withTransactionId(transactionId == null ? 
null : String.valueOf(transactionId)).withEntityId(entityId)//
                 .build();
     }
 
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 057b19335..6523a6eba 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
@@ -20,8 +20,8 @@ package org.apache.fineract.integrationtests;
 
 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;
 import static org.apache.http.HttpStatus.SC_FORBIDDEN;
+import static org.apache.http.HttpStatus.SC_LOCKED;
 import static org.apache.http.HttpStatus.SC_OK;
 import static org.hamcrest.Matchers.anyOf;
 import static org.hamcrest.Matchers.is;
@@ -95,7 +95,7 @@ public class SavingsAccountTransactionTest {
         this.requestSpec = new 
RequestSpecBuilder().setContentType(ContentType.JSON).build();
         this.requestSpec.header("Authorization", "Basic " + 
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
         this.responseSpec = new 
ResponseSpecBuilder().expectStatusCode(SC_OK).build();
-        this.concurrentResponseSpec = new 
ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), 
is(SC_CONFLICT))).build();
+        this.concurrentResponseSpec = new 
ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), is(SC_LOCKED))).build();
         this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
         this.savingsProductHelper = new SavingsProductHelper();
         this.datatableHelper = new DatatableHelper(this.requestSpec, 
this.responseSpec);
@@ -189,7 +189,7 @@ public class SavingsAccountTransactionTest {
 
         SavingsAccountHelper batchWithTransactionHelper = new 
SavingsAccountHelper(requestSpec, concurrentResponseSpec);
         SavingsAccountHelper batchWithoutTransactionHelper = new 
SavingsAccountHelper(requestSpec,
-                new ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), 
is(SC_CONFLICT), is(SC_FORBIDDEN))).build());
+                new ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), 
is(SC_LOCKED), is(SC_FORBIDDEN))).build());
         String transactionDate = SavingsAccountHelper.TRANSACTION_DATE;
         String transactionAmount = "10";
         ExecutorService executor = Executors.newFixedThreadPool(30);
@@ -322,7 +322,7 @@ public class SavingsAccountTransactionTest {
                 if (enclosingTransaction) {
                     Integer statusCode1 = responses.get(0).getStatusCode();
                     assertNotNull(statusCode1);
-                    assertTrue(SC_OK == statusCode1 || SC_CONFLICT == 
statusCode1);
+                    assertTrue(SC_OK == statusCode1 || SC_LOCKED == 
statusCode1);
                     if (SC_OK == statusCode1) {
                         assertEquals(4, responses.size());
                         Integer statusCode4 = responses.get(3).getStatusCode();
@@ -335,10 +335,10 @@ public class SavingsAccountTransactionTest {
                     assertEquals(4, responses.size());
                     Integer statusCode1 = responses.get(0).getStatusCode();
                     assertNotNull(statusCode1);
-                    assertTrue(SC_OK == statusCode1 || SC_CONFLICT == 
statusCode1);
+                    assertTrue(SC_OK == statusCode1 || SC_LOCKED == 
statusCode1);
                     Integer statusCode4 = responses.get(3).getStatusCode();
                     assertNotNull(statusCode4);
-                    assertTrue(SC_OK == statusCode1 ? (SC_OK == statusCode4 || 
SC_CONFLICT == statusCode4) : SC_FORBIDDEN == statusCode4);
+                    assertTrue(SC_OK == statusCode1 ? (SC_OK == statusCode4 || 
SC_LOCKED == statusCode4) : SC_FORBIDDEN == statusCode4);
                 }
             } else {
                 String json = transactionData.getJson();
@@ -359,7 +359,7 @@ public class SavingsAccountTransactionTest {
                 assertNotNull(res.get(CommonConstants.RESPONSE_RESOURCE_ID));
                 return true;
             }
-            assertEquals(String.valueOf(SC_CONFLICT), statusCode);
+            assertEquals(String.valueOf(SC_LOCKED), statusCode);
             return false;
         }
     }

Reply via email to