You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2022/07/13 19:50:47 UTC
[fineract] branch develop updated: Batch API extensions and a couple of OpenAPI fixes + minor datatable fixes
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 8c023e74a Batch API extensions and a couple of OpenAPI fixes + minor datatable fixes
8c023e74a is described below
commit 8c023e74a8f070294f40db7708a9d479554564e6
Author: Arnold Galovics <ga...@gmail.com>
AuthorDate: Wed Jul 13 08:58:40 2022 +0200
Batch API extensions and a couple of OpenAPI fixes + minor datatable fixes
---
.../java/org/apache/fineract/client/util/JSON.java | 6 +
.../api/GLAccountsApiResourceSwagger.java | 2 +-
.../batch/command/CommandStrategyProvider.java | 10 +-
.../internal/ActivateClientCommandStrategy.java | 29 +-
.../command/internal/ApplyLoanCommandStrategy.java | 27 +-
.../internal/ApplySavingsCommandStrategy.java | 31 +--
.../internal/ApproveLoanCommandStrategy.java | 29 +-
.../ApproveLoanRescheduleCommandStrategy.java | 31 +--
.../internal/CollectChargesCommandStrategy.java | 31 +--
.../internal/CreateChargeCommandStrategy.java | 31 +--
.../internal/CreateClientCommandStrategy.java | 29 +-
...a => CreateTransactionLoanCommandStrategy.java} | 47 ++--
.../internal/DisburseLoanCommandStrategy.java | 29 +-
...tDatatableEntryByAppTableIdCommandStrategy.java | 93 +++++++
.../internal/GetLoanByIdCommandStrategy.java | 96 +++----
.../GetTransactionByIdCommandStrategy.java | 24 +-
.../internal/UpdateClientCommandStrategy.java | 29 +-
.../batch/service/BatchApiServiceImpl.java | 31 ++-
.../codes/api/CodeValuesApiResourceSwagger.java | 2 +
.../api/GlobalConfigurationApiResource.java | 3 +-
.../data/ResultsetColumnHeaderData.java | 4 +
.../service/ReadWriteNonCoreDataServiceImpl.java | 8 +-
.../api/LoanProductsApiResourceSwagger.java | 22 +-
.../batch/command/CommandStrategyProviderTest.java | 20 +-
.../CreateTransactionLoanCommandStrategyTest.java | 119 +++++++++
...atableEntryByAppTableIdCommandStrategyTest.java | 160 +++++++++++
.../internal/GetLoanByIdCommandStrategyTest.java | 60 -----
.../GetTransactionByIdCommandStrategyTest.java | 93 -------
.../fineract/integrationtests/BatchApiTest.java | 292 +++++++++++++++++++--
.../integrationtests/common/BatchHelper.java | 215 +++++++++++++--
30 files changed, 1079 insertions(+), 524 deletions(-)
diff --git a/fineract-client/src/main/java/org/apache/fineract/client/util/JSON.java b/fineract-client/src/main/java/org/apache/fineract/client/util/JSON.java
index de7611f16..c478a7bb5 100644
--- a/fineract-client/src/main/java/org/apache/fineract/client/util/JSON.java
+++ b/fineract-client/src/main/java/org/apache/fineract/client/util/JSON.java
@@ -120,6 +120,12 @@ public class JSON {
case NULL:
in.nextNull();
return null;
+ case STRING:
+ String dateString = in.nextString();
+ if (dateString != null && dateString.length() != 0) {
+ return LocalDate.parse(dateString);
+ }
+ return null;
case BEGIN_ARRAY:
in.beginArray();
int year = in.nextInt();
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/api/GLAccountsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/api/GLAccountsApiResourceSwagger.java
index 7a1d54236..34c85fe2e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/api/GLAccountsApiResourceSwagger.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/api/GLAccountsApiResourceSwagger.java
@@ -129,7 +129,7 @@ final class GLAccountsApiResourceSwagger {
public Long parentId;
@Schema(example = "1")
- public EnumOptionData usage;
+ public String usage;
@Schema(example = "Desc")
public String description;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java
index d14afd0d7..634450304 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java
@@ -92,7 +92,10 @@ public class CommandStrategyProvider {
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges").method("GET").build(),
"collectChargesCommandStrategy");
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/transactions\\?command=repayment").method("POST").build(),
- "repayLoanCommandStrategy");
+ "createTransactionLoanCommandStrategy");
+ this.commandStrategies.put(
+ CommandContext.resource("loans\\/\\d+\\/transactions\\?command=creditBalanceRefund").method("POST").build(),
+ "createTransactionLoanCommandStrategy");
this.commandStrategies.put(CommandContext.resource("clients\\/\\d+\\?command=activate").method("POST").build(),
"activateClientCommandStrategy");
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\?command=approve").method("POST").build(),
@@ -103,6 +106,11 @@ public class CommandStrategyProvider {
"approveLoanRescheduleCommandStrategy");
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/transactions\\/\\d+").method("GET").build(),
"getTransactionByIdCommandStrategy");
+ this.commandStrategies.put(CommandContext.resource("datatables\\/[a-zA-Z0-9_]*\\/\\d+").method("GET").build(),
+ "getDatatableEntryByAppTableIdCommandStrategy");
+ this.commandStrategies.put(
+ CommandContext.resource("datatables\\/[a-zA-Z0-9_]*\\/\\d+(\\?(\\w+(?:\\=[\\w,]+|&)+)+)").method("GET").build(),
+ "getDatatableEntryByAppTableIdCommandStrategy");
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ActivateClientCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ActivateClientCommandStrategy.java
index d5601e06f..20ab7e3ea 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ActivateClientCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ActivateClientCommandStrategy.java
@@ -25,8 +25,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.client.api.ClientsApiResource;
import org.springframework.stereotype.Component;
@@ -61,27 +59,14 @@ public class ActivateClientCommandStrategy implements CommandStrategy {
final List<String> pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl());
Long clientId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?")));
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'activate' function from 'ClientsApiResource' to activate a
+ // client
+ responseBody = clientsApiResource.activate(clientId, "activate", request.getBody());
- // Calls 'activate' function from 'ClientsApiResource' to activate a
- // client
- responseBody = clientsApiResource.activate(clientId, "activate", request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after the successful activation of
- // the client
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after the successful activation of
+ // the client
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApplyLoanCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApplyLoanCommandStrategy.java
index 0a0d45cea..c6e9639b5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApplyLoanCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApplyLoanCommandStrategy.java
@@ -23,8 +23,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource;
import org.springframework.stereotype.Component;
@@ -56,26 +54,13 @@ public class ApplyLoanCommandStrategy implements CommandStrategy {
response.setRequestId(request.getRequestId());
response.setHeaders(request.getHeaders());
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'SubmitLoanFunction' function from 'LoansApiResource' to
+ // Apply Loan to an existing client
+ responseBody = loansApiResource.calculateLoanScheduleOrSubmitLoanApplication(null, null, request.getBody());
- // Calls 'SubmitLoanFunction' function from 'LoansApiResource' to
- // Apply Loan to an existing client
- responseBody = loansApiResource.calculateLoanScheduleOrSubmitLoanApplication(null, null, request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after loan is successfully applied
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after loan is successfully applied
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApplySavingsCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApplySavingsCommandStrategy.java
index 32359c81f..a5c2a914f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApplySavingsCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApplySavingsCommandStrategy.java
@@ -23,8 +23,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.savings.api.SavingsAccountsApiResource;
import org.springframework.stereotype.Component;
@@ -56,28 +54,15 @@ public class ApplySavingsCommandStrategy implements CommandStrategy {
response.setRequestId(request.getRequestId());
response.setHeaders(request.getHeaders());
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'submitApplication' function from
+ // 'SavingsAccountsApiResource' to Apply Savings to an existing
+ // client
+ responseBody = savingsAccountsApiResource.submitApplication(request.getBody());
- // Calls 'submitApplication' function from
- // 'SavingsAccountsApiResource' to Apply Savings to an existing
- // client
- responseBody = savingsAccountsApiResource.submitApplication(request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after savings is successfully
- // applied
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after savings is successfully
+ // applied
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApproveLoanCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApproveLoanCommandStrategy.java
index 26dac2941..c517e4119 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApproveLoanCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApproveLoanCommandStrategy.java
@@ -25,8 +25,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource;
import org.springframework.stereotype.Component;
@@ -61,27 +59,14 @@ public class ApproveLoanCommandStrategy implements CommandStrategy {
final List<String> pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl());
Long loanId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?")));
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'approve' function from 'LoansApiResource' to approve a
+ // loan
+ responseBody = loansApiResource.stateTransitions(loanId, "approve", request.getBody());
- // Calls 'approve' function from 'LoansApiResource' to approve a
- // loan
- responseBody = loansApiResource.stateTransitions(loanId, "approve", request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after the successful approval of a
- // loan
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after the successful approval of a
+ // loan
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApproveLoanRescheduleCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApproveLoanRescheduleCommandStrategy.java
index 4220f9c13..15748e7da 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApproveLoanRescheduleCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ApproveLoanRescheduleCommandStrategy.java
@@ -25,8 +25,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.api.RescheduleLoansApiResource;
import org.springframework.stereotype.Component;
@@ -47,28 +45,15 @@ public class ApproveLoanRescheduleCommandStrategy implements CommandStrategy {
final List<String> pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl());
Long scheduleId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?")));
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'approve' function from 'Loans reschedule Request' to
+ // approve a
+ // loan
+ responseBody = rescheduleLoansApiResource.updateLoanRescheduleRequest(scheduleId, "approve", request.getBody());
- // Calls 'approve' function from 'Loans reschedule Request' to
- // approve a
- // loan
- responseBody = rescheduleLoansApiResource.updateLoanRescheduleRequest(scheduleId, "approve", request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after the successful approval of a
- // Loans reschedule Request
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after the successful approval of a
+ // Loans reschedule Request
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CollectChargesCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CollectChargesCommandStrategy.java
index 9d516cb7d..593ed0c69 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CollectChargesCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CollectChargesCommandStrategy.java
@@ -25,8 +25,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource;
import org.springframework.stereotype.Component;
@@ -63,28 +61,15 @@ public class CollectChargesCommandStrategy implements CommandStrategy {
// Pluck out the loanId out of the relative path
Long loanId = Long.parseLong(pathParameters.get(1));
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'retrieveAllLoanCharges' function from
+ // 'LoanChargesApiResource' to Collect
+ // Charges for a loan
+ responseBody = loanChargesApiResource.retrieveAllLoanCharges(loanId, uriInfo);
- // Calls 'retrieveAllLoanCharges' function from
- // 'LoanChargesApiResource' to Collect
- // Charges for a loan
- responseBody = loanChargesApiResource.retrieveAllLoanCharges(loanId, uriInfo);
-
- response.setStatusCode(200);
- // Sets the body of the response after Charges have been
- // successfully collected
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after Charges have been
+ // successfully collected
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateChargeCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateChargeCommandStrategy.java
index 0edc2b9a8..7e7be136e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateChargeCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateChargeCommandStrategy.java
@@ -25,8 +25,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource;
import org.springframework.stereotype.Component;
@@ -61,28 +59,15 @@ public class CreateChargeCommandStrategy implements CommandStrategy {
final List<String> pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl());
Long loanId = Long.parseLong(pathParameters.get(1));
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'executeLoanCharge' function from 'LoanChargesApiResource'
+ // to create
+ // a new charge for a loan
+ responseBody = loanChargesApiResource.executeLoanCharge(loanId, null, request.getBody());
- // Calls 'executeLoanCharge' function from 'LoanChargesApiResource'
- // to create
- // a new charge for a loan
- responseBody = loanChargesApiResource.executeLoanCharge(loanId, null, request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after Charge has been successfully
- // created
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after Charge has been successfully
+ // created
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateClientCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateClientCommandStrategy.java
index 3020a2f20..fc0d71757 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateClientCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateClientCommandStrategy.java
@@ -23,8 +23,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.client.api.ClientsApiResource;
import org.springframework.stereotype.Component;
@@ -56,27 +54,14 @@ public class CreateClientCommandStrategy implements CommandStrategy {
response.setRequestId(request.getRequestId());
response.setHeaders(request.getHeaders());
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'create' function from 'ClientsApiResource' to create a new
+ // client
+ responseBody = clientsApiResource.create(request.getBody());
- // Calls 'create' function from 'ClientsApiResource' to create a new
- // client
- responseBody = clientsApiResource.create(request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after the successful creation of
- // the client
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after the successful creation of
+ // the client
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/RepayLoanCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java
similarity index 56%
rename from fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/RepayLoanCommandStrategy.java
rename to fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java
index c91269cf7..a192b2624 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/RepayLoanCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java
@@ -20,20 +20,22 @@ package org.apache.fineract.batch.command.internal;
import com.google.common.base.Splitter;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.ws.rs.core.UriInfo;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionsApiResource;
+import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
/**
- * Implements {@link CommandStrategy} and handles repayment for a Loan. It passes the contents of the body from the
- * BatchRequest to {@link LoanTransactionsApiResource} and gets back the response. This class will also catch any errors
- * raised by {@link LoanTransactionsApiResource} and map those errors to appropriate status codes in BatchResponse.
+ * Implements {@link CommandStrategy} and handles the creation of a transaction for a Loan. It passes the contents of
+ * the body from the BatchRequest to {@link LoanTransactionsApiResource} and gets back the response. This class will
+ * also catch any errors raised by {@link LoanTransactionsApiResource} and map those errors to appropriate status codes
+ * in BatchResponse.
*
* @author Mohit Sinha
*
@@ -43,7 +45,7 @@ import org.springframework.stereotype.Component;
*/
@Component
@RequiredArgsConstructor
-public class RepayLoanCommandStrategy implements CommandStrategy {
+public class CreateTransactionLoanCommandStrategy implements CommandStrategy {
private final LoanTransactionsApiResource loanTransactionsApiResource;
@@ -59,25 +61,26 @@ public class RepayLoanCommandStrategy implements CommandStrategy {
final List<String> pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl());
Long loanId = Long.parseLong(pathParameters.get(1));
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+");
+ Matcher commandMatcher = commandPattern.matcher(pathParameters.get(2));
- responseBody = loanTransactionsApiResource.executeLoanTransaction(loanId, "repayment", request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after Charge has been successfully
- // created
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
+ if (!commandMatcher.find()) {
+ // This would only occur if the CommandStrategyProvider is incorrectly configured.
+ response.setRequestId(request.getRequestId());
+ response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
+ response.setBody(
+ "Resource with method " + request.getMethod() + " and relativeUrl " + request.getRelativeUrl() + " doesn't exist");
+ return response;
+ }
+ String commandQueryParam = commandMatcher.group(0);
+ String command = commandQueryParam.substring(commandQueryParam.indexOf("=") + 1);
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
+ responseBody = loanTransactionsApiResource.executeLoanTransaction(loanId, command, request.getBody());
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after Charge has been successfully
+ // created
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/DisburseLoanCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/DisburseLoanCommandStrategy.java
index e4244be90..cffd07bd2 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/DisburseLoanCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/DisburseLoanCommandStrategy.java
@@ -25,8 +25,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource;
import org.springframework.stereotype.Component;
@@ -61,28 +59,15 @@ public class DisburseLoanCommandStrategy implements CommandStrategy {
final List<String> pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl());
Long loanId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?")));
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'disburse' function from 'LoansApiResource' to disburse a
+ // loan
+ responseBody = loansApiResource.stateTransitions(loanId, "disburse", request.getBody());
- // Calls 'disburse' function from 'LoansApiResource' to disburse a
- // loan
- responseBody = loansApiResource.stateTransitions(loanId, "disburse", request.getBody());
+ response.setStatusCode(200);
- response.setStatusCode(200);
-
- // Sets the body of the response after the successful disbursal of
- // the loan
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ // Sets the body of the response after the successful disbursal of
+ // the loan
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByAppTableIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByAppTableIdCommandStrategy.java
new file mode 100644
index 000000000..58c8e5b5c
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByAppTableIdCommandStrategy.java
@@ -0,0 +1,93 @@
+/**
+ * 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.batch.command.internal;
+
+import java.util.Map;
+import javax.ws.rs.core.UriInfo;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.fineract.batch.command.CommandStrategy;
+import org.apache.fineract.batch.command.CommandStrategyUtils;
+import org.apache.fineract.batch.domain.BatchRequest;
+import org.apache.fineract.batch.domain.BatchResponse;
+import org.apache.fineract.infrastructure.core.api.MutableUriInfo;
+import org.apache.fineract.infrastructure.dataqueries.api.DatatablesApiResource;
+import org.apache.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+/**
+ * Implements {@link CommandStrategy} and get datatable by appTableId. It passes the contents of the body from the
+ * BatchRequest to {@link DatatablesApiResource} and gets back the response. This class will also catch any errors
+ * raised by {@link DatatablesApiResource} and map those errors to appropriate status codes in BatchResponse.
+ */
+@Component
+@RequiredArgsConstructor
+public class GetDatatableEntryByAppTableIdCommandStrategy implements CommandStrategy {
+
+ /**
+ * Data table api resource {@link DatatablesApiResource}.
+ */
+ private final DatatablesApiResource dataTablesApiResource;
+
+ @Override
+ public BatchResponse execute(final BatchRequest request, @SuppressWarnings("unused") UriInfo uriInfo) {
+ final MutableUriInfo parameterizedUriInfo = new MutableUriInfo(uriInfo);
+ final BatchResponse response = new BatchResponse();
+ final String responseBody;
+
+ response.setRequestId(request.getRequestId());
+ response.setHeaders(request.getHeaders());
+
+ final String relativeUrl = request.getRelativeUrl();
+ final String relativeUrlSubString = StringUtils.substringAfter(relativeUrl, "/");
+
+ // uriInfo will contain the query parameter value(s) that are sent in the actual batch uri.
+ // for example: batches?enclosingTransaction=true
+ // But the query parameters that are sent in the batch relative url has to be sent to
+ // datatablesApiResource.getDatatable
+ // To use the relative url query parameters
+ // - Parse and fetch the query parameters sent in the relative url
+ // (datatables/dt_123/1?genericResultSet=true)
+ // - Add them to the MutableUriInfo query parameters list
+ // - Call datatablesApiResource.getDatatable(dataTable, appTableId, null, uriInfo)
+ long appTableId;
+ if (relativeUrl.indexOf('?') > 0) {
+ appTableId = Long.parseLong(StringUtils.substringBetween(relativeUrlSubString, "/", "?"));
+ Map<String, String> queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl);
+
+ // Add the query parameters sent in the relative URL to MutableUriInfo
+ CommandStrategyUtils.addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters);
+ } else {
+ appTableId = Long.parseLong(StringUtils.substringAfter(relativeUrlSubString, "/"));
+ }
+
+ String dataTableName = relativeUrlSubString.substring(0, relativeUrlSubString.indexOf("/"));
+
+ // Calls 'getDatatable' function from 'DatatablesApiResource' to
+ // get the datatable details based on the appTableId
+ responseBody = dataTablesApiResource.getDatatable(dataTableName, appTableId, null, parameterizedUriInfo);
+
+ response.setStatusCode(HttpStatus.SC_OK);
+
+ // Sets the response after retrieving the datatable
+ response.setBody(responseBody);
+
+ return response;
+ }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetLoanByIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetLoanByIdCommandStrategy.java
index 66781ec3a..15cea55f0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetLoanByIdCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetLoanByIdCommandStrategy.java
@@ -26,8 +26,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.infrastructure.core.api.MutableUriInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource;
import org.apache.http.HttpStatus;
@@ -60,64 +58,52 @@ public class GetLoanByIdCommandStrategy implements CommandStrategy {
final String relativeUrl = request.getRelativeUrl();
Long loanId;
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
- // uriInfo will contain the query parameter value(s) that are sent in the actual batch uri.
- // for example: batches?enclosingTransaction=true
- // But the query parameters that are sent in the batch relative url has to be sent to
- // LoansApiResource.retrieveLoan
- // To use the relative url query parameters
- // - Parse and fetch the query parameters sent in the relative url
- // (loans/66?fields=id,principal,annualInterestRate)
- // - Add them to the UriInfo query parameters list
- // - Call loansApiResource.retrieveLoan(loanId, false, uriInfo)
- // - Remove the relative url query parameters from UriInfo in the finally (after loan details are retrieved)
- Map<String, String> queryParameters = null;
- if (relativeUrl.indexOf('?') > 0) {
- loanId = Long.parseLong(StringUtils.substringBetween(relativeUrl, "/", "?"));
- queryParameters = getQueryParameters(relativeUrl);
-
- // Add the query parameters sent in the relative URL to UriInfo
- addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters);
- } else {
- loanId = Long.parseLong(StringUtils.substringAfter(relativeUrl, "/"));
- }
+ // uriInfo will contain the query parameter value(s) that are sent in the actual batch uri.
+ // for example: batches?enclosingTransaction=true
+ // But the query parameters that are sent in the batch relative url has to be sent to
+ // LoansApiResource.retrieveLoan
+ // To use the relative url query parameters
+ // - Parse and fetch the query parameters sent in the relative url
+ // (loans/66?fields=id,principal,annualInterestRate)
+ // - Add them to the UriInfo query parameters list
+ // - Call loansApiResource.retrieveLoan(loanId, false, uriInfo)
+ // - Remove the relative url query parameters from UriInfo in the finally (after loan details are retrieved)
+ Map<String, String> queryParameters = null;
+ if (relativeUrl.indexOf('?') > 0) {
+ loanId = Long.parseLong(StringUtils.substringBetween(relativeUrl, "/", "?"));
+ queryParameters = getQueryParameters(relativeUrl);
+
+ // Add the query parameters sent in the relative URL to UriInfo
+ addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters);
+ } else {
+ loanId = Long.parseLong(StringUtils.substringAfter(relativeUrl, "/"));
+ }
- // Calls 'retrieveLoan' function from 'LoansApiResource' to
- // get the loan details based on the loan id
- final boolean staffInSelectedOfficeOnly = false;
- String associations = null;
- String exclude = null;
- String fields = null;
- if (queryParameters != null && queryParameters.size() > 0) {
- if (queryParameters.containsKey("associations")) {
- associations = queryParameters.get("associations");
- }
- if (queryParameters.containsKey("exclude")) {
- exclude = queryParameters.get("exclude");
- }
- if (queryParameters.containsKey("fields")) {
- fields = queryParameters.get("fields");
- }
+ // Calls 'retrieveLoan' function from 'LoansApiResource' to
+ // get the loan details based on the loan id
+ final boolean staffInSelectedOfficeOnly = false;
+ String associations = null;
+ String exclude = null;
+ String fields = null;
+ if (queryParameters != null && queryParameters.size() > 0) {
+ if (queryParameters.containsKey("associations")) {
+ associations = queryParameters.get("associations");
}
+ if (queryParameters.containsKey("exclude")) {
+ exclude = queryParameters.get("exclude");
+ }
+ if (queryParameters.containsKey("fields")) {
+ fields = queryParameters.get("fields");
+ }
+ }
- responseBody = loansApiResource.retrieveLoan(loanId, staffInSelectedOfficeOnly, associations, exclude, fields,
- parameterizedUriInfo);
-
- response.setStatusCode(HttpStatus.SC_OK);
-
- // Sets the response after retrieving the loan
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
+ responseBody = loansApiResource.retrieveLoan(loanId, staffInSelectedOfficeOnly, associations, exclude, fields,
+ parameterizedUriInfo);
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
+ response.setStatusCode(HttpStatus.SC_OK);
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ // Sets the response after retrieving the loan
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java
index 3f7f22a89..bec9b431c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java
@@ -29,8 +29,6 @@ import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.command.CommandStrategyUtils;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.infrastructure.core.api.MutableUriInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionsApiResource;
import org.apache.http.HttpStatus;
@@ -88,25 +86,13 @@ public class GetTransactionByIdCommandStrategy implements CommandStrategy {
}
}
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
- // Calls 'retrieveTransaction' function from 'loanTransactionsApiResource'
- responseBody = loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, fields, uriInfo);
+ // Calls 'retrieveTransaction' function from 'loanTransactionsApiResource'
+ responseBody = loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, fields, uriInfo);
- response.setStatusCode(HttpStatus.SC_OK);
+ response.setStatusCode(HttpStatus.SC_OK);
- // Sets the body of the response after retrieving the transaction
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ // Sets the body of the response after retrieving the transaction
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/UpdateClientCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/UpdateClientCommandStrategy.java
index 2977ed58b..9d0e3aae7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/UpdateClientCommandStrategy.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/UpdateClientCommandStrategy.java
@@ -23,8 +23,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
-import org.apache.fineract.batch.exception.ErrorHandler;
-import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.portfolio.client.api.ClientsApiResource;
import org.springframework.stereotype.Component;
@@ -60,27 +58,14 @@ public class UpdateClientCommandStrategy implements CommandStrategy {
final String relativeUrl = request.getRelativeUrl();
final Long clientId = Long.parseLong(relativeUrl.substring(relativeUrl.indexOf('/') + 1));
- // Try-catch blocks to map exceptions to appropriate status codes
- try {
+ // Calls 'update' function from 'ClientsApiResource' to update a
+ // client
+ responseBody = clientsApiResource.update(clientId, request.getBody());
- // Calls 'update' function from 'ClientsApiResource' to update a
- // client
- responseBody = clientsApiResource.update(clientId, request.getBody());
-
- response.setStatusCode(200);
- // Sets the body of the response after the successful update of
- // client information
- response.setBody(responseBody);
-
- } catch (RuntimeException e) {
-
- // Gets an object of type ErrorInfo, containing information about
- // raised exception
- ErrorInfo ex = ErrorHandler.handler(e);
-
- response.setStatusCode(ex.getStatusCode());
- response.setBody(ex.getMessage());
- }
+ response.setStatusCode(200);
+ // Sets the body of the response after the successful update of
+ // client information
+ response.setBody(responseBody);
return response;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java
index 44ef98191..20502e3c1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java
@@ -27,6 +27,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.batch.command.CommandContext;
import org.apache.fineract.batch.command.CommandStrategy;
import org.apache.fineract.batch.command.CommandStrategyProvider;
@@ -55,6 +56,7 @@ import org.springframework.transaction.support.TransactionTemplate;
*/
@Service
@RequiredArgsConstructor
+@Slf4j
public class BatchApiServiceImpl implements BatchApiService {
private final CommandStrategyProvider strategyProvider;
@@ -86,24 +88,35 @@ public class BatchApiServiceImpl implements BatchApiService {
final BatchRequest rootRequest = rootNode.getRequest();
final CommandStrategy commandStrategy = this.strategyProvider
.getCommandStrategy(CommandContext.resource(rootRequest.getRelativeUrl()).method(rootRequest.getMethod()).build());
- final BatchResponse rootResponse = commandStrategy.execute(rootRequest, uriInfo);
+ final BatchResponse rootResponse = safelyExecuteStrategy(commandStrategy, rootRequest, uriInfo);
responseList.add(rootResponse);
responseList.addAll(this.processChildRequests(rootNode, rootResponse, uriInfo));
}
- Collections.sort(responseList, new Comparator<BatchResponse>() {
-
- @Override
- public int compare(BatchResponse source, BatchResponse testee) {
- return source.getRequestId().compareTo(testee.getRequestId());
- }
- });
+ Collections.sort(responseList, Comparator.comparing(BatchResponse::getRequestId));
return responseList;
}
+ private BatchResponse safelyExecuteStrategy(CommandStrategy commandStrategy, BatchRequest request, UriInfo uriInfo) {
+ try {
+ return commandStrategy.execute(request, uriInfo);
+ } catch (RuntimeException e) {
+ log.warn("Exception while executing batch strategy {}", commandStrategy.getClass().getSimpleName(), e);
+
+ ErrorInfo ex = ErrorHandler.handler(e);
+
+ final BatchResponse response = new BatchResponse();
+ response.setRequestId(request.getRequestId());
+ response.setHeaders(request.getHeaders());
+ response.setStatusCode(ex.getStatusCode());
+ response.setBody(ex.getMessage());
+ return response;
+ }
+ }
+
private List<BatchResponse> processChildRequests(final BatchRequestNode rootRequest, BatchResponse rootResponse, UriInfo uriInfo) {
final List<BatchResponse> childResponses = new ArrayList<>();
@@ -121,7 +134,7 @@ public class BatchApiServiceImpl implements BatchApiService {
final CommandStrategy commandStrategy = this.strategyProvider.getCommandStrategy(
CommandContext.resource(childRequest.getRelativeUrl()).method(childRequest.getMethod()).build());
- childResponse = commandStrategy.execute(childRequest, uriInfo);
+ childResponse = safelyExecuteStrategy(commandStrategy, childRequest, uriInfo);
} else {
// Something went wrong with the parent request, create
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodeValuesApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodeValuesApiResourceSwagger.java
index ee8e48af1..26df57634 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodeValuesApiResourceSwagger.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodeValuesApiResourceSwagger.java
@@ -55,6 +55,8 @@ final class CodeValuesApiResourceSwagger {
@Schema(example = "Passport")
public String name;
+ @Schema(example = "true")
+ public Boolean isActive;
@Schema(example = "Passport information")
public String description;
@Schema(example = "0")
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationApiResource.java
index 7d6fc0778..f26438d48 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationApiResource.java
@@ -20,7 +20,6 @@ package org.apache.fineract.infrastructure.configuration.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
@@ -103,7 +102,7 @@ public class GlobalConfigurationApiResource {
+ "Returns the list global enable/disable survey configurations.\n" + "\n" + "Example Requests:\n" + "\n"
+ "configurations/survey")
@ApiResponses({
- @ApiResponse(responseCode = "200", description = "List of example \\n response \\nsurveys response \\ngiven below", content = @Content(array = @ArraySchema(schema = @Schema(implementation = GlobalConfigurationApiResourceSwagger.GetGlobalConfigurationsResponse.class)))) })
+ @ApiResponse(responseCode = "200", description = "List of example \\n response \\nsurveys response \\ngiven below", content = @Content(schema = @Schema(implementation = GlobalConfigurationApiResourceSwagger.GetGlobalConfigurationsResponse.class))) })
public String retrieveConfiguration(@Context final UriInfo uriInfo,
@DefaultValue("false") @QueryParam("survey") @Parameter(description = "survey") final boolean survey) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ResultsetColumnHeaderData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ResultsetColumnHeaderData.java
index e318cd02d..7ae84bf38 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ResultsetColumnHeaderData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ResultsetColumnHeaderData.java
@@ -326,4 +326,8 @@ public final class ResultsetColumnHeaderData implements Serializable {
public String getColumnCode() {
return this.columnCode;
}
+
+ public List<ResultsetColumnValueData> getColumnValues() {
+ return this.columnValues;
+ }
}
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 cbae01e23..ca887a6b0 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
@@ -1652,7 +1652,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
pValueWrite = "null";
} else {
if ("bit".equalsIgnoreCase(pColumnHeader.getColumnType())) {
- pValueWrite = BooleanUtils.toString(BooleanUtils.toBooleanObject(pValue), "1", "0", "null");
+ if (databaseTypeResolver.isMySQL()) {
+ pValueWrite = BooleanUtils.toString(BooleanUtils.toBooleanObject(pValue), "1", "0", "null");
+ } else if (databaseTypeResolver.isPostgreSQL()) {
+ pValueWrite = BooleanUtils.toString(BooleanUtils.toBooleanObject(pValue), "B'1'", "B'0'", "null");
+ } else {
+ throw new IllegalStateException("Current database is not supported");
+ }
} else {
pValueWrite = singleQuote + this.genericDataService.replace(pValue, singleQuote, singleQuote + singleQuote)
+ singleQuote;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
index e786f9bad..3aa826ef5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
@@ -25,7 +25,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
-import org.apache.fineract.portfolio.rate.data.RateData;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
/**
* Created by Chirag Gupta on 12/27/17.
@@ -69,6 +69,26 @@ final class LoanProductsApiResourceSwagger {
public Integer id;
}
+ static final class RateData {
+
+ private RateData() {}
+
+ @Schema(example = "1")
+ public Long id;
+
+ @Schema(example = "some name")
+ public String name;
+
+ @Schema(example = "20")
+ public BigDecimal percentage;
+
+ @Schema(description = "Apply specific product using its id, code, and value.")
+ public EnumOptionData productApply;
+
+ @Schema(example = "false")
+ public boolean active;
+ }
+
@Schema(example = "LP Accrual Accounting")
public String name;
@Schema(example = "LPAA")
diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java
index 7ce584cd1..22e8811d8 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java
@@ -32,10 +32,11 @@ import org.apache.fineract.batch.command.internal.ApproveLoanRescheduleCommandSt
import org.apache.fineract.batch.command.internal.CollectChargesCommandStrategy;
import org.apache.fineract.batch.command.internal.CreateChargeCommandStrategy;
import org.apache.fineract.batch.command.internal.CreateClientCommandStrategy;
+import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy;
import org.apache.fineract.batch.command.internal.DisburseLoanCommandStrategy;
+import org.apache.fineract.batch.command.internal.GetDatatableEntryByAppTableIdCommandStrategy;
import org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy;
import org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy;
-import org.apache.fineract.batch.command.internal.RepayLoanCommandStrategy;
import org.apache.fineract.batch.command.internal.UnknownCommandStrategy;
import org.apache.fineract.batch.command.internal.UpdateClientCommandStrategy;
import org.junit.jupiter.params.ParameterizedTest;
@@ -66,8 +67,10 @@ public class CommandStrategyProviderTest {
Arguments.of("loans/123/charges", HttpMethod.POST, "createChargeCommandStrategy", mock(CreateChargeCommandStrategy.class)),
Arguments.of("loans/123/charges", HttpMethod.GET, "collectChargesCommandStrategy",
mock(CollectChargesCommandStrategy.class)),
- Arguments.of("loans/123/transactions?command=repayment", HttpMethod.POST, "repayLoanCommandStrategy",
- mock(RepayLoanCommandStrategy.class)),
+ Arguments.of("loans/123/transactions?command=repayment", HttpMethod.POST, "createTransactionLoanCommandStrategy",
+ mock(CreateTransactionLoanCommandStrategy.class)),
+ Arguments.of("loans/123/transactions?command=creditBalanceRefund", HttpMethod.POST, "createTransactionLoanCommandStrategy",
+ mock(CreateTransactionLoanCommandStrategy.class)),
Arguments.of("clients/456?command=activate", HttpMethod.POST, "activateClientCommandStrategy",
mock(ActivateClientCommandStrategy.class)),
Arguments.of("loans/123?command=approve", HttpMethod.POST, "approveLoanCommandStrategy",
@@ -77,7 +80,11 @@ public class CommandStrategyProviderTest {
Arguments.of("rescheduleloans/123?command=approve", HttpMethod.POST, "approveLoanRescheduleCommandStrategy",
mock(ApproveLoanRescheduleCommandStrategy.class)),
Arguments.of("loans/123/transactions/123", HttpMethod.GET, "getTransactionByIdCommandStrategy",
- mock(GetTransactionByIdCommandStrategy.class)));
+ mock(GetTransactionByIdCommandStrategy.class)),
+ Arguments.of("datatables/test_dt_table/123", HttpMethod.GET, "getDatatableEntryByAppTableIdCommandStrategy",
+ mock(GetDatatableEntryByAppTableIdCommandStrategy.class)),
+ Arguments.of("datatables/test_dt_table/123?genericResultSet=true", HttpMethod.GET,
+ "getDatatableEntryByAppTableIdCommandStrategy", mock(GetDatatableEntryByAppTableIdCommandStrategy.class)));
}
/**
@@ -99,7 +106,6 @@ public class CommandStrategyProviderTest {
final ApplicationContext applicationContext = mock(ApplicationContext.class);
final CommandStrategyProvider commandStrategyProvider = new CommandStrategyProvider(applicationContext);
when(applicationContext.getBean(beanName)).thenReturn(commandStrategy);
-
final CommandStrategy result = commandStrategyProvider.getCommandStrategy(CommandContext.resource(url).method(httpMethod).build());
assertEquals(commandStrategy, result);
}
@@ -111,7 +117,9 @@ public class CommandStrategyProviderTest {
*/
private static Stream<Arguments> provideCommandStrategyResourceDetailsForErrors() {
return Stream.of(Arguments.of("loans/123?command=reject", HttpMethod.POST),
- Arguments.of("loans/glimAccount/746?command=approve", HttpMethod.POST), Arguments.of("loans/123", HttpMethod.PUT));
+ Arguments.of("loans/glimAccount/746?command=approve", HttpMethod.POST), Arguments.of("loans/123", HttpMethod.PUT),
+ Arguments.of("datatables/test_dt_table", HttpMethod.GET), Arguments.of("datatables", HttpMethod.GET));
+
}
/**
diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategyTest.java
new file mode 100644
index 000000000..c081a2e0c
--- /dev/null
+++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategyTest.java
@@ -0,0 +1,119 @@
+/**
+ * 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.batch.command.internal;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.UriInfo;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.fineract.batch.domain.BatchRequest;
+import org.apache.fineract.batch.domain.BatchResponse;
+import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionsApiResource;
+import org.apache.http.HttpStatus;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Test class fpr {@link CreateTransactionLoanCommandStrategy}.
+ */
+public class CreateTransactionLoanCommandStrategyTest {
+
+ /**
+ * Test {@link CreateTransactionLoanCommandStrategy#execute} happy path scenario.
+ */
+ @Test
+ public void testExecuteSuccessScenario() {
+ final TestContext testContext = new TestContext();
+ final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
+ final String command = "myCommand";
+ final BatchRequest batchRequest = getBatchRequest(loanId, command);
+ final String responseBody = "myResponseBody";
+
+ when(testContext.loanTransactionsApiResource.executeLoanTransaction(loanId, command, batchRequest.getBody()))
+ .thenReturn(responseBody);
+
+ BatchResponse batchResponse = testContext.subjectToTest.execute(batchRequest, testContext.uriInfo);
+
+ assertEquals(HttpStatus.SC_OK, batchResponse.getStatusCode());
+ assertSame(responseBody, batchResponse.getBody());
+ assertEquals(batchRequest.getRequestId(), batchResponse.getRequestId());
+ assertEquals(batchRequest.getHeaders(), batchResponse.getHeaders());
+
+ verify(testContext.loanTransactionsApiResource).executeLoanTransaction(loanId, command, batchRequest.getBody());
+ }
+
+ /**
+ * Creates and returns a request with the given loan id and command value.
+ *
+ * @param loanId
+ * the loan id
+ * @param command
+ * the transaction id
+ * @return BatchRequest
+ */
+ private BatchRequest getBatchRequest(final Long loanId, final String command) {
+
+ final BatchRequest br = new BatchRequest();
+ String relativeUrl = "loans/" + loanId + "/transactions?command=" + command;
+
+ br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5)));
+ br.setRelativeUrl(relativeUrl);
+ br.setMethod(HttpMethod.POST);
+ br.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5)));
+ br.setBody("{}");
+
+ return br;
+ }
+
+ /**
+ * Private test context class used since testng runs in parallel to avoid state between tests
+ */
+ private static class TestContext {
+
+ /**
+ * Mock URI info.
+ */
+ @Mock
+ private UriInfo uriInfo;
+
+ /**
+ * Mock loan transactions API resource.
+ */
+ @Mock
+ private LoanTransactionsApiResource loanTransactionsApiResource;
+
+ /**
+ * The {@link CreateTransactionLoanCommandStrategy} under test.
+ */
+ private final CreateTransactionLoanCommandStrategy subjectToTest;
+
+ /**
+ * Constructor.
+ */
+ TestContext() {
+ MockitoAnnotations.openMocks(this);
+ subjectToTest = new CreateTransactionLoanCommandStrategy(loanTransactionsApiResource);
+ }
+ }
+}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByAppTableIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByAppTableIdCommandStrategyTest.java
new file mode 100644
index 000000000..7699dec0c
--- /dev/null
+++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByAppTableIdCommandStrategyTest.java
@@ -0,0 +1,160 @@
+/**
+ * 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.batch.command.internal;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.verify;
+
+import java.util.List;
+import java.util.stream.Stream;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.UriInfo;
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.fineract.batch.domain.BatchRequest;
+import org.apache.fineract.batch.domain.BatchResponse;
+import org.apache.fineract.infrastructure.core.api.MutableUriInfo;
+import org.apache.fineract.infrastructure.dataqueries.api.DatatablesApiResource;
+import org.apache.http.HttpStatus;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests {GetDatatableEntryByAppTableIdCommandStrategy}.
+ */
+public class GetDatatableEntryByAppTableIdCommandStrategyTest {
+
+ /**
+ * Query parameter provider.
+ *
+ * @return the test data stream
+ */
+ private static Stream<Arguments> provideQueryParameters() {
+ return Stream.of(Arguments.of(null, 0), Arguments.of("genericResultSet=true", 1));
+ }
+
+ /**
+ * Test {@link GetDatatableEntryByAppTableIdCommandStrategy#execute} happy path scenario.
+ *
+ * @param queryParameter
+ * the query parameter
+ * @param numberOfQueryParams
+ * number of query params are provided
+ */
+ @ParameterizedTest
+ @MethodSource("provideQueryParameters")
+ public void testExecuteSuccessScenario(final String queryParameter, final int numberOfQueryParams) {
+ final TestContext testContext = new TestContext();
+
+ final Long loanId = RandomUtils.nextLong();
+ final String datatableName = "dt_loan_xyz";
+ final BatchRequest request = getBatchRequest(loanId, queryParameter, datatableName);
+ final String responseBody = "{\\\"columnHeaders\\\":[{}],\\\"data\\\":\\\"{}\\\"}";
+
+ given(testContext.dataTableApiResource.getDatatable(eq(datatableName), eq(loanId), eq(null), any(UriInfo.class)))
+ .willReturn(responseBody);
+
+ final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
+
+ assertEquals(HttpStatus.SC_OK, response.getStatusCode());
+ assertEquals(request.getRequestId(), response.getRequestId());
+ assertEquals(request.getHeaders(), response.getHeaders());
+ assertEquals(responseBody, response.getBody());
+
+ verify(testContext.dataTableApiResource).getDatatable(eq(datatableName), eq(loanId), eq(null), testContext.uriInfoCaptor.capture());
+ MutableUriInfo mutableUriInfo = testContext.uriInfoCaptor.getValue();
+ assertThat(mutableUriInfo.getAdditionalQueryParameters()).hasSize(numberOfQueryParams);
+ if (numberOfQueryParams > 0) {
+ List<String> param = mutableUriInfo.getAdditionalQueryParameters().get("genericResultSet");
+ assertEquals(param.get(0), "true");
+ }
+ }
+
+ /**
+ * Creates and returns a request with the given loan id.
+ *
+ * @param loanId
+ * the loan id
+ * @param queryParameter
+ * the query parameter
+ * @param datatableName
+ * the datatable name
+ * @return the {@link BatchRequest}
+ */
+ private BatchRequest getBatchRequest(final Long loanId, final String queryParameter, final String datatableName) {
+ final BatchRequest br = new BatchRequest();
+ String relativeUrl = String.format("datatables/%s/%s", datatableName, loanId);
+ if (queryParameter != null) {
+ relativeUrl = relativeUrl + "?" + queryParameter;
+ }
+
+ br.setRequestId(RandomUtils.nextLong());
+ br.setRelativeUrl(relativeUrl);
+ br.setMethod(HttpMethod.GET);
+ br.setReference(RandomUtils.nextLong());
+ br.setBody("{}");
+
+ return br;
+ }
+
+ /**
+ * Private test context class used since testng runs in parallel to avoid state between tests
+ */
+ private static final class TestContext {
+
+ /**
+ * The subject under test.
+ */
+ private final GetDatatableEntryByAppTableIdCommandStrategy subjectToTest;
+
+ /**
+ * Mock of {@link UriInfo}
+ */
+ @Mock
+ private UriInfo uriInfo;
+
+ /**
+ * Captor of {@link MutableUriInfo}.
+ */
+ @Captor
+ private ArgumentCaptor<MutableUriInfo> uriInfoCaptor;
+
+ /**
+ * {@link DatatablesApiResource} mock.
+ */
+ @Mock
+ private DatatablesApiResource dataTableApiResource;
+
+ /**
+ * Constructor.
+ */
+ private TestContext() {
+ MockitoAnnotations.openMocks(this);
+ subjectToTest = new GetDatatableEntryByAppTableIdCommandStrategy(dataTableApiResource);
+ }
+ }
+}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetLoanByIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetLoanByIdCommandStrategyTest.java
index 40a381488..d8327f89c 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetLoanByIdCommandStrategyTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetLoanByIdCommandStrategyTest.java
@@ -34,9 +34,7 @@ import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
import org.apache.fineract.infrastructure.core.api.MutableUriInfo;
import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
import org.apache.http.HttpStatus;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@@ -87,64 +85,6 @@ public class GetLoanByIdCommandStrategyTest {
assertThat(mutableUriInfo.getAdditionalQueryParameters()).hasSize(noOfQueryParams);
}
- /**
- * Test {@link GetLoanByIdCommandStrategy#execute} for internal server error.
- */
- @Test
- public void testExecuteForInternalServerError() {
- // given
- final TestContext testContext = new TestContext();
- final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
- final BatchRequest request = getBatchRequest(loanId, null, null, null);
-
- given(testContext.loansApiResource.retrieveLoan(eq(loanId), eq(false), eq(null), eq(null), eq(null), any(UriInfo.class)))
- .willThrow(new RuntimeException("Some error"));
-
- // when
- final BatchResponse response = testContext.underTest.execute(request, testContext.uriInfo);
-
- // then
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_INTERNAL_SERVER_ERROR);
- assertThat(response.getBody()).isEqualTo("{\"Exception\": java.lang.RuntimeException: Some error}");
- assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
- assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
- }
-
- /**
- * Test {@link GetLoanByIdCommandStrategy#execute} for loan not found exception.
- */
- @Test
- public void testExecuteForLoanNotFoundException() {
- // given
- final TestContext testContext = new TestContext();
- final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
- final BatchRequest request = getBatchRequest(loanId, null, null, null);
-
- given(testContext.loansApiResource.retrieveLoan(eq(loanId), eq(false), eq(null), eq(null), eq(null), any(UriInfo.class)))
- .willThrow(new LoanNotFoundException(loanId));
-
- // when
- final BatchResponse response = testContext.underTest.execute(request, testContext.uriInfo);
-
- // then
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
- assertThat(response.getBody()).isEqualTo(buildLoanNotFoundError(loanId));
- assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
- assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
- }
-
- private String buildLoanNotFoundError(final Long loanId) {
- return String.format(
- "{\n \"developerMessage\": \"The requested resource is not available.\",\n"
- + " \"httpStatusCode\": \"404\",\n \"defaultUserMessage\": \"The requested resource is not available.\",\n"
- + " \"userMessageGlobalisationCode\": \"error.msg.resource.not.found\",\n \"errors\": [\n {\n"
- + " \"developerMessage\": \"Loan with identifier %s does not exist\",\n"
- + " \"defaultUserMessage\": \"Loan with identifier %s does not exist\",\n"
- + " \"userMessageGlobalisationCode\": \"error.msg.loan.id.invalid\",\n \"parameterName\": \"id\",\n"
- + " \"args\": [\n {\n \"value\": %s\n }\n ]\n }\n ]\n" + "}",
- loanId, loanId, loanId);
- }
-
/**
* Creates and returns a request with the given loan id.
*
diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategyTest.java
index fe92be9dc..60ef582f8 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategyTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategyTest.java
@@ -19,11 +19,9 @@
package org.apache.fineract.batch.command.internal;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.when;
import java.util.stream.Stream;
import javax.ws.rs.HttpMethod;
@@ -32,10 +30,7 @@ import org.apache.commons.lang3.RandomStringUtils;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionsApiResource;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
import org.apache.http.HttpStatus;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@@ -84,75 +79,6 @@ public class GetTransactionByIdCommandStrategyTest {
assertThat(response.getBody()).isEqualTo(responseBody);
}
- /**
- * Test {@link GetTransactionByIdCommandStrategy#execute} for internal server error.
- */
- @Test
- public void testExecuteForInternalServerError() {
- // given
- final TestContext testContext = new TestContext();
- final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
- final Long transactionId = Long.valueOf(RandomStringUtils.randomNumeric(4));
- final BatchRequest request = getBatchRequest(loanId, transactionId, null);
-
- given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, null, testContext.uriInfo))
- .willThrow(new RuntimeException("Some error"));
-
- // when
- final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
-
- // then
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_INTERNAL_SERVER_ERROR);
- assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
- assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
- assertThat(response.getBody()).isEqualTo("{\"Exception\": java.lang.RuntimeException: Some error}");
- }
-
- /**
- * Test {@link GetTransactionByIdCommandStrategy#execute} for loan not found exception.
- */
- @Test
- public void testExecuteForLoanNotFoundException() {
- // given
- final TestContext testContext = new TestContext();
- final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
- final Long transactionId = Long.valueOf(RandomStringUtils.randomNumeric(4));
- final BatchRequest request = getBatchRequest(loanId, transactionId, null);
-
- given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, null, testContext.uriInfo))
- .willThrow(new LoanNotFoundException(loanId));
-
- // when
- final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
-
- // then
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
- assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
- assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
- assertThat(response.getBody()).isEqualTo(build404NotFoundError("Loan", loanId));
- }
-
- /**
- * Test {@link GetTransactionByIdCommandStrategy#execute} for transaction not found exception.
- */
- @Test
- public void testExecuteForTransactionNotFoundException() {
- final TestContext testContext = new TestContext();
- final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
- final Long transactionId = Long.valueOf(RandomStringUtils.randomNumeric(4));
- final BatchRequest request = getBatchRequest(loanId, transactionId, null);
-
- when(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, null, testContext.uriInfo))
- .thenThrow(new LoanTransactionNotFoundException(transactionId));
-
- final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
-
- assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatusCode());
- assertEquals(build404NotFoundError("Transaction", transactionId), response.getBody());
- assertEquals(request.getRequestId(), response.getRequestId());
- assertEquals(request.getHeaders(), response.getHeaders());
- }
-
/**
* Creates and returns a request with the given loan id and transaction id.
*
@@ -179,25 +105,6 @@ public class GetTransactionByIdCommandStrategyTest {
return br;
}
- /**
- * Builds the 404 not found error.
- *
- * @param field
- * the field name
- * @param id
- * the id
- */
- private String build404NotFoundError(final String field, final Long id) {
- return String.format("{\n" + " \"developerMessage\": \"The requested resource is not available.\",\n"
- + " \"httpStatusCode\": \"404\",\n" + " \"defaultUserMessage\": \"The requested resource is not available.\",\n"
- + " \"userMessageGlobalisationCode\": \"error.msg.resource.not.found\",\n" + " \"errors\": [\n" + " {\n"
- + " \"developerMessage\": \"%s with identifier %s does not exist\",\n"
- + " \"defaultUserMessage\": \"%s with identifier %s does not exist\",\n"
- + " \"userMessageGlobalisationCode\": \"error.msg.loan.id.invalid\",\n" + " \"parameterName\": \"id\",\n"
- + " \"args\": [\n" + " {\n" + " \"value\": %s\n" + " }\n" + " ]\n" + " }\n" + " ]\n"
- + "}", field, id, field, id, id);
- }
-
/**
* Private test context class used since testng runs in parallel to avoid state between tests
*/
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 59d0ce052..49bded81a 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
@@ -18,6 +18,8 @@
*/
package org.apache.fineract.integrationtests;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.restassured.builder.RequestSpecBuilder;
@@ -28,6 +30,7 @@ import io.restassured.specification.ResponseSpecification;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
@@ -38,6 +41,7 @@ import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
+import org.apache.fineract.integrationtests.common.system.DatatableHelper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Assertions;
@@ -55,9 +59,26 @@ import org.junit.jupiter.api.Test;
*/
public class BatchApiTest {
+ /**
+ * The response specification
+ */
private ResponseSpecification responseSpec;
+
+ /**
+ * The request specification
+ */
private RequestSpecification requestSpec;
+ /**
+ * The datatable helper
+ */
+ private DatatableHelper datatableHelper;
+
+ /**
+ * Loan app datatable
+ */
+ private static final String LOAN_APP_TABLE_NAME = "m_loan";
+
/**
* Sets up the essential settings for the TEST like contentType, expectedStatusCode. It uses the '@BeforeEach'
* annotation provided by jUnit.
@@ -68,6 +89,7 @@ public class BatchApiTest {
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+ this.datatableHelper = new DatatableHelper(this.requestSpec, this.responseSpec);
}
/**
@@ -240,7 +262,8 @@ public class BatchApiTest {
// Get the clientId parameter from createClient Response
final JsonElement clientId = new FromJsonHelper().parse(response.get(0).getBody()).getAsJsonObject().get("clientId");
- Assertions.assertEquals(200L, (long) response.get(1).getStatusCode(), "Verify Status Code 200" + clientId.getAsString());
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(1).getStatusCode(),
+ "Verify Status Code 200" + clientId.getAsString());
}
/**
@@ -281,7 +304,7 @@ public class BatchApiTest {
final List<BatchResponse> response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec,
jsonifiedRequest);
- Assertions.assertEquals(200L, (long) response.get(1).getStatusCode(), "Verify Status Code 200");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(1).getStatusCode(), "Verify Status Code 200");
}
/**
@@ -341,7 +364,7 @@ public class BatchApiTest {
final List<BatchResponse> response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec,
jsonifiedRequest);
- Assertions.assertEquals(200L, (long) response.get(3).getStatusCode(), "Verify Status Code 200 for Create Loan Charge");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(3).getStatusCode(), "Verify Status Code 200 for Create Loan Charge");
}
/**
@@ -349,7 +372,7 @@ public class BatchApiTest {
* successful responses. It first creates a new loan and then makes two repayments for it and then verifies that
* 200(OK) is returned for the repayment requests.
*
- * @see org.apache.fineract.batch.command.internal.RepayLoanCommandStrategy
+ * @see CreateTransactionLoanCommandStrategy
*/
@Test
public void shouldReturnOkStatusForBatchRepayment() {
@@ -392,10 +415,10 @@ public class BatchApiTest {
final BatchRequest br5 = BatchHelper.disburseLoanRequest(4734L, 4733L);
// Create a loanRepay Request
- final BatchRequest br6 = BatchHelper.repayLoanRequest(4735L, 4734L);
+ final BatchRequest br6 = BatchHelper.repayLoanRequest(4735L, 4734L, "500");
// Create a loanRepay Request
- final BatchRequest br7 = BatchHelper.repayLoanRequest(4736L, 4734L);
+ final BatchRequest br7 = BatchHelper.repayLoanRequest(4736L, 4734L, "500");
final List<BatchRequest> batchRequests = new ArrayList<>();
@@ -412,8 +435,85 @@ public class BatchApiTest {
final List<BatchResponse> response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec,
jsonifiedRequest);
- Assertions.assertEquals(200L, (long) response.get(5).getStatusCode(), "Verify Status Code 200 for Repayment");
- Assertions.assertEquals(200L, (long) response.get(6).getStatusCode(), "Verify Status Code 200 for Repayment");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(5).getStatusCode(), "Verify Status Code 200 for Repayment");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(6).getStatusCode(), "Verify Status Code 200 for Repayment");
+ }
+
+ /**
+ * Tests that batch credit balance refund for loans is happening properly. Collected properly 200(OK) status was
+ * returned for successful responses. It first creates a new loan and then makes an overpayment, before creating a
+ * credit balance refund to refund a portion of the over-payment.
+ *
+ * @see CreateTransactionLoanCommandStrategy
+ */
+ @Test
+ public void shouldReturnOkStatusForBatchCreditBalanceRefund() {
+
+ final String loanProductJSON = new LoanProductTestBuilder() //
+ .withPrincipal("1000.00") //
+ .withNumberOfRepayments("24") //
+ .withRepaymentAfterEvery("1") //
+ .withRepaymentTypeAsMonth() //
+ .withinterestRatePerPeriod("2") //
+ .withInterestRateFrequencyTypeAsMonths() //
+ .withAmortizationTypeAsEqualPrincipalPayment() //
+ .withInterestTypeAsDecliningBalance() //
+ .currencyDetails("0", "100").build(null);
+
+ final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
+ ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
+
+ final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec);
+ Assertions.assertNotNull(collateralId);
+ final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec,
+ clientID.toString(), collateralId);
+ Assertions.assertNotNull(clientCollateralId);
+
+ final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON);
+
+ final Long createActiveClientRequestId = 4730L;
+ final Long applyLoanRequestId = createActiveClientRequestId + 1;
+ final Long approveLoanRequestId = applyLoanRequestId + 1;
+ final Long disburseLoanRequestId = approveLoanRequestId + 1;
+ final Long repayLoanRequestId = disburseLoanRequestId + 1;
+ final Long creditBalanceRefundRequestId = repayLoanRequestId + 1;
+
+ // Create a createClient Request
+ final BatchRequest br1 = BatchHelper.createActiveClientRequest(createActiveClientRequestId, "");
+
+ // Create a ApplyLoan Request
+ final BatchRequest br2 = BatchHelper.applyLoanRequest(applyLoanRequestId, createActiveClientRequestId, productId,
+ clientCollateralId);
+
+ // Create a approveLoan Request
+ final BatchRequest br3 = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId);
+
+ // Create a disburseLoan Request
+ final BatchRequest br4 = BatchHelper.disburseLoanRequest(disburseLoanRequestId, approveLoanRequestId);
+
+ // Create a loanRepay Request which will result in an overpay.
+ final BatchRequest br5 = BatchHelper.repayLoanRequest(repayLoanRequestId, disburseLoanRequestId, "20000");
+
+ // Create a credit balance refund request
+ final BatchRequest br6 = BatchHelper.creditBalanceRefundRequest(creditBalanceRefundRequestId, repayLoanRequestId, "500");
+
+ final List<BatchRequest> batchRequests = new ArrayList<>();
+
+ batchRequests.add(br1);
+ batchRequests.add(br2);
+ batchRequests.add(br3);
+ batchRequests.add(br4);
+ batchRequests.add(br5);
+ batchRequests.add(br6);
+
+ final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests);
+
+ final List<BatchResponse> response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec,
+ jsonifiedRequest);
+
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(4).getStatusCode(), "Verify Status Code 200 for Repayment");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(5).getStatusCode(),
+ "Verify Status Code 200 for Credit Balance Refund");
}
/**
@@ -441,8 +541,8 @@ public class BatchApiTest {
final List<BatchResponse> response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec,
jsonifiedRequest);
- Assertions.assertEquals(200L, (long) response.get(0).getStatusCode(), "Verify Status Code 200 for Create Client");
- Assertions.assertEquals(200L, (long) response.get(1).getStatusCode(), "Verify Status Code 200 for Activate Client");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(0).getStatusCode(), "Verify Status Code 200 for Create Client");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(1).getStatusCode(), "Verify Status Code 200 for Activate Client");
}
/**
@@ -504,8 +604,8 @@ public class BatchApiTest {
final List<BatchResponse> response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec,
jsonifiedRequest);
- Assertions.assertEquals(200L, (long) response.get(3).getStatusCode(), "Verify Status Code 200 for Approve Loan");
- Assertions.assertEquals(200L, (long) response.get(4).getStatusCode(), "Verify Status Code 200 for Disburse Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(3).getStatusCode(), "Verify Status Code 200 for Approve Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(4).getStatusCode(), "Verify Status Code 200 for Disburse Loan");
}
/**
@@ -558,10 +658,10 @@ public class BatchApiTest {
final List<BatchResponse> response = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec, this.responseSpec,
jsonifiedRequest);
- Assertions.assertEquals(200L, (long) response.get(0).getStatusCode(), "Verify Status Code 200 for create client");
- Assertions.assertEquals(200L, (long) response.get(1).getStatusCode(), "Verify Status Code 200 for apply Loan");
- Assertions.assertEquals(200L, (long) response.get(2).getStatusCode(), "Verify Status Code 200 for approve Loan");
- Assertions.assertEquals(200L, (long) response.get(3).getStatusCode(), "Verify Status Code 200 for disburse Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(0).getStatusCode(), "Verify Status Code 200 for create client");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(1).getStatusCode(), "Verify Status Code 200 for apply Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(2).getStatusCode(), "Verify Status Code 200 for approve Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(3).getStatusCode(), "Verify Status Code 200 for disburse Loan");
}
/**
@@ -754,4 +854,164 @@ public class BatchApiTest {
// Repayment schedule information will be available in the response based on the query parameter
Assertions.assertTrue(responses.get(3).getBody().contains("repaymentSchedule"));
}
+
+ /**
+ * Test for the successful get loan and get datatable entry. A '200' status code is expected on successful
+ * responses.
+ *
+ * @see org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy
+ * @see org.apache.fineract.batch.command.internal.ApproveLoanCommandStrategy
+ * @see org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy
+ */
+ @Test
+ public void shouldReturnOkStatusOnSuccessfulGetDataTableEntry() {
+ final FromJsonHelper jsonHelper = new FromJsonHelper();
+ final Long loanId = jsonHelper.extractLongNamed("loanId", jsonHelper.parse(setupAccount()).getAsJsonObject());
+ final String datatableName = this.datatableHelper.createDatatable(LOAN_APP_TABLE_NAME, false);
+ try {
+
+ // Get loan by id Request with query param
+ final BatchRequest getLoanBatchRequest = BatchHelper.getLoanByIdRequest(loanId, "associations=repaymentSchedule,transactions");
+
+ // Get datatable batch request
+ final BatchRequest getDatatableBatchRequest = BatchHelper.getDatatableByIdRequest(loanId, datatableName,
+ "genericResultSet=true");
+
+ final List<BatchRequest> batchRequestsGetLoan = Arrays.asList(getLoanBatchRequest, getDatatableBatchRequest);
+
+ final List<BatchResponse> responsesGetLoan = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec,
+ this.responseSpec, BatchHelper.toJsonString(batchRequestsGetLoan));
+
+ final String getLoanResponse = responsesGetLoan.get(0).getBody();
+ final String getDatatableResponse = responsesGetLoan.get(1).getBody();
+
+ Assertions.assertEquals(HttpStatus.SC_OK, responsesGetLoan.get(0).getStatusCode(), "Verify Status Code 200 for get loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, responsesGetLoan.get(1).getStatusCode(), "Verify Status Code 200 for datatable");
+
+ final Long loanIdInGetResponse = jsonHelper.extractLongNamed("id", jsonHelper.parse(getLoanResponse).getAsJsonObject());
+ Assertions.assertEquals(loanId, loanIdInGetResponse);
+
+ // Repayment schedule information will be available in the response based on the query parameter
+ Assertions.assertTrue(getLoanResponse.contains("repaymentSchedule"));
+
+ // Transaction will be available in the response based on the query parameter
+ Assertions.assertTrue(getLoanResponse.contains("transactions"));
+
+ // datatable info will be available in the response based on the query parameter
+ Assertions.assertTrue(getDatatableResponse.contains("columnHeaders"));
+
+ // datatable info will be available in the response based on the query parameter
+ Assertions.assertTrue(getDatatableResponse.contains("data"));
+ } finally {
+ deleteDatatable(datatableName);
+ }
+ }
+
+ /**
+ * Test for the successful get loan and get datatable entry where get datatable request have no query param. A '200'
+ * status code is expected on successful responses.
+ *
+ * @see org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy
+ * @see org.apache.fineract.batch.command.internal.ApproveLoanCommandStrategy
+ * @see org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy
+ */
+ @Test
+ public void shouldReturnOkStatusOnSuccessfulGetDatatableEntryWithNoQueryParam() {
+ final FromJsonHelper jsonHelper = new FromJsonHelper();
+ final Long loanId = jsonHelper.extractLongNamed("loanId", jsonHelper.parse(setupAccount()).getAsJsonObject());
+ final String datatableName = this.datatableHelper.createDatatable(LOAN_APP_TABLE_NAME, false);
+ try {
+ // Get loan by id Request with query param
+ final BatchRequest getLoanBatchRequest = BatchHelper.getLoanByIdRequest(loanId, "associations=repaymentSchedule,transactions");
+
+ // Get datatable batch request
+ final BatchRequest getDatatableBatchRequest = BatchHelper.getDatatableByIdRequest(loanId, datatableName, null);
+
+ final List<BatchRequest> batchRequestsGetLoan = Arrays.asList(getLoanBatchRequest, getDatatableBatchRequest);
+
+ final List<BatchResponse> responsesGetLoan = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec,
+ this.responseSpec, BatchHelper.toJsonString(batchRequestsGetLoan));
+
+ final String getLoanResponse = responsesGetLoan.get(0).getBody();
+
+ Assertions.assertEquals(HttpStatus.SC_OK, responsesGetLoan.get(0).getStatusCode(), "Verify Status Code 200 for Get Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, responsesGetLoan.get(1).getStatusCode(), "Verify Status Code 200 for Get Datatable");
+
+ final Long loanIdInGetResponse = jsonHelper.extractLongNamed("id", jsonHelper.parse(getLoanResponse).getAsJsonObject());
+ Assertions.assertEquals(loanId, loanIdInGetResponse);
+
+ Assertions.assertTrue(getLoanResponse.contains("repaymentSchedule"));
+
+ Assertions.assertTrue(getLoanResponse.contains("transactions"));
+ } finally {
+ deleteDatatable(datatableName);
+ }
+
+ }
+
+ /**
+ * Delete datatable
+ *
+ * @param datatableName
+ * the datatable name
+ */
+ private void deleteDatatable(final String datatableName) {
+ String deletedDatatableName = this.datatableHelper.deleteDatatable(datatableName);
+ assertEquals(datatableName, deletedDatatableName, "Fail to delete the datatable");
+ }
+
+ /**
+ * Setup account to test get loan and get datatable batch call
+ *
+ * @return the response body
+ */
+ private String setupAccount() {
+ final String loanProductJSON = new LoanProductTestBuilder() //
+ .withPrincipal("10000000.00") //
+ .withNumberOfRepayments("24") //
+ .withRepaymentAfterEvery("1") //
+ .withRepaymentTypeAsMonth() //
+ .withinterestRatePerPeriod("2") //
+ .withInterestRateFrequencyTypeAsMonths() //
+ .withAmortizationTypeAsEqualPrincipalPayment() //
+ .withInterestTypeAsDecliningBalance() //
+ .currencyDetails("0", "100").build(null);
+
+ final Long applyLoanRequestId = 5730L;
+ final Long approveLoanRequestId = 5731L;
+ final Long disburseLoanRequestId = 5734L;
+ final Long repayLoanRequestId = 5735L;
+
+ // Create product
+ final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON);
+
+ // Create client
+ final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
+ ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientId);
+
+ // Create an ApplyLoan Request
+ final BatchRequest applyLoanBatchRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId);
+
+ // Create an approveLoan Request
+ final BatchRequest approveLoanBatchRequest = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId);
+
+ // Create a disburseLoan Request
+ final BatchRequest disburseLoanBatchRequest = BatchHelper.disburseLoanRequest(disburseLoanRequestId, applyLoanRequestId);
+
+ // Create a repayment Request
+ final BatchRequest repaymentBatchRequest = BatchHelper.repayLoanRequest(repayLoanRequestId, applyLoanRequestId, "500");
+
+ final List<BatchRequest> batchRequests = Arrays.asList(applyLoanBatchRequest, approveLoanBatchRequest, disburseLoanBatchRequest,
+ repaymentBatchRequest);
+
+ final List<BatchResponse> responses = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec, this.responseSpec,
+ BatchHelper.toJsonString(batchRequests));
+
+ Assertions.assertEquals(HttpStatus.SC_OK, responses.get(0).getStatusCode(), "Verify Status Code 200 for Apply Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, responses.get(1).getStatusCode(), "Verify Status Code 200 for Approve Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, responses.get(2).getStatusCode(), "Verify Status Code 200 for Disburse Loan");
+ Assertions.assertEquals(HttpStatus.SC_OK, responses.get(3).getStatusCode(), "Verify Status Code 200 for Repay Loan");
+
+ return responses.get(0).getBody();
+ }
}
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
index 5b37a620d..ff45e9974 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
@@ -23,10 +23,14 @@ import com.google.gson.reflect.TypeToken;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.security.SecureRandom;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.ws.rs.HttpMethod;
+import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
import org.junit.jupiter.api.Assertions;
@@ -223,12 +227,37 @@ public final class BatchHelper {
* given requestId and reference.
*
* @param requestId
+ * the request ID
* @param reference
+ * the reference ID
* @param productId
- * @return BatchRequest
+ * the product ID
+ * @return BatchRequest the batch request
*/
public static BatchRequest applyLoanRequest(final Long requestId, final Long reference, final Integer productId,
final Integer clientCollateralId) {
+ return applyLoanRequest(requestId, reference, productId, clientCollateralId, LocalDate.now(ZoneId.systemDefault()).minusDays(10),
+ "10,000.00");
+ }
+
+ /**
+ * Creates and returns a {@link org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy} Request with
+ * given requestId and reference.
+ *
+ * @param requestId
+ * the request ID
+ * @param reference
+ * the reference ID
+ * @param productId
+ * the product ID
+ * @param date
+ * the loan submitted on date
+ * @param loanAmount
+ * the loan amount
+ * @return BatchRequest the batch request
+ */
+ public static BatchRequest applyLoanRequest(final Long requestId, final Long reference, final Integer productId,
+ final Integer clientCollateralId, final LocalDate date, final String loanAmount) {
final BatchRequest br = new BatchRequest();
@@ -236,19 +265,20 @@ public final class BatchHelper {
br.setRelativeUrl("loans");
br.setMethod("POST");
br.setReference(reference);
+ String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
String body = "{\"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en_GB\", \"clientId\": \"$.clientId\"," + "\"productId\": "
- + productId + ", \"principal\": \"10,000.00\", \"loanTermFrequency\": 10,"
+ + productId + ", \"principal\": \"" + loanAmount + "\", \"loanTermFrequency\": 10,"
+ "\"loanTermFrequencyType\": 2, \"loanType\": \"individual\", \"numberOfRepayments\": 10,"
+ "\"repaymentEvery\": 1, \"repaymentFrequencyType\": 2, \"interestRatePerPeriod\": 10,"
+ "\"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1,"
- + "\"transactionProcessingStrategyId\": 1, \"expectedDisbursementDate\": \"10 Jun 2013\",";
+ + "\"transactionProcessingStrategyId\": 1, \"expectedDisbursementDate\": \"" + dateString + "\",";
if (clientCollateralId != null) {
- body = body + "\"collateral\": [{\"clientCollateralId\": \"" + clientCollateralId.toString() + "\", \"quantity\": \"1\"}],";
+ body = body + "\"collateral\": [{\"clientCollateralId\": \"" + clientCollateralId + "\", \"quantity\": \"1\"}],";
}
- body = body + "\"submittedOnDate\": \"10 Jun 2013\"}";
+ body = body + "\"submittedOnDate\": \"" + dateString + "\"}";
br.setBody(body);
@@ -385,17 +415,37 @@ public final class BatchHelper {
*
*
* @param requestId
+ * the request ID
* @param reference
- * @return BatchRequest
+ * the reference ID
+ * @return BatchRequest the batch request
*/
public static BatchRequest approveLoanRequest(final Long requestId, final Long reference) {
+ return approveLoanRequest(requestId, reference, LocalDate.now(ZoneId.systemDefault()).minusDays(10));
+ }
+
+ /**
+ * Creates and returns a {@link org.apache.fineract.batch.command.internal.ApproveLoanCommandStrategy} Request with
+ * given requestId and reference.
+ *
+ *
+ * @param requestId
+ * the request ID
+ * @param reference
+ * the reference ID
+ * @param date
+ * the approved on date
+ * @return BatchRequest the batch request
+ */
+ public static BatchRequest approveLoanRequest(final Long requestId, final Long reference, LocalDate date) {
final BatchRequest br = new BatchRequest();
br.setRequestId(requestId);
br.setRelativeUrl("loans/$.loanId?command=approve");
br.setReference(reference);
br.setMethod("POST");
- br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"approvedOnDate\": \"12 September 2013\","
+ String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
+ br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"approvedOnDate\": \"" + dateString + "\","
+ "\"note\": \"Loan approval note\"}");
return br;
@@ -407,39 +457,123 @@ public final class BatchHelper {
*
*
* @param requestId
+ * the request ID
* @param reference
- * @return BatchRequest
+ * the reference ID
+ * @return BatchRequest the batch request
*/
public static BatchRequest disburseLoanRequest(final Long requestId, final Long reference) {
+ return disburseLoanRequest(requestId, reference, LocalDate.now(ZoneId.systemDefault()).minusDays(8));
+ }
+
+ /**
+ * Creates and returns a {@link org.apache.fineract.batch.command.internal.DisburseLoanCommandStrategy} Request with
+ * given requestId and reference.
+ *
+ *
+ * @param requestId
+ * the request ID
+ * @param reference
+ * the reference ID
+ * @param date
+ * the actual disbursement date
+ * @return BatchRequest the batch request
+ */
+ public static BatchRequest disburseLoanRequest(final Long requestId, final Long reference, final LocalDate date) {
final BatchRequest br = new BatchRequest();
br.setRequestId(requestId);
br.setRelativeUrl("loans/$.loanId?command=disburse");
br.setReference(reference);
br.setMethod("POST");
- br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"actualDisbursementDate\": \"15 September 2013\"}");
+ String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
+ br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"actualDisbursementDate\": \"" + dateString + "\"}");
return br;
}
/**
- * Creates and returns a {@link org.apache.fineract.batch.command.internal.RepayLoanCommandStrategy} Request with
- * given requestId.
+ * Creates and returns a {@link CreateTransactionLoanCommandStrategy} Request with given requestId.
*
+ * @param requestId
+ * the request ID
+ * @param reference
+ * the reference ID
+ * @param amount
+ * the amount
+ * @param date
+ * the transaction date
+ * @return BatchRequest the batch request
+ */
+ public static BatchRequest repayLoanRequest(final Long requestId, final Long reference, final String amount) {
+ return repayLoanRequest(requestId, reference, amount, LocalDate.now(ZoneId.systemDefault()));
+ }
+
+ /**
+ * Creates and returns a {@link CreateTransactionLoanCommandStrategy} Request with given requestId.
*
* @param requestId
+ * the request ID
* @param reference
- * @return BatchRequest
+ * the reference ID
+ * @param amount
+ * the amount
+ * @param date
+ * the transaction date
+ * @return BatchRequest the batch request
*/
- public static BatchRequest repayLoanRequest(final Long requestId, final Long reference) {
+ public static BatchRequest repayLoanRequest(final Long requestId, final Long reference, final String amount, final LocalDate date) {
final BatchRequest br = new BatchRequest();
br.setRequestId(requestId);
br.setReference(reference);
br.setRelativeUrl("loans/$.loanId/transactions?command=repayment");
br.setMethod("POST");
- br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", "
- + "\"transactionDate\": \"15 September 2013\", \"transactionAmount\": 500}");
+ String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
+ br.setBody(String.format(
+ "{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", " + "\"transactionDate\": \"%s\", \"transactionAmount\": %s}",
+ dateString, amount));
+
+ return br;
+ }
+
+ /**
+ * Creates and returns a {@link CreateTransactionLoanCommandStrategy} request with given request ID.
+ *
+ *
+ * @param requestId
+ * the request ID
+ * @param reference
+ * teh reference
+ * @return BatchRequest the created {@link BatchRequest}
+ */
+ public static BatchRequest creditBalanceRefundRequest(final Long requestId, final Long reference, final String amount) {
+ return creditBalanceRefundRequest(requestId, reference, amount, LocalDate.now(ZoneId.systemDefault()));
+ }
+
+ /**
+ * Creates and returns a {@link CreateTransactionLoanCommandStrategy} request with given request ID.
+ *
+ *
+ * @param requestId
+ * the request ID
+ * @param reference
+ * teh reference
+ * @param date
+ * the transaction date
+ * @return BatchRequest the created {@link BatchRequest}
+ */
+ public static BatchRequest creditBalanceRefundRequest(final Long requestId, final Long reference, final String amount, LocalDate date) {
+ final BatchRequest br = new BatchRequest();
+
+ br.setRequestId(requestId);
+ br.setReference(reference);
+ br.setRelativeUrl("loans/$.loanId/transactions?command=creditBalanceRefund");
+ br.setMethod("POST");
+ String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
+ br.setBody(String.format(
+ "{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", " + "\"transactionDate\": \"%s\", \"transactionAmount\": %s}",
+ dateString, amount));
return br;
}
@@ -511,4 +645,55 @@ public final class BatchHelper {
return br;
}
+
+ /**
+ * Creates and returns a {@link org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy} request with
+ * given loan id and query param.
+ *
+ * @param loanId
+ * the loan id
+ * @param queryParameter
+ * the query parameters
+ * @return the {@link BatchRequest}
+ */
+ public static BatchRequest getLoanByIdRequest(final Long loanId, final String queryParameter) {
+ final BatchRequest br = new BatchRequest();
+ String relativeUrl = String.format("loans/%s", loanId);
+ if (queryParameter != null) {
+ relativeUrl = relativeUrl + "?" + queryParameter;
+ }
+
+ br.setRequestId(4567L);
+ br.setRelativeUrl(relativeUrl);
+ br.setMethod(HttpMethod.GET);
+ br.setBody("{}");
+
+ return br;
+ }
+
+ /**
+ * Creates and returns a batch request to get datatable entry.
+ *
+ * @param loanId
+ * the loan id
+ * @param datatableName
+ * the name of datatable
+ * @param queryParameter
+ * the query parameters
+ * @return the {@link BatchRequest}
+ */
+ public static BatchRequest getDatatableByIdRequest(final Long loanId, final String datatableName, final String queryParameter) {
+ final BatchRequest br = new BatchRequest();
+ String relativeUrl = String.format("datatables/%s/%s", datatableName, loanId);
+ if (queryParameter != null) {
+ relativeUrl = relativeUrl + "?" + queryParameter;
+ }
+
+ br.setRequestId(4568L);
+ br.setRelativeUrl(relativeUrl);
+ br.setMethod(HttpMethod.GET);
+ br.setBody("{}");
+
+ return br;
+ }
}