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 0a7009a00..0560934f1 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 @@ -18,6 +18,10 @@ */ package org.apache.fineract.batch.command; +import static javax.ws.rs.HttpMethod.GET; +import static javax.ws.rs.HttpMethod.POST; +import static javax.ws.rs.HttpMethod.PUT; + import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.fineract.batch.command.internal.UnknownCommandStrategy; @@ -38,6 +42,41 @@ public class CommandStrategyProvider { private final ApplicationContext applicationContext; private static final Map commandStrategies = new ConcurrentHashMap<>(); + /** + * Regex pattern for specifying any number of query params or not specific any query param + */ + private static final String OPTIONAL_QUERY_PARAM_REGEX = "(\\?(\\w+(?:\\=[\\w,]+|&)+)+)?"; + + /** + * Regex pattern for specifying query params + */ + private static final String MANDATORY_QUERY_PARAM_REGEX = "(\\?(\\w+(?:\\=[\\w,]+|&)+)+)"; + + /** + * Regex pattern for specifying any query param that has key = 'command' or not specific anything. + */ + private static final String OPTIONAL_COMMAND_PARAM_REGEX = "(\\?command=[\\w]+)?"; + + /** + * Regex pattern for specifying a mandatory query param that has key = 'command'. + */ + private static final String MANDATORY_COMMAND_PARAM_REGEX = "\\?command=[\\w]+"; + + /** + * Regex pattern for specifying a UUID param. + */ + private static final String UUID_PARAM_REGEX = "[\\w\\d-]+"; + + /** + * Regex pattern for specifying a param that's should be a number. + */ + private static final String NUMBER_REGEX = "\\d+"; + + /** + * Regex pattern for specifying a param that contains case in-sensitive alphanumeric characters with underscores. + */ + private static final String ALPHANUMBERIC_WITH_UNDERSCORE_REGEX = "[a-zA-Z0-9_]*"; + /** * Constructs a CommandStrategyProvider with argument of ApplicationContext type. It also initializes * commandStrategies using init() function by filling it with available CommandStrategies in @@ -81,46 +120,88 @@ public class CommandStrategyProvider { * command Strategy will have to be added within this function in order to initiate it within the constructor. */ private static void init() { - commandStrategies.put(CommandContext.resource("clients").method("POST").build(), "createClientCommandStrategy"); - commandStrategies.put(CommandContext.resource("clients\\/\\d+").method("PUT").build(), "updateClientCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans").method("POST").build(), "applyLoanCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+").method("GET").build(), "getLoanByIdCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans/\\d+(\\?(\\w+(?:\\=[\\w,]+|&)+)+)").method("GET").build(), + commandStrategies.put(CommandContext.resource("clients").method(POST).build(), "createClientCommandStrategy"); + commandStrategies.put(CommandContext.resource("clients\\/" + NUMBER_REGEX).method(PUT).build(), "updateClientCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans").method(POST).build(), "applyLoanCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans\\/" + NUMBER_REGEX + OPTIONAL_QUERY_PARAM_REGEX).method(GET).build(), "getLoanByIdCommandStrategy"); - commandStrategies.put(CommandContext.resource("savingsaccounts").method("POST").build(), "applySavingsCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges").method("POST").build(), "createChargeCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges").method("GET").build(), "collectChargesCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges\\/\\d+").method("GET").build(), + commandStrategies.put( + CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + OPTIONAL_QUERY_PARAM_REGEX).method(GET).build(), + "getLoanByExternalIdCommandStrategy"); + commandStrategies.put(CommandContext.resource("savingsaccounts").method(POST).build(), "applySavingsCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans\\/" + NUMBER_REGEX + "\\/charges").method(POST).build(), + "createChargeCommandStrategy"); + commandStrategies + .put(CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + "\\/charges" + OPTIONAL_COMMAND_PARAM_REGEX + "") + .method(POST).build(), "createChargeByLoanExternalIdCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans\\/" + NUMBER_REGEX + "\\/charges").method(GET).build(), + "collectChargesCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + "\\/charges").method(GET).build(), + "collectChargesByLoanExternalIdCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans\\/" + NUMBER_REGEX + "\\/charges\\/" + NUMBER_REGEX).method(GET).build(), "getChargeByIdCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/transactions\\?(\\w+(\\=[\\w]+))").method("POST").build(), + commandStrategies.put(CommandContext.resource( + "loans\\/external-id\\/" + UUID_PARAM_REGEX + "\\/charges\\/external-id\\/" + UUID_PARAM_REGEX + OPTIONAL_QUERY_PARAM_REGEX) + .method(GET).build(), "getChargeByChargeExternalIdCommandStrategy"); + commandStrategies.put(CommandContext + .resource("loans\\/" + NUMBER_REGEX + "\\/charges\\/" + NUMBER_REGEX + MANDATORY_COMMAND_PARAM_REGEX).method(POST).build(), + "adjustChargeCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + "\\/charges\\/external-id\\/" + + UUID_PARAM_REGEX + MANDATORY_COMMAND_PARAM_REGEX).method(POST).build(), "adjustChargeByChargeExternalIdCommandStrategy"); + commandStrategies.put( + CommandContext.resource("loans\\/" + NUMBER_REGEX + "\\/transactions" + MANDATORY_COMMAND_PARAM_REGEX).method(POST).build(), "createTransactionLoanCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/transactions\\/\\d+(\\?command=[\\w]+)?").method("POST").build(), - "adjustTransactionCommandStrategy"); - commandStrategies.put(CommandContext.resource("clients\\/\\d+\\?command=activate").method("POST").build(), + commandStrategies.put( + CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + "\\/transactions" + MANDATORY_COMMAND_PARAM_REGEX) + .method(POST).build(), + "createTransactionByLoanExternalIdCommandStrategy"); + commandStrategies + .put(CommandContext.resource("loans\\/" + NUMBER_REGEX + "\\/transactions\\/" + NUMBER_REGEX + OPTIONAL_COMMAND_PARAM_REGEX) + .method(POST).build(), "adjustTransactionCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + "\\/transactions\\/external-id\\/" + + UUID_PARAM_REGEX + OPTIONAL_COMMAND_PARAM_REGEX).method(POST).build(), "adjustTransactionByExternalIdCommandStrategy"); + commandStrategies.put(CommandContext.resource("clients\\/" + NUMBER_REGEX + "\\?command=activate").method(POST).build(), "activateClientCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+\\?command=approve").method("POST").build(), + commandStrategies.put(CommandContext.resource("loans\\/" + NUMBER_REGEX + "\\?command=approve").method(POST).build(), "approveLoanCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+\\?command=disburse").method("POST").build(), + commandStrategies.put(CommandContext.resource("loans\\/" + NUMBER_REGEX + "\\?command=disburse").method(POST).build(), "disburseLoanCommandStrategy"); - commandStrategies.put(CommandContext.resource("rescheduleloans").method("POST").build(), + commandStrategies.put( + CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + MANDATORY_COMMAND_PARAM_REGEX).method(POST).build(), + "loanStateTransistionsByExternalIdCommandStrategy"); + commandStrategies.put(CommandContext.resource("rescheduleloans").method(POST).build(), "createLoanRescheduleRequestCommandStrategy"); - commandStrategies.put(CommandContext.resource("rescheduleloans\\/\\d+\\?command=approve").method("POST").build(), + commandStrategies.put(CommandContext.resource("rescheduleloans\\/" + NUMBER_REGEX + "\\?command=approve").method(POST).build(), "approveLoanRescheduleCommandStrategy"); - commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/transactions\\/\\d+").method("GET").build(), + commandStrategies.put(CommandContext.resource("loans\\/" + NUMBER_REGEX + "\\/transactions\\/" + NUMBER_REGEX).method(GET).build(), "getTransactionByIdCommandStrategy"); - commandStrategies.put(CommandContext.resource("datatables\\/[a-zA-Z0-9_]*\\/\\d+").method("GET").build(), - "getDatatableEntryByAppTableIdCommandStrategy"); - commandStrategies.put(CommandContext.resource("datatables\\/[a-zA-Z0-9_]*\\/\\d+").method("POST").build(), + commandStrategies.put(CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + "\\/transactions\\/external-id\\/" + + UUID_PARAM_REGEX + OPTIONAL_QUERY_PARAM_REGEX).method(GET).build(), "getTransactionByExternalIdCommandStrategy"); + commandStrategies.put( + CommandContext.resource("datatables\\/" + ALPHANUMBERIC_WITH_UNDERSCORE_REGEX + "\\/" + NUMBER_REGEX).method(POST).build(), "createDatatableEntryCommandStrategy"); - commandStrategies.put(CommandContext.resource("datatables\\/[a-zA-Z0-9_]*\\/\\d+\\/\\d+").method("PUT").build(), + commandStrategies.put( + CommandContext.resource("datatables\\/" + ALPHANUMBERIC_WITH_UNDERSCORE_REGEX + "\\/" + NUMBER_REGEX + "\\/" + NUMBER_REGEX) + .method(PUT).build(), "updateDatatableEntryOneToManyCommandStrategy"); - commandStrategies.put(CommandContext.resource("datatables\\/[a-zA-Z0-9_]*\\/\\d+").method("PUT").build(), + commandStrategies.put( + CommandContext.resource("datatables\\/" + ALPHANUMBERIC_WITH_UNDERSCORE_REGEX + "\\/" + NUMBER_REGEX).method(PUT).build(), "updateDatatableEntryOneToOneCommandStrategy"); commandStrategies.put( - CommandContext.resource("datatables\\/[a-zA-Z0-9_]*\\/\\d+(\\?(\\w+(?:\\=[\\w,]+|&)+)+)").method("GET").build(), - "getDatatableEntryByAppTableIdCommandStrategy"); + CommandContext.resource("datatables\\/" + ALPHANUMBERIC_WITH_UNDERSCORE_REGEX + "\\/" + NUMBER_REGEX + "\\/" + NUMBER_REGEX) + .method(PUT).build(), + "updateDatatableEntryOneToManyCommandStrategy"); + commandStrategies.put(CommandContext + .resource("datatables\\/" + ALPHANUMBERIC_WITH_UNDERSCORE_REGEX + "\\/" + NUMBER_REGEX + OPTIONAL_QUERY_PARAM_REGEX) + .method(GET).build(), "getDatatableEntryByAppTableIdCommandStrategy"); + commandStrategies.put(CommandContext.resource("loans\\/" + NUMBER_REGEX + OPTIONAL_COMMAND_PARAM_REGEX).method(PUT).build(), + "modifyLoanApplicationCommandStrategy"); commandStrategies.put( - CommandContext.resource("datatables\\/[a-zA-Z0-9_]*\\/query(\\?(\\w+(?:\\=[\\w,]+|&)+)+)").method("GET").build(), + CommandContext.resource("loans\\/external-id\\/" + UUID_PARAM_REGEX + OPTIONAL_COMMAND_PARAM_REGEX).method(PUT).build(), + "modifyLoanApplicationByExternalIdCommandStrategy"); + commandStrategies.put( + CommandContext.resource("datatables\\/" + ALPHANUMBERIC_WITH_UNDERSCORE_REGEX + "\\/query" + MANDATORY_QUERY_PARAM_REGEX) + .method(GET).build(), "getDatatableEntryByQueryCommandStrategy"); } 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 20ab7e3ea..b0b8eb88b 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 @@ -26,6 +26,7 @@ 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.portfolio.client.api.ClientsApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -57,13 +58,13 @@ public class ActivateClientCommandStrategy implements CommandStrategy { response.setHeaders(request.getHeaders()); final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); - Long clientId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?"))); + final Long clientId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?"))); // Calls 'activate' function from 'ClientsApiResource' to activate a // client responseBody = clientsApiResource.activate(clientId, "activate", request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after the successful activation of // the client response.setBody(responseBody); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustChargeByChargeExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustChargeByChargeExternalIdCommandStrategy.java new file mode 100644 index 000000000..eb6e4961a --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustChargeByChargeExternalIdCommandStrategy.java @@ -0,0 +1,99 @@ +/** + * 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 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.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} to adjust a charge using external id. It passes the contents of the body from the + * BatchRequest to {@link LoanChargesApiResource} and gets back the response. This class will also catch any errors + * raised by {@link LoanChargesApiResource} and map those errors to appropriate status codes in BatchResponse. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class AdjustChargeByChargeExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loan charges api resource {@link LoanChargesApiResource}. + */ + private final LoanChargesApiResource loanChargesApiResource; + + @Override + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + final String relativeUrl = request.getRelativeUrl(); + + // Expected pattern - loans\/external-id\/[\w\d_-]+\/charges\/external-id\/[\w\d_-]+(\?command=[\w]+)? + // Get the loan and charge ids for use in loanChargesApiResource + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + String loanExternalId = pathParameters.get(2); + + final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+"); + final Matcher commandMatcher = commandPattern.matcher(pathParameters.get(5)); + + 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; + } + final String commandQueryParam = commandMatcher.group(0); + final String command = commandQueryParam.substring(commandQueryParam.indexOf("=") + 1); + + final String chargeExternalIdPathParameter = pathParameters.get(5); + String loanChargeExternalId; + if (chargeExternalIdPathParameter.contains("?")) { + loanChargeExternalId = pathParameters.get(5).substring(0, pathParameters.get(5).indexOf("?")); + } else { + loanChargeExternalId = pathParameters.get(5); + } + + // Calls 'executeLoanCharge' function from 'loanChargesApiResource' using external id + responseBody = loanChargesApiResource.executeLoanCharge(loanExternalId, loanChargeExternalId, command, request.getBody()); + + response.setStatusCode(HttpStatus.SC_OK); + + // Sets the body of the response after retrieving the charge + response.setBody(responseBody); + + return response; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustChargeCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustChargeCommandStrategy.java new file mode 100644 index 000000000..1ee3f437e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustChargeCommandStrategy.java @@ -0,0 +1,98 @@ +/** + * 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 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.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} to adjust a charge. It passes the contents of the body from the BatchRequest to + * {@link LoanChargesApiResource} and gets back the response. This class will also catch any errors raised by + * {@link LoanChargesApiResource} and map those errors to appropriate status codes in BatchResponse. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class AdjustChargeCommandStrategy implements CommandStrategy { + + /** + * Loan charges api resource {@link LoanChargesApiResource}. + */ + private final LoanChargesApiResource loanChargesApiResource; + + @Override + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + final String relativeUrl = request.getRelativeUrl(); + + // Get the loan and charge ids for use in loanChargesApiResource + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + final Long loanId = Long.parseLong(pathParameters.get(1)); + + final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+"); + final Matcher commandMatcher = commandPattern.matcher(pathParameters.get(3)); + + 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; + } + final String commandQueryParam = commandMatcher.group(0); + final String command = commandQueryParam.substring(commandQueryParam.indexOf("=") + 1); + + final String chargeIdPathParameter = pathParameters.get(3); + Long loanChargeId; + if (chargeIdPathParameter.contains("?")) { + loanChargeId = Long.parseLong(pathParameters.get(3).substring(0, pathParameters.get(3).indexOf("?"))); + } else { + loanChargeId = Long.parseLong(pathParameters.get(3)); + } + + // Calls 'executeLoanCharge' function from 'loanChargesApiResource' + responseBody = loanChargesApiResource.executeLoanCharge(loanId, loanChargeId, command, request.getBody()); + + response.setStatusCode(HttpStatus.SC_OK); + + // Sets the body of the response after retrieving the charge + response.setBody(responseBody); + + return response; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustTransactionByExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustTransactionByExternalIdCommandStrategy.java new file mode 100644 index 000000000..d0d5f21c3 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustTransactionByExternalIdCommandStrategy.java @@ -0,0 +1,89 @@ +/** + * 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 com.google.common.base.Splitter; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.UriInfo; +import lombok.RequiredArgsConstructor; +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.portfolio.loanaccount.api.LoanTransactionsApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} to adjust a transaction by external id. 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. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class AdjustTransactionByExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loan transactions api resource {@link LoanTransactionsApiResource}. + */ + private final LoanTransactionsApiResource loanTransactionsApiResource; + + @Override + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + final String relativeUrl = request.getRelativeUrl(); + + // Expected URL pattern - loans\/external-id\/[\w\d_-]+\/transactions\/external-id\/[\w\d_-]+(\?command=[\w]+)? + // Get the loan and transaction ids for use in loanTransactionsApiResource + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + final String loanExternalId = pathParameters.get(2); + + final String transactionIdPathParameter = pathParameters.get(5); + String transactionExternalId; + if (transactionIdPathParameter.contains("?")) { + transactionExternalId = transactionIdPathParameter.substring(0, transactionIdPathParameter.indexOf("?")); + } else { + transactionExternalId = transactionIdPathParameter; + } + + final Map queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + final String command = queryParameters.get("command"); + + // Calls 'adjustLoanTransaction' function from 'loanTransactionsApiResource' using external-id + responseBody = loanTransactionsApiResource.adjustLoanTransaction(loanExternalId, transactionExternalId, request.getBody(), command); + + response.setStatusCode(HttpStatus.SC_OK); + + // 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/AdjustTransactionCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustTransactionCommandStrategy.java index 038a9064a..572ff88bd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustTransactionCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/AdjustTransactionCommandStrategy.java @@ -44,10 +44,13 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class AdjustTransactionCommandStrategy implements CommandStrategy { + /** + * Loan transactions api resource {@link LoanTransactionsApiResource}. + */ private final LoanTransactionsApiResource loanTransactionsApiResource; @Override - public BatchResponse execute(final BatchRequest request, UriInfo uriInfo) { + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { final BatchResponse response = new BatchResponse(); final String responseBody; @@ -58,7 +61,7 @@ public class AdjustTransactionCommandStrategy implements CommandStrategy { // Get the loan and transaction ids for use in loanTransactionsApiResource final List pathParameters = Splitter.on('/').splitToList(relativeUrl); - Long loanId = Long.parseLong(pathParameters.get(1)); + final Long loanId = Long.parseLong(pathParameters.get(1)); final String transactionIdPathParameter = pathParameters.get(3); Long transactionId; @@ -68,8 +71,8 @@ public class AdjustTransactionCommandStrategy implements CommandStrategy { transactionId = Long.parseLong(pathParameters.get(3)); } - Map queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); - String command = queryParameters.get("command"); + final Map queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + final String command = queryParameters.get("command"); // Calls 'adjustLoanTransaction' function from 'loanTransactionsApiResource' responseBody = loanTransactionsApiResource.adjustLoanTransaction(loanId, transactionId, request.getBody(), command); 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 c6e9639b5..946fc2036 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 @@ -24,6 +24,7 @@ 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.portfolio.loanaccount.api.LoansApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -58,7 +59,7 @@ public class ApplyLoanCommandStrategy implements CommandStrategy { // Apply Loan to an existing client responseBody = loansApiResource.calculateLoanScheduleOrSubmitLoanApplication(null, null, request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after loan is successfully applied response.setBody(responseBody); 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 a5c2a914f..17d069d47 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 @@ -24,6 +24,7 @@ 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.portfolio.savings.api.SavingsAccountsApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -59,7 +60,7 @@ public class ApplySavingsCommandStrategy implements CommandStrategy { // client responseBody = savingsAccountsApiResource.submitApplication(request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after savings is successfully // applied response.setBody(responseBody); 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 c517e4119..ef98ff6c1 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 @@ -26,6 +26,7 @@ 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.portfolio.loanaccount.api.LoansApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -57,13 +58,13 @@ public class ApproveLoanCommandStrategy implements CommandStrategy { response.setHeaders(request.getHeaders()); final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); - Long loanId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?"))); + final Long loanId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?"))); // Calls 'approve' function from 'LoansApiResource' to approve a // loan responseBody = loansApiResource.stateTransitions(loanId, "approve", request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after the successful approval of a // loan response.setBody(responseBody); 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 15748e7da..a901015fb 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 @@ -26,6 +26,7 @@ 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.portfolio.loanaccount.rescheduleloan.api.RescheduleLoansApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; @Component @@ -35,7 +36,7 @@ public class ApproveLoanRescheduleCommandStrategy implements CommandStrategy { private final RescheduleLoansApiResource rescheduleLoansApiResource; @Override - public BatchResponse execute(BatchRequest request, UriInfo uriInfo) { + public BatchResponse execute(BatchRequest request, final UriInfo uriInfo) { final BatchResponse response = new BatchResponse(); final String responseBody; @@ -43,14 +44,14 @@ public class ApproveLoanRescheduleCommandStrategy implements CommandStrategy { response.setHeaders(request.getHeaders()); final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); - Long scheduleId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?"))); + final Long scheduleId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?"))); // Calls 'approve' function from 'Loans reschedule Request' to // approve a // loan responseBody = rescheduleLoansApiResource.updateLoanRescheduleRequest(scheduleId, "approve", request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after the successful approval of a // Loans reschedule Request response.setBody(responseBody); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CollectChargesByLoanExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CollectChargesByLoanExternalIdCommandStrategy.java new file mode 100644 index 000000000..bd411a994 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CollectChargesByLoanExternalIdCommandStrategy.java @@ -0,0 +1,88 @@ +/** + * 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 com.google.common.base.Splitter; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.UriInfo; +import lombok.RequiredArgsConstructor; +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.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} and Collect Charges for a Loan by external id. It passes the contents of the body + * from the BatchRequest to {@link LoanChargesApiResource} and gets back the response. This class will also catch any + * errors raised by {@link LoanChargesApiResource} and map those errors to appropriate status codes in BatchResponse. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class CollectChargesByLoanExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loan charges api resource {@link LoanChargesApiResource}. + */ + private final LoanChargesApiResource loanChargesApiResource; + + @Override + public BatchResponse execute(BatchRequest request, final 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(); + // Expected pattern - loans\/external-id\/[\w\d_-]+\/charges + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + + // Pluck out the loanExternalId out of the relative path + final String loanExternalId = pathParameters.get(2); + + Map queryParameters; + if (relativeUrl.indexOf('?') > 0) { + queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + + // Add the query parameters sent in the relative URL to UriInfo + CommandStrategyUtils.addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters); + } + + // Calls 'retrieveAllLoanCharges' function from + // 'LoanChargesApiResource' to Collect + // Charges for a loan + responseBody = loanChargesApiResource.retrieveAllLoanCharges(loanExternalId, parameterizedUriInfo); + + response.setStatusCode(HttpStatus.SC_OK); + // 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/CollectChargesCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CollectChargesCommandStrategy.java index 593ed0c69..72abb5018 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 @@ -26,6 +26,7 @@ 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.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -35,8 +36,6 @@ import org.springframework.stereotype.Component; * will also catch any errors raised by {@link org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource} and * map those errors to appropriate status codes in BatchResponse. * - * @author Rishabh Shukla - * * @see org.apache.fineract.batch.command.CommandStrategy * @see org.apache.fineract.batch.domain.BatchRequest * @see org.apache.fineract.batch.domain.BatchResponse @@ -45,10 +44,13 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class CollectChargesCommandStrategy implements CommandStrategy { + /** + * Loan charges api resource {@link LoanChargesApiResource}. + */ private final LoanChargesApiResource loanChargesApiResource; @Override - public BatchResponse execute(BatchRequest request, UriInfo uriInfo) { + public BatchResponse execute(BatchRequest request, final UriInfo uriInfo) { final BatchResponse response = new BatchResponse(); final String responseBody; @@ -59,14 +61,14 @@ public class CollectChargesCommandStrategy implements CommandStrategy { final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); // Pluck out the loanId out of the relative path - Long loanId = Long.parseLong(pathParameters.get(1)); + final Long loanId = Long.parseLong(pathParameters.get(1)); // Calls 'retrieveAllLoanCharges' function from // 'LoanChargesApiResource' to Collect // Charges for a loan responseBody = loanChargesApiResource.retrieveAllLoanCharges(loanId, uriInfo); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after Charges have been // successfully collected response.setBody(responseBody); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateChargeByLoanExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateChargeByLoanExternalIdCommandStrategy.java new file mode 100644 index 000000000..b935cd0a4 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateChargeByLoanExternalIdCommandStrategy.java @@ -0,0 +1,87 @@ +/** + * 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 com.google.common.base.Splitter; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.UriInfo; +import lombok.RequiredArgsConstructor; +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.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} and Create Charge for a Loan by external id. It passes the contents of the body + * from the BatchRequest to {@link LoanChargesApiResource} and gets back the response. This class will also catch any + * errors raised by {@link LoanChargesApiResource} and map those errors to appropriate status codes in BatchResponse. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class CreateChargeByLoanExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loan charges api resource {@link LoanChargesApiResource}. + */ + private final LoanChargesApiResource loanChargesApiResource; + + @Override + public BatchResponse execute(BatchRequest request, @SuppressWarnings("unused") final UriInfo uriInfo) { + + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + final String relativeUrl = request.getRelativeUrl(); + + // Expected pattern - loans\/external-id\/[\w\d_-]+\/charges + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + final String loanExternalIdPathParameter = pathParameters.get(2); + String loanExternalId; + if (loanExternalIdPathParameter.contains("?")) { + loanExternalId = pathParameters.get(2).substring(0, pathParameters.get(2).indexOf("?")); + } else { + loanExternalId = pathParameters.get(2); + } + + final Map queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + final String command = queryParameters.get("command"); + + // Calls 'executeLoanCharge' function from 'LoanChargesApiResource' + // to create a new charge for based on loan external id + responseBody = loanChargesApiResource.executeLoanCharge(loanExternalId, command, request.getBody()); + + response.setStatusCode(HttpStatus.SC_OK); + // 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/CreateChargeCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateChargeCommandStrategy.java index 7e7be136e..470f284c9 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 @@ -26,6 +26,7 @@ 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.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -57,14 +58,14 @@ public class CreateChargeCommandStrategy implements CommandStrategy { response.setHeaders(request.getHeaders()); final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); - Long loanId = Long.parseLong(pathParameters.get(1)); + final Long loanId = Long.parseLong(pathParameters.get(1)); // Calls 'executeLoanCharge' function from 'LoanChargesApiResource' // to create // a new charge for a loan responseBody = loanChargesApiResource.executeLoanCharge(loanId, null, request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after Charge has been successfully // created response.setBody(responseBody); 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 fc0d71757..76bae0f46 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 @@ -24,6 +24,7 @@ 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.portfolio.client.api.ClientsApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -58,7 +59,7 @@ public class CreateClientCommandStrategy implements CommandStrategy { // client responseBody = clientsApiResource.create(request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after the successful creation of // the client response.setBody(responseBody); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java index e757c073d..5bd41b630 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java @@ -26,6 +26,7 @@ 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.infrastructure.dataqueries.api.DatatablesApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -61,7 +62,7 @@ public class CreateDatatableEntryCommandStrategy implements CommandStrategy { // 'DatatablesApiResource' to create a datatable entry on an existing loan responseBody = datatablesApiResource.createDatatableEntry(datatableName, loanId, request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after datatable entry is successfully // created response.setBody(responseBody); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateLoanRescheduleRequestCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateLoanRescheduleRequestCommandStrategy.java index 256c5f050..a218593fb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateLoanRescheduleRequestCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateLoanRescheduleRequestCommandStrategy.java @@ -24,6 +24,7 @@ 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.portfolio.loanaccount.rescheduleloan.api.RescheduleLoansApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -55,7 +56,7 @@ public class CreateLoanRescheduleRequestCommandStrategy implements CommandStrate // 'RescheduleLoansApiResource' to create a reschedule request on an existing loan responseBody = rescheduleLoansApiResource.createLoanRescheduleRequest(request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after savings is successfully // applied response.setBody(responseBody); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategy.java new file mode 100644 index 000000000..550009817 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategy.java @@ -0,0 +1,89 @@ +/** + * 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 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.portfolio.loanaccount.api.LoanTransactionsApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} and handles the creation of a transaction for a Loan using External Id. 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. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class CreateTransactionByLoanExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loan transactions api resource {@link LoanTransactionsApiResource}. + */ + private final LoanTransactionsApiResource loanTransactionsApiResource; + + @Override + public BatchResponse execute(BatchRequest request, @SuppressWarnings("unused") UriInfo uriInfo) { + + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + // Expected Pattern - loans\/external-id\/[a-zA-Z0-9_-]*\/transactions\?command=[\w]+ + final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); + final String loanExternalId = pathParameters.get(2); + + final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+"); + final Matcher commandMatcher = commandPattern.matcher(pathParameters.get(3)); + + 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; + } + final String commandQueryParam = commandMatcher.group(0); + final String command = commandQueryParam.substring(commandQueryParam.indexOf("=") + 1); + + responseBody = loanTransactionsApiResource.executeLoanTransaction(loanExternalId, command, request.getBody()); + + response.setStatusCode(HttpStatus.SC_OK); + // 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/CreateTransactionLoanCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java index a192b2624..1cb4cac28 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java @@ -37,8 +37,6 @@ import org.springframework.stereotype.Component; * also catch any errors raised by {@link LoanTransactionsApiResource} and map those errors to appropriate status codes * in BatchResponse. * - * @author Mohit Sinha - * * @see CommandStrategy * @see BatchRequest * @see BatchResponse @@ -47,6 +45,9 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class CreateTransactionLoanCommandStrategy implements CommandStrategy { + /** + * Loan transactions api resource {@link LoanTransactionsApiResource}. + */ private final LoanTransactionsApiResource loanTransactionsApiResource; @Override @@ -59,10 +60,10 @@ public class CreateTransactionLoanCommandStrategy implements CommandStrategy { response.setHeaders(request.getHeaders()); final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); - Long loanId = Long.parseLong(pathParameters.get(1)); + final Long loanId = Long.parseLong(pathParameters.get(1)); - Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+"); - Matcher commandMatcher = commandPattern.matcher(pathParameters.get(2)); + final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+"); + final Matcher commandMatcher = commandPattern.matcher(pathParameters.get(2)); if (!commandMatcher.find()) { // This would only occur if the CommandStrategyProvider is incorrectly configured. @@ -72,12 +73,12 @@ public class CreateTransactionLoanCommandStrategy implements CommandStrategy { "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); + final String commandQueryParam = commandMatcher.group(0); + final String command = commandQueryParam.substring(commandQueryParam.indexOf("=") + 1); responseBody = loanTransactionsApiResource.executeLoanTransaction(loanId, command, request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after Charge has been successfully // created response.setBody(responseBody); 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 cffd07bd2..88fa9d60a 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 @@ -26,6 +26,7 @@ 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.portfolio.loanaccount.api.LoansApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -57,13 +58,13 @@ public class DisburseLoanCommandStrategy implements CommandStrategy { response.setHeaders(request.getHeaders()); final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); - Long loanId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?"))); + final Long loanId = Long.parseLong(pathParameters.get(1).substring(0, pathParameters.get(1).indexOf("?"))); // Calls 'disburse' function from 'LoansApiResource' to disburse a // loan responseBody = loansApiResource.stateTransitions(loanId, "disburse", request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after the successful disbursal of // the loan diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByChargeExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByChargeExternalIdCommandStrategy.java new file mode 100644 index 000000000..2ca8f6321 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByChargeExternalIdCommandStrategy.java @@ -0,0 +1,91 @@ +/** + * 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 com.google.common.base.Splitter; +import java.util.List; +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.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} to retrieve a charge by external id. It passes the contents of the body from the + * BatchRequest to {@link LoanChargesApiResource} and gets back the response. This class will also catch any errors + * raised by {@link LoanChargesApiResource} and map those errors to appropriate status codes in BatchResponse. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class GetChargeByChargeExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loan charges api resource {@link LoanChargesApiResource}. + */ + private final LoanChargesApiResource loanChargesApiResource; + + @Override + public BatchResponse execute(final BatchRequest request, final 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(); + + // Expected pattern - loans\/external-id\/[\w\d_-]+\/charges\/external-id\/[\w\d_-]+ + // Get the loan and charge external ids for use in loanChargesApiResource + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + final String loanExternalId = pathParameters.get(2); + String chargeExternalId; + if (relativeUrl.indexOf('?') > 0) { + chargeExternalId = StringUtils.substringBeforeLast(pathParameters.get(5), "?"); + } else { + chargeExternalId = pathParameters.get(5); + } + + Map queryParameters; + if (relativeUrl.indexOf('?') > 0) { + queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + + // Add the query parameters sent in the relative URL to UriInfo + CommandStrategyUtils.addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters); + } + + responseBody = loanChargesApiResource.retrieveLoanCharge(loanExternalId, chargeExternalId, parameterizedUriInfo); + response.setStatusCode(HttpStatus.SC_OK); + response.setBody(responseBody); + + return response; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategy.java index 2df109b1d..0fd4d3036 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategy.java @@ -46,10 +46,13 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class GetChargeByIdCommandStrategy implements CommandStrategy { + /** + * Loan charges api resource {@link LoanChargesApiResource}. + */ private final LoanChargesApiResource loanChargesApiResource; @Override - public BatchResponse execute(final BatchRequest request, UriInfo uriInfo) { + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { final MutableUriInfo parameterizedUriInfo = new MutableUriInfo(uriInfo); final BatchResponse response = new BatchResponse(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetLoanByExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetLoanByExternalIdCommandStrategy.java new file mode 100644 index 000000000..9daac5f8c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetLoanByExternalIdCommandStrategy.java @@ -0,0 +1,152 @@ +/** + * 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 com.google.common.base.Splitter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.UriInfo; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.BooleanUtils; +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.infrastructure.core.api.MutableUriInfo; +import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} and get loan by external id. It passes the contents of the body from the + * BatchRequest to {@link LoansApiResource} and gets back the response. This class will also catch any errors raised by + * {@link LoansApiResource} and map those errors to appropriate status codes in BatchResponse. + */ +@Component +@RequiredArgsConstructor +public class GetLoanByExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loans api resource {@link LoansApiResource}. + */ + private final LoansApiResource loansApiResource; + + @Override + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { + final MutableUriInfo parameterizedUriInfo = new MutableUriInfo(uriInfo); + + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + // Expected pattern - loans\/external-id\/[\w\d_-]+\?associations=transactions + final String relativeUrl = request.getRelativeUrl(); + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + final String loanExternalIdPathParameter = pathParameters.get(2); + + String loanExternalId; + + // 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/external-id/ff62fc65-1bba-4bb0-b090-5f9ecf0a66f1?fields=id,principal,annualInterestRate) + // - Add them to the UriInfo query parameters list + // - Call loansApiResource.retrieveLoan(loanExternalId, false, uriInfo) + // - Remove the relative url query parameters from UriInfo in the finally (after loan details are retrieved) + Map queryParameters = null; + if (loanExternalIdPathParameter.indexOf('?') > 0) { + loanExternalId = StringUtils.substringBefore(loanExternalIdPathParameter, "?"); + queryParameters = getQueryParameters(relativeUrl); + + // Add the query parameters sent in the relative URL to UriInfo + addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters); + } else { + loanExternalId = loanExternalIdPathParameter; + } + + // Calls 'retrieveLoan' function from 'LoansApiResource' to + // get the loan details based on the loan external id + 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"); + } + if (queryParameters.containsKey("staffInSelectedOfficeOnly")) { + staffInSelectedOfficeOnly = BooleanUtils.toBoolean(queryParameters.get("staffInSelectedOfficeOnly")); + } + } + + responseBody = loansApiResource.retrieveLoan(loanExternalId, staffInSelectedOfficeOnly, associations, exclude, fields, + parameterizedUriInfo); + + response.setStatusCode(HttpStatus.SC_OK); + + // Sets the response after retrieving the loan + response.setBody(responseBody); + + return response; + } + + /** + * Get query parameters from relative URL. + * + * @param relativeUrl + * the relative URL + * @return the query parameters in a map + */ + private Map getQueryParameters(final String relativeUrl) { + final String queryParameterStr = StringUtils.substringAfter(relativeUrl, "?"); + final String[] queryParametersArray = StringUtils.split(queryParameterStr, "&"); + final Map queryParametersMap = new HashMap<>(); + for (String parameterStr : queryParametersArray) { + String[] keyValue = StringUtils.split(parameterStr, "="); + queryParametersMap.put(keyValue[0], keyValue[1]); + } + return queryParametersMap; + } + + /** + * Add query parameters(received in the relative URL) to URI info query parameters. + * + * @param uriInfo + * the URI info + * @param queryParameters + * the query parameters + */ + private void addQueryParametersToUriInfo(final MutableUriInfo uriInfo, final Map queryParameters) { + for (Map.Entry entry : queryParameters.entrySet()) { + uriInfo.addAdditionalQueryParameter(entry.getKey(), entry.getValue()); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByExternalIdCommandStrategy.java new file mode 100644 index 000000000..12a5505fc --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByExternalIdCommandStrategy.java @@ -0,0 +1,105 @@ +/** + * 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 com.google.common.base.Splitter; +import java.util.HashMap; +import java.util.List; +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.portfolio.loanaccount.api.LoanTransactionsApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} to retrieve a transaction by external id. 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. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class GetTransactionByExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loan transactions api resource {@link LoanTransactionsApiResource}. + */ + private final LoanTransactionsApiResource loanTransactionsApiResource; + + @Override + public BatchResponse execute(final BatchRequest request, final 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(); + + // Expected pattern - loans\/external-id\/[\w\d_-]+\/transactions\/external-id\/[\w\d_-]+ + // Get the loan and transaction ids for use in loanTransactionsApiResource + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + final String loanExternalId = pathParameters.get(2); + String transactionExternalId; + if (relativeUrl.indexOf('?') > 0) { + transactionExternalId = StringUtils.substringBeforeLast(pathParameters.get(5), "?"); + } else { + transactionExternalId = pathParameters.get(5); + } + + Map queryParameters = new HashMap<>(); + if (relativeUrl.indexOf('?') > 0) { + queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + + // Add the query parameters sent in the relative URL to UriInfo + CommandStrategyUtils.addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters); + } + + String fields = null; + if (!queryParameters.isEmpty()) { + if (queryParameters.containsKey("fields")) { + fields = queryParameters.get("fields"); + } + } + + // Calls 'retrieveTransaction' function from 'loanTransactionsApiResource' using external id + responseBody = loanTransactionsApiResource.retrieveTransactionByLoanExternalIdAndTransactionExternalId(loanExternalId, + transactionExternalId, fields, uriInfo); + + response.setStatusCode(HttpStatus.SC_OK); + + // 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/GetTransactionByIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java index bec9b431c..ea06239c8 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 @@ -47,10 +47,13 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class GetTransactionByIdCommandStrategy implements CommandStrategy { + /** + * Loan transactions api resource {@link LoanTransactionsApiResource}. + */ private final LoanTransactionsApiResource loanTransactionsApiResource; @Override - public BatchResponse execute(final BatchRequest request, UriInfo uriInfo) { + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { final MutableUriInfo parameterizedUriInfo = new MutableUriInfo(uriInfo); final BatchResponse response = new BatchResponse(); @@ -63,7 +66,7 @@ public class GetTransactionByIdCommandStrategy implements CommandStrategy { // Get the loan and transaction ids for use in loanTransactionsApiResource final List pathParameters = Splitter.on('/').splitToList(relativeUrl); - Long loanId = Long.parseLong(pathParameters.get(1)); + final Long loanId = Long.parseLong(pathParameters.get(1)); Long transactionId; if (relativeUrl.indexOf('?') > 0) { transactionId = Long.parseLong(StringUtils.substringBeforeLast(pathParameters.get(3), "?")); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/LoanStateTransistionsByExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/LoanStateTransistionsByExternalIdCommandStrategy.java new file mode 100644 index 000000000..8177ee965 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/LoanStateTransistionsByExternalIdCommandStrategy.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 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.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.portfolio.loanaccount.api.LoansApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} to handle approval of a pending loan by its external id. It passes the contents of + * the body from the BatchRequest to {@link LoansApiResource} and gets back the response. This class will also catch any + * errors raised by {@link LoansApiResource} and map those errors to appropriate status codes in BatchResponse. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class LoanStateTransistionsByExternalIdCommandStrategy implements CommandStrategy { + + /** + * Loans api resource {@link LoansApiResource}. + */ + private final LoansApiResource loansApiResource; + + @Override + public BatchResponse execute(final BatchRequest request, @SuppressWarnings("unused") final UriInfo uriInfo) { + + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + // Expected pattern - loans\/external-id\/[\w\d_-]+\?command=*** + final String relativeUrl = request.getRelativeUrl(); + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + final String loanExternalIdPathParameter = pathParameters.get(2); + + final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+"); + final Matcher commandMatcher = commandPattern.matcher(loanExternalIdPathParameter); + + 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; + } + final String commandQueryParam = commandMatcher.group(0); + final String command = commandQueryParam.substring(commandQueryParam.indexOf("=") + 1); + + final String loanExternalId = StringUtils.substringBefore(loanExternalIdPathParameter, "?"); + + // Calls 'approve'/'disburse' function from 'LoansApiResource' to approve/disburse loan + responseBody = loansApiResource.stateTransitions(loanExternalId, command, request.getBody()); + + response.setStatusCode(HttpStatus.SC_OK); + // 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/ModifyLoanApplicationByExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationByExternalIdCommandStrategy.java new file mode 100644 index 000000000..9efd78149 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationByExternalIdCommandStrategy.java @@ -0,0 +1,96 @@ +/** + * 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 com.google.common.base.Splitter; +import java.util.List; +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.portfolio.loanaccount.api.LoansApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link CommandStrategy} to handle any updates to the loan application. It passes the contents of the body + * from the BatchRequest to {@link LoansApiResource} and gets back the response. This class will also catch any errors + * raised by {@link LoansApiResource} and map those errors to appropriate status codes in BatchResponse. + * + * @see CommandStrategy + * @see BatchRequest + * @see BatchResponse + */ +@Component +@RequiredArgsConstructor +public class ModifyLoanApplicationByExternalIdCommandStrategy implements CommandStrategy { + + /** + * {@link LoansApiResource} object + */ + private final LoansApiResource loansApiResource; + + /** + * Returns {@link BatchResponse} object by taking in and executing {@link BatchRequest} object. + * + * @param request + * the {@link BatchRequest} object + * @param uriInfo + * the {@link UriInfo} object + * @return response the {@link BatchResponse} object + */ + @Override + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + // Expected pattern - loans\/external-id\/[\w\d_-]+\?command=adjust + final String relativeUrl = request.getRelativeUrl(); + + // Get the loan id for use in loansApiResource + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + + final String loanIdPathParameter = pathParameters.get(2); + String loanExternalId; + if (loanIdPathParameter.contains("?")) { + loanExternalId = StringUtils.substringBefore(loanIdPathParameter, "?"); + } else { + loanExternalId = loanIdPathParameter; + } + + final Map queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + final String command = queryParameters.get("command"); + + responseBody = loansApiResource.modifyLoanApplication(loanExternalId, command, request.getBody()); + + response.setStatusCode(HttpStatus.SC_OK); + + // Sets the body of the response modifying the loan application + response.setBody(responseBody); + return response; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationCommandStrategy.java new file mode 100644 index 000000000..922a8cf9e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationCommandStrategy.java @@ -0,0 +1,97 @@ +/** + * 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 com.google.common.base.Splitter; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.UriInfo; +import lombok.RequiredArgsConstructor; +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.portfolio.loanaccount.api.LoansApiResource; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Implements {@link org.apache.fineract.batch.command.CommandStrategy} to handle any updates to the loan application. + * It passes the contents of the body from the BatchRequest to + * {@link org.apache.fineract.portfolio.loanaccount.api.LoansApiResource} and gets back the response. This class will + * also catch any errors raised by {@link org.apache.fineract.portfolio.loanaccount.api.LoansApiResource} and map those + * errors to appropriate status codes in BatchResponse. + * + * @see org.apache.fineract.batch.command.CommandStrategy + * @see org.apache.fineract.batch.domain.BatchRequest + * @see org.apache.fineract.batch.domain.BatchResponse + */ +@Component +@RequiredArgsConstructor +public class ModifyLoanApplicationCommandStrategy implements CommandStrategy { + + /** + * {@link LoansApiResource} object + */ + private final LoansApiResource loansApiResource; + + /** + * Returns {@link org.apache.fineract.batch.domain.BatchResponse} object by taking in and executing + * {@link org.apache.fineract.batch.domain.BatchRequest} object. + * + * @param request + * the {@link org.apache.fineract.batch.domain.BatchRequest} object + * @param uriInfo + * the {@link UriInfo} object + * @return response the {@link org.apache.fineract.batch.domain.BatchResponse} object + */ + @Override + public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) { + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + final String relativeUrl = request.getRelativeUrl(); + + // Get the loan id for use in loansApiResource + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + + final String loanIdPathParameter = pathParameters.get(1); + Long loanId; + if (loanIdPathParameter.contains("?")) { + loanId = Long.parseLong(loanIdPathParameter.substring(0, loanIdPathParameter.indexOf("?"))); + } else { + loanId = Long.parseLong(loanIdPathParameter); + } + + final Map queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + final String command = queryParameters.get("command"); + + responseBody = loansApiResource.modifyLoanApplication(loanId, command, request.getBody()); + + response.setStatusCode(HttpStatus.SC_OK); + + // Sets the body of the response modifying the loan application + 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 9d0e3aae7..1e53d313f 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 @@ -24,6 +24,7 @@ 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.portfolio.client.api.ClientsApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -62,7 +63,7 @@ public class UpdateClientCommandStrategy implements CommandStrategy { // client responseBody = clientsApiResource.update(clientId, request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after the successful update of // client information response.setBody(responseBody); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/UpdateDatatableEntryOneToManyCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/UpdateDatatableEntryOneToManyCommandStrategy.java index 96e990ccd..de903a371 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/UpdateDatatableEntryOneToManyCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/UpdateDatatableEntryOneToManyCommandStrategy.java @@ -26,6 +26,7 @@ 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.infrastructure.dataqueries.api.DatatablesApiResource; +import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; /** @@ -62,7 +63,7 @@ public class UpdateDatatableEntryOneToManyCommandStrategy implements CommandStra // 'DatatablesApiResource' to update a datatable entry on an existing entity in a one-many relationship responseBody = datatablesApiResource.updateDatatableEntryOneToMany(datatableName, entityId, datatableEntryId, request.getBody()); - response.setStatusCode(200); + response.setStatusCode(HttpStatus.SC_OK); // Sets the body of the response after datatable entry is successfully // updated response.setBody(responseBody); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResourceSwagger.java index f991d4894..17ee409a3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResourceSwagger.java @@ -107,6 +107,8 @@ final class LoanChargesApiResourceSwagger { public LocalDate submittedOnDate; @Schema(example = "95174ff9-1a75-4d72-a413-6f9b1cb988b7") public String externalId; + @Schema(example = "26 March 2013") + public LocalDate dueDate; } @Schema(description = "GetLoansLoanIdChargesTemplateResponse") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java index da2b2801a..caaae16de 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java @@ -957,6 +957,8 @@ final class LoansApiResourceSwagger { public boolean disallowExpectedDisbursements; @Schema(example = "1") public Integer clientId; + @Schema(example = "5e77989e-aa11-11bc-b109-0242ac120004") + public String clientExternalId; @Schema(example = "Kampala first Client") public String clientName; @Schema(example = "2") @@ -981,6 +983,8 @@ final class LoansApiResourceSwagger { public BigDecimal principal; @Schema(example = "1000.000000") public Double approvedPrincipal; + @Schema(example = "1001.000000") + public Double proposedPrincipal; @Schema(example = "200.000000") public Double netDisbursalAmount; @Schema(example = "12") @@ -996,6 +1000,8 @@ final class LoansApiResourceSwagger { public GetLoansLoanIdInterestRateFrequencyType interestRateFrequencyType; @Schema(example = "24") public Integer annualInterestRate; + @Schema(example = "false") + public Boolean isFloatingInterestRate; public GetLoansLoanIdAmortizationType amortizationType; @Schema(example = "5.5") public BigDecimal fixedPrincipalPercentagePerInstallment; @@ -1057,8 +1063,8 @@ final class LoansApiResourceSwagger { public String locale; @Schema(example = "1") public Integer productId; - @Schema(example = "100,000.00") - public String principal; + @Schema(example = "1000.00") + public BigDecimal principal; @Schema(example = "12") public Integer loanTermFrequency; @Schema(example = "2") @@ -1163,9 +1169,11 @@ final class LoansApiResourceSwagger { @Schema(example = "1") public Integer clientId; @Schema(example = "1") - public Integer loanId; + public Long loanId; @Schema(example = "1") - public Integer resourceId; + public Long resourceId; + @Schema(example = "95174ff9-1a75-4d72-a413-6f9b1cb988b7") + public String resourceExternalId; } @Schema(description = "PutLoansLoanIdRequest") @@ -1314,9 +1322,9 @@ final class LoansApiResourceSwagger { @Schema(example = "1") public Integer clientId; @Schema(example = "1") - public Integer loanId; + public Long loanId; @Schema(example = "1") - public Integer resourceId; + public Long resourceId; @Schema(example = "95174ff9-1a75-4d72-a413-6f9b1cb988b7") public String resourceExternalId; public PutLoansLoanIdChanges changes; @@ -1332,9 +1340,9 @@ final class LoansApiResourceSwagger { @Schema(example = "1") public Integer clientId; @Schema(example = "1") - public Integer loanId; + public Long loanId; @Schema(example = "1") - public Integer resourceId; + public Long resourceId; @Schema(example = "95174ff9-1a75-4d72-a413-6f9b1cb988b7") public String resourceExternalId; } @@ -1370,7 +1378,7 @@ final class LoansApiResourceSwagger { @Schema(example = "3e7791ce-aa10-11ec-b909-0242ac120002") public String externalId; @Schema(example = "5000.33") - public String transactionAmount; + public BigDecimal transactionAmount; @Schema(example = "Description of disbursement details.") public String note; @Schema(example = "28 June 2022") @@ -1380,7 +1388,7 @@ final class LoansApiResourceSwagger { @Schema(example = "28 June 2022") public String approvedOnDate; @Schema(example = "1000") - public String approvedLoanAmount; + public BigDecimal approvedLoanAmount; @Schema(example = "28 June 2022") public String expectedDisbursementDate; @Schema(example = "28 June 2022") 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 507e615e9..cd9cff795 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 @@ -25,25 +25,38 @@ import static org.mockito.Mockito.when; import java.util.stream.Stream; import javax.ws.rs.HttpMethod; import org.apache.fineract.batch.command.internal.ActivateClientCommandStrategy; +import org.apache.fineract.batch.command.internal.AdjustChargeByChargeExternalIdCommandStrategy; +import org.apache.fineract.batch.command.internal.AdjustChargeCommandStrategy; +import org.apache.fineract.batch.command.internal.AdjustTransactionByExternalIdCommandStrategy; import org.apache.fineract.batch.command.internal.AdjustTransactionCommandStrategy; import org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy; import org.apache.fineract.batch.command.internal.ApplySavingsCommandStrategy; import org.apache.fineract.batch.command.internal.ApproveLoanCommandStrategy; import org.apache.fineract.batch.command.internal.ApproveLoanRescheduleCommandStrategy; +import org.apache.fineract.batch.command.internal.CollectChargesByLoanExternalIdCommandStrategy; import org.apache.fineract.batch.command.internal.CollectChargesCommandStrategy; +import org.apache.fineract.batch.command.internal.CreateChargeByLoanExternalIdCommandStrategy; import org.apache.fineract.batch.command.internal.CreateChargeCommandStrategy; import org.apache.fineract.batch.command.internal.CreateClientCommandStrategy; import org.apache.fineract.batch.command.internal.CreateDatatableEntryCommandStrategy; import org.apache.fineract.batch.command.internal.CreateLoanRescheduleRequestCommandStrategy; +import org.apache.fineract.batch.command.internal.CreateTransactionByLoanExternalIdCommandStrategy; import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy; import org.apache.fineract.batch.command.internal.DisburseLoanCommandStrategy; +import org.apache.fineract.batch.command.internal.GetChargeByChargeExternalIdCommandStrategy; import org.apache.fineract.batch.command.internal.GetChargeByIdCommandStrategy; import org.apache.fineract.batch.command.internal.GetDatatableEntryByAppTableIdCommandStrategy; +import org.apache.fineract.batch.command.internal.GetDatatableEntryByQueryCommandStrategy; +import org.apache.fineract.batch.command.internal.GetLoanByExternalIdCommandStrategy; import org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy; +import org.apache.fineract.batch.command.internal.GetTransactionByExternalIdCommandStrategy; import org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy; +import org.apache.fineract.batch.command.internal.LoanStateTransistionsByExternalIdCommandStrategy; +import org.apache.fineract.batch.command.internal.ModifyLoanApplicationCommandStrategy; import org.apache.fineract.batch.command.internal.UnknownCommandStrategy; import org.apache.fineract.batch.command.internal.UpdateClientCommandStrategy; import org.apache.fineract.batch.command.internal.UpdateDatatableEntryOneToManyCommandStrategy; +import org.apache.fineract.batch.command.internal.UpdateDatatableEntryOneToOneCommandStrategy; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -68,12 +81,52 @@ public class CommandStrategyProviderTest { mock(GetLoanByIdCommandStrategy.class)), Arguments.of("loans/123?associations=all&exclude=guarantors", HttpMethod.GET, "getLoanByIdCommandStrategy", mock(GetLoanByIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1", HttpMethod.GET, "getLoanByExternalIdCommandStrategy", + mock(GetLoanByExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1?associations=all", HttpMethod.GET, + "getLoanByExternalIdCommandStrategy", mock(GetLoanByExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1?associations=all&exclude=guarantors", HttpMethod.GET, + "getLoanByExternalIdCommandStrategy", mock(GetLoanByExternalIdCommandStrategy.class)), Arguments.of("savingsaccounts", HttpMethod.POST, "applySavingsCommandStrategy", mock(ApplySavingsCommandStrategy.class)), Arguments.of("loans/123/charges", HttpMethod.POST, "createChargeCommandStrategy", mock(CreateChargeCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/charges", HttpMethod.POST, + "createChargeByLoanExternalIdCommandStrategy", mock(CreateChargeByLoanExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/charges?command=mycommand", HttpMethod.POST, + "createChargeByLoanExternalIdCommandStrategy", mock(CreateChargeByLoanExternalIdCommandStrategy.class)), Arguments.of("loans/123/charges", HttpMethod.GET, "collectChargesCommandStrategy", mock(CollectChargesCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/charges", HttpMethod.GET, + "collectChargesByLoanExternalIdCommandStrategy", mock(CollectChargesByLoanExternalIdCommandStrategy.class)), Arguments.of("loans/123/charges/123", HttpMethod.GET, "getChargeByIdCommandStrategy", mock(GetChargeByIdCommandStrategy.class)), + Arguments.of( + "loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/charges/external-id/7dfad438-2319-48ce-8520-10a62801e9ab", + HttpMethod.GET, "getChargeByChargeExternalIdCommandStrategy", + mock(GetChargeByChargeExternalIdCommandStrategy.class)), + Arguments.of( + "loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/charges/external-id/7dfad438-2319-48ce-8520-10a62801e9ab?fields=id", + HttpMethod.GET, "getChargeByChargeExternalIdCommandStrategy", + mock(GetChargeByChargeExternalIdCommandStrategy.class)), + Arguments.of("loans/123/charges/123?command=adjustment", HttpMethod.POST, "adjustChargeCommandStrategy", + mock(AdjustChargeCommandStrategy.class)), + Arguments.of( + "loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/charges/external-id/7dfad438-2319-48ce-8520-10a62801e9ab?command=adjustment", + HttpMethod.POST, "adjustChargeByChargeExternalIdCommandStrategy", + mock(AdjustChargeByChargeExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions?command=repayment", HttpMethod.POST, + "createTransactionByLoanExternalIdCommandStrategy", mock(CreateTransactionByLoanExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions?command=creditBalanceRefund", + HttpMethod.POST, "createTransactionByLoanExternalIdCommandStrategy", + mock(CreateTransactionByLoanExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions?command=goodwillCredit", HttpMethod.POST, + "createTransactionByLoanExternalIdCommandStrategy", mock(CreateTransactionByLoanExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions?command=merchantIssuedRefund", + HttpMethod.POST, "createTransactionByLoanExternalIdCommandStrategy", + mock(CreateTransactionByLoanExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions?command=payoutRefund", HttpMethod.POST, + "createTransactionByLoanExternalIdCommandStrategy", mock(CreateTransactionByLoanExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions?command=chargeRefund", HttpMethod.POST, + "createTransactionByLoanExternalIdCommandStrategy", mock(CreateTransactionByLoanExternalIdCommandStrategy.class)), Arguments.of("loans/123/transactions?command=repayment", HttpMethod.POST, "createTransactionLoanCommandStrategy", mock(CreateTransactionLoanCommandStrategy.class)), Arguments.of("loans/123/transactions?command=creditBalanceRefund", HttpMethod.POST, "createTransactionLoanCommandStrategy", @@ -90,18 +143,33 @@ public class CommandStrategyProviderTest { mock(AdjustTransactionCommandStrategy.class)), Arguments.of("loans/123/transactions/123?command=chargeback", HttpMethod.POST, "adjustTransactionCommandStrategy", mock(AdjustTransactionCommandStrategy.class)), + Arguments.of( + "loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions/external-id/7dfad438-2319-48ce-8520-10a62801e9ab", + HttpMethod.POST, "adjustTransactionByExternalIdCommandStrategy", + mock(AdjustTransactionByExternalIdCommandStrategy.class)), + Arguments.of( + "loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions/external-id/7dfad438-2319-48ce-8520-10a62801e9ab?command=chargeback", + HttpMethod.POST, "adjustTransactionByExternalIdCommandStrategy", + mock(AdjustTransactionByExternalIdCommandStrategy.class)), Arguments.of("clients/456?command=activate", HttpMethod.POST, "activateClientCommandStrategy", mock(ActivateClientCommandStrategy.class)), Arguments.of("loans/123?command=approve", HttpMethod.POST, "approveLoanCommandStrategy", mock(ApproveLoanCommandStrategy.class)), Arguments.of("loans/123?command=disburse", HttpMethod.POST, "disburseLoanCommandStrategy", mock(DisburseLoanCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1?command=approve", HttpMethod.POST, + "loanStateTransistionsByExternalIdCommandStrategy", mock(LoanStateTransistionsByExternalIdCommandStrategy.class)), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1?command=disburse", HttpMethod.POST, + "loanStateTransistionsByExternalIdCommandStrategy", mock(LoanStateTransistionsByExternalIdCommandStrategy.class)), Arguments.of("rescheduleloans", HttpMethod.POST, "createLoanRescheduleRequestCommandStrategy", mock(CreateLoanRescheduleRequestCommandStrategy.class)), Arguments.of("rescheduleloans/123?command=approve", HttpMethod.POST, "approveLoanRescheduleCommandStrategy", mock(ApproveLoanRescheduleCommandStrategy.class)), Arguments.of("loans/123/transactions/123", HttpMethod.GET, "getTransactionByIdCommandStrategy", mock(GetTransactionByIdCommandStrategy.class)), + Arguments.of( + "loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions/external-id/7dfad438-2319-48ce-8520-10a62801e9ab?fields=id", + HttpMethod.GET, "getTransactionByExternalIdCommandStrategy", mock(GetTransactionByExternalIdCommandStrategy.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, @@ -109,7 +177,15 @@ public class CommandStrategyProviderTest { Arguments.of("datatables/test_dt_table/123", HttpMethod.POST, "createDatatableEntryCommandStrategy", mock(CreateDatatableEntryCommandStrategy.class)), Arguments.of("datatables/test_dt_table/123/1", HttpMethod.PUT, "updateDatatableEntryOneToManyCommandStrategy", - mock(UpdateDatatableEntryOneToManyCommandStrategy.class))); + mock(UpdateDatatableEntryOneToManyCommandStrategy.class)), + Arguments.of("datatables/test_dt_table/123", HttpMethod.PUT, "updateDatatableEntryOneToOneCommandStrategy", + mock(UpdateDatatableEntryOneToOneCommandStrategy.class)), + Arguments.of("loans/123?command=markAsFraud", HttpMethod.PUT, "modifyLoanApplicationCommandStrategy", + mock(ModifyLoanApplicationCommandStrategy.class)), + Arguments.of("loans/123", HttpMethod.PUT, "modifyLoanApplicationCommandStrategy", + mock(ModifyLoanApplicationCommandStrategy.class)), + Arguments.of("datatables/test_dt_table/query?columnFilter=id&valueFilter=12&resultColumns=id", HttpMethod.GET, + "getDatatableEntryByQueryCommandStrategy", mock(GetDatatableEntryByQueryCommandStrategy.class))); } /** @@ -136,15 +212,22 @@ public class CommandStrategyProviderTest { } /** - * Command strategy provider for error scenarioss. + * Command strategy provider for error scenarios. * * @return the test data stream */ private static Stream 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("datatables/test_dt_table", HttpMethod.GET), Arguments.of("datatables", HttpMethod.GET), - Arguments.of("loans//charges/123", HttpMethod.GET), Arguments.of("loans/123/charges/", HttpMethod.GET)); + Arguments.of("loans//charges/123", HttpMethod.GET), Arguments.of("loans/123/charges/", HttpMethod.GET), + Arguments.of("loans/123/charges/123", HttpMethod.POST), + Arguments.of( + "loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/charges/external-id/7dfad438-2319-48ce-8520-10a62801e9ab", + HttpMethod.POST), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1/transactions", HttpMethod.POST), + Arguments.of("loans/external-id/8dfad438-2319-48ce-8520-10a62801e9a1", HttpMethod.POST), + Arguments.of("datatables/test_dt_table/query", HttpMethod.GET)); } diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustChargeByChargeExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustChargeByChargeExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..8dac1ef83 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustChargeByChargeExternalIdCommandStrategyTest.java @@ -0,0 +1,158 @@ +/** + * 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.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +import java.util.UUID; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.batch.domain.BatchRequest; +import org.apache.fineract.batch.domain.BatchResponse; +import org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link AdjustChargeByChargeExternalIdCommandStrategy}. + */ +public class AdjustChargeByChargeExternalIdCommandStrategyTest { + + /** + * Test {@link AdjustChargeByChargeExternalIdCommandStrategy#execute} happy path scenario. + * + */ + @Test + public void testExecuteAdjustChargeByExternalIdWithCommandSuccessScenario() { + // given + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final String loanChargeExternalId = UUID.randomUUID().toString(); + final String command = "adjustment"; + final BatchRequest request = getBatchRequest(loanExternalId, loanChargeExternalId, command); + final String responseBody = "{\"loanId\":13,\"resourceId\":16,\"subResourceId\":26,\"changes\":{\"amount\":10.0," + + "\"transactionDate\":[2022,12,7],\"locale\":\"de_DE\"}}"; + + given(testContext.loanChargesApiResource.executeLoanCharge(eq(loanExternalId), eq(loanChargeExternalId), eq(command), + eq(request.getBody()))).willReturn(responseBody); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loanChargesApiResource).executeLoanCharge(eq(loanExternalId), eq(loanChargeExternalId), eq(command), + eq(request.getBody())); + } + + /** + * Test {@link AdjustChargeByChargeExternalIdCommandStrategy#execute} error scenario. + * + */ + @Test + public void testExecuteAdjustChargeByExternalIdWithoutCommandErrorScenario() { + // given + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final String loanChargeExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, loanChargeExternalId, null); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals("Resource with method " + request.getMethod() + " and relativeUrl " + request.getRelativeUrl() + " doesn't exist", + response.getBody()); + verifyNoInteractions(testContext.loanChargesApiResource); + } + + /** + * Creates and returns a request with the given loan external id and charge external id. + * + * @param loanExternalId + * the loan external id + * @param chargeExternalId + * the charge external id + * @param chargeCommand + * the charge command + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String chargeExternalId, final String chargeCommand) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = String.format("loans/external-id/%s/charges/external-id/%s", loanExternalId, chargeExternalId); + + br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setRelativeUrl(relativeUrl); + if (StringUtils.isNotBlank(chargeCommand)) { + br.setRelativeUrl(br.getRelativeUrl() + String.format("?command=%s", chargeCommand)); + } + br.setMethod(HttpMethod.POST); + br.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setBody("{\"amount\":7.00,\"locale\":\"en\"}"); + + return br; + } + + /** + * Private test context class used since testng runs in parallel to avoid state between tests + */ + private static class TestContext { + + /** + * The Mock UriInfo + */ + @Mock + private UriInfo uriInfo; + + /** + * The Mock {@link LoanChargesApiResource} + */ + @Mock + private LoanChargesApiResource loanChargesApiResource; + + /** + * The class under test. + */ + private final AdjustChargeByChargeExternalIdCommandStrategy subjectToTest; + + /** + * Constructor. + */ + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new AdjustChargeByChargeExternalIdCommandStrategy(loanChargesApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustChargeCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustChargeCommandStrategyTest.java new file mode 100644 index 000000000..7bb5d040c --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustChargeCommandStrategyTest.java @@ -0,0 +1,154 @@ +/** + * 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.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.batch.domain.BatchRequest; +import org.apache.fineract.batch.domain.BatchResponse; +import org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource; +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link AdjustChargeCommandStrategy}. + */ +public class AdjustChargeCommandStrategyTest { + + /** + * Test {@link AdjustChargeCommandStrategy#execute} happy path scenario. + */ + @Test + public void testExecuteWithAdjustmentCommandSuccessScenario() { + // given + final TestContext testContext = new TestContext(); + + final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4)); + final Long loanChargeId = Long.valueOf(RandomStringUtils.randomNumeric(4)); + final String command = "adjustment"; + final BatchRequest request = getBatchRequest(loanId, loanChargeId, command); + final String responseBody = "{\"loanId\":13,\"resourceId\":16,\"subResourceId\":26,\"changes\":{\"amount\":10.0," + + "\"transactionDate\":[2022,12,7],\"locale\":\"de_DE\"}}"; + + given(testContext.loanChargesApiResource.executeLoanCharge(eq(loanId), eq(loanChargeId), eq(command), eq(request.getBody()))) + .willReturn(responseBody); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loanChargesApiResource).executeLoanCharge(eq(loanId), eq(loanChargeId), eq(command), eq(request.getBody())); + } + + /** + * Test {@link AdjustChargeCommandStrategy#execute} error scenario. + */ + @Test + public void testExecuteWithoutCommandErrorScenario() { + // given + final TestContext testContext = new TestContext(); + + final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4)); + final Long loanChargeId = Long.valueOf(RandomStringUtils.randomNumeric(4)); + final BatchRequest request = getBatchRequest(loanId, loanChargeId, null); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals("Resource with method " + request.getMethod() + " and relativeUrl " + request.getRelativeUrl() + " doesn't exist", + response.getBody()); + verifyNoInteractions(testContext.loanChargesApiResource); + } + + /** + * Creates and returns a request with the given loan id and transaction id. + * + * @param loanId + * the loan id + * @param transactionId + * the transaction id + * @param chargeCommand + * the charge command + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final Long loanId, final Long transactionId, final String chargeCommand) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = String.format("loans/%s/charges/%s", loanId, transactionId); + + br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setRelativeUrl(relativeUrl); + if (StringUtils.isNotBlank(chargeCommand)) { + br.setRelativeUrl(br.getRelativeUrl() + String.format("?command=%s", chargeCommand)); + } + br.setMethod(HttpMethod.POST); + br.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setBody("{\"amount\":7.00,\"locale\":\"en\"}"); + + return br; + } + + /** + * Private test context class used since testng runs in parallel to avoid state between tests + */ + private static class TestContext { + + /** + * The Mock UriInfo + */ + @Mock + private UriInfo uriInfo; + + /** + * The Mock {@link LoanChargesApiResource} + */ + @Mock + private LoanChargesApiResource loanChargesApiResource; + + /** + * The class under test. + */ + private final AdjustChargeCommandStrategy subjectToTest; + + /** + * Constructor. + */ + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new AdjustChargeCommandStrategy(loanChargesApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustTransactionByExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustTransactionByExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..ae2618fb5 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustTransactionByExternalIdCommandStrategyTest.java @@ -0,0 +1,163 @@ +/** + * 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.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +import java.util.UUID; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +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 for {@link AdjustTransactionByExternalIdCommandStrategy}. + */ +public class AdjustTransactionByExternalIdCommandStrategyTest { + + /** + * Test {@link AdjustTransactionByExternalIdCommandStrategy#execute} happy path scenario. + */ + @Test + public void testExecuteWithoutCommandSuccessScenario() { + // given + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final String transactionExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, transactionExternalId, null); + final String responseBody = "{\"officeId\":1,\"clientId\":107,\"loanId\":71,\"resourceId\":193,\"changes\"" + + ":{\"transactionDate\":\"03 October 2022\",\"transactionAmount\":\"500\",\"locale\":\"en\",\"dateFormat\":" + + "\"dd MMMM yyyy\",\"paymentTypeId\":\"\"}}"; + + given(testContext.loanTransactionsApiResource.adjustLoanTransaction(eq(loanExternalId), eq(transactionExternalId), + eq(request.getBody()), eq(null))).willReturn(responseBody); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loanTransactionsApiResource).adjustLoanTransaction(eq(loanExternalId), eq(transactionExternalId), + eq(request.getBody()), isNull()); + } + + /** + * Test {@link AdjustTransactionByExternalIdCommandStrategy#execute} happy path scenario. + */ + @Test + public void testExecuteWithCommandSuccessScenario() { + // given + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final String transactionExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, transactionExternalId, "chargeback"); + final String responseBody = "{\"officeId\":1,\"clientId\":107,\"loanId\":71,\"resourceId\":193,\"changes\"" + + ":{\"transactionDate\":\"03 October 2022\",\"transactionAmount\":\"500\",\"locale\":\"en\",\"dateFormat\":" + + "\"dd MMMM yyyy\",\"paymentTypeId\":\"\"}}"; + + given(testContext.loanTransactionsApiResource.adjustLoanTransaction(eq(loanExternalId), eq(transactionExternalId), + eq(request.getBody()), eq("chargeback"))).willReturn(responseBody); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loanTransactionsApiResource).adjustLoanTransaction(eq(loanExternalId), eq(transactionExternalId), + eq(request.getBody()), eq("chargeback")); + } + + /** + * Creates and returns a request with the given loan id and transaction id. + * + * @param loanExternalId + * the loan id + * @param transactionExternalId + * the transaction id + * @param transactionCommand + * the optional transaction command + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String transactionExternalId, final String transactionCommand) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = String.format("loans/external-id/%s/transactions/external-id/%s", loanExternalId, transactionExternalId); + + br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setRelativeUrl(relativeUrl); + if (StringUtils.isNotBlank(transactionCommand)) { + br.setRelativeUrl(br.getRelativeUrl() + String.format("?command=%s", transactionCommand)); + } + br.setMethod(HttpMethod.POST); + br.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setBody("{\"locale\":\"en\",\"dateFormat\":\"dd MMMM yyyy\",\"transactionDate\":\"03 October 2022\",\"transactionAmount\":500}"); + + return br; + } + + /** + * Private test context class used since testng runs in parallel to avoid state between tests + */ + private static class TestContext { + + /** + * The Mock UriInfo + */ + @Mock + private UriInfo uriInfo; + + /** + * The Mock {@link LoanTransactionsApiResource} + */ + @Mock + private LoanTransactionsApiResource loanTransactionsApiResource; + + /** + * The class under test. + */ + private final AdjustTransactionByExternalIdCommandStrategy subjectToTest; + + /** + * Constructor. + */ + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new AdjustTransactionByExternalIdCommandStrategy(loanTransactionsApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustTransactionCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustTransactionCommandStrategyTest.java index 20dae9a60..9d3faf448 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustTransactionCommandStrategyTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/AdjustTransactionCommandStrategyTest.java @@ -21,6 +21,7 @@ package org.apache.fineract.batch.command.internal; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; import javax.ws.rs.HttpMethod; import javax.ws.rs.core.UriInfo; @@ -30,10 +31,13 @@ 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.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +/** + * Test class for {@link AdjustTransactionCommandStrategy}. + */ public class AdjustTransactionCommandStrategyTest { /** @@ -58,10 +62,12 @@ public class AdjustTransactionCommandStrategyTest { final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); // then - assertEquals(response.getStatusCode(), HttpStatus.SC_OK); - assertEquals(response.getRequestId(), request.getRequestId()); - assertEquals(response.getHeaders(), request.getHeaders()); - assertEquals(response.getBody(), responseBody); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loanTransactionsApiResource).adjustLoanTransaction(eq(loanId), eq(transactionId), eq(request.getBody()), + eq(null)); } /** @@ -86,10 +92,12 @@ public class AdjustTransactionCommandStrategyTest { final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); // then - assertEquals(response.getStatusCode(), HttpStatus.SC_OK); - assertEquals(response.getRequestId(), request.getRequestId()); - assertEquals(response.getHeaders(), request.getHeaders()); - assertEquals(response.getBody(), responseBody); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loanTransactionsApiResource).adjustLoanTransaction(eq(loanId), eq(transactionId), eq(request.getBody()), + eq("chargeback")); } /** @@ -125,14 +133,26 @@ public class AdjustTransactionCommandStrategyTest { */ private static class TestContext { + /** + * The Mock UriInfo + */ @Mock private UriInfo uriInfo; + /** + * The Mock {@link LoanTransactionsApiResource} + */ @Mock private LoanTransactionsApiResource loanTransactionsApiResource; + /** + * The class under test. + */ private final AdjustTransactionCommandStrategy subjectToTest; + /** + * Constructor. + */ TestContext() { MockitoAnnotations.openMocks(this); subjectToTest = new AdjustTransactionCommandStrategy(loanTransactionsApiResource); diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CollectChargesByLoanExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CollectChargesByLoanExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..351e62434 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CollectChargesByLoanExternalIdCommandStrategyTest.java @@ -0,0 +1,147 @@ +/** + * 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.assertj.core.api.Assertions.assertThat; +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.UUID; +import java.util.stream.Stream; +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.infrastructure.core.api.MutableUriInfo; +import org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource; +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; + +/** + * The {@link CollectChargesByLoanExternalIdCommandStrategy} test class. + */ +public class CollectChargesByLoanExternalIdCommandStrategyTest { + + /** + * Query parameter provider. + * + * @return the test data stream + */ + private static Stream provideQueryParameters() { + return Stream.of(Arguments.of(null, 0), Arguments.of("fields=name,amountOrPercentage", 1)); + } + + /** + * Test {@link CollectChargesByLoanExternalIdCommandStrategy#execute} happy path scenario. + */ + @ParameterizedTest + @MethodSource("provideQueryParameters") + public void testExecuteSuccessScenario(final String queryParameter, final int numberOfQueryParams) { + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, queryParameter); + final String responseBody = "someResponseBody"; + + given(testContext.loanChargesApiResource.retrieveAllLoanCharges(eq(loanExternalId), any(UriInfo.class))).willReturn(responseBody); + + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_OK); + assertThat(response.getRequestId()).isEqualTo(request.getRequestId()); + assertThat(response.getHeaders()).isEqualTo(request.getHeaders()); + assertThat(response.getBody()).isEqualTo(responseBody); + + verify(testContext.loanChargesApiResource).retrieveAllLoanCharges(eq(loanExternalId), testContext.uriInfoCaptor.capture()); + MutableUriInfo mutableUriInfo = testContext.uriInfoCaptor.getValue(); + assertThat(mutableUriInfo.getAdditionalQueryParameters()).hasSize(numberOfQueryParams); + } + + /** + * Creates and returns a request with the given loan external id. + * + * @param loanExternalId + * the loan external id + * @param queryParameter + * the query parameter + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String queryParameter) { + final BatchRequest br = new BatchRequest(); + String relativeUrl = "loans/external-id/" + loanExternalId + "/charges"; + + if (queryParameter != null) { + relativeUrl = relativeUrl + "?" + queryParameter; + } + + br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setRelativeUrl(relativeUrl); + br.setMethod(HttpMethod.GET); + 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 { + + /** + * The subject to test + */ + private final CollectChargesByLoanExternalIdCommandStrategy subjectToTest; + + /** + * The mock uri info + */ + @Mock + private UriInfo uriInfo; + + /** + * The mock {@link LoanChargesApiResource} object. + */ + @Mock + private LoanChargesApiResource loanChargesApiResource; + + /** + * The uri info captor + */ + @Captor + private ArgumentCaptor uriInfoCaptor; + + /** + * Test Context constructor + */ + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new CollectChargesByLoanExternalIdCommandStrategy(loanChargesApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateChargeByLoanExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateChargeByLoanExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..7f812443d --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateChargeByLoanExternalIdCommandStrategyTest.java @@ -0,0 +1,140 @@ +/** + * 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 java.util.UUID; +import java.util.stream.Stream; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.batch.domain.BatchRequest; +import org.apache.fineract.batch.domain.BatchResponse; +import org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource; +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.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link CreateChargeByLoanExternalIdCommandStrategy}. + */ +public class CreateChargeByLoanExternalIdCommandStrategyTest { + + /** + * Command arguments provider. + * + * @return command argument + */ + private static Stream provideCommandParameters() { + return Stream.of(Arguments.of(null, 0), Arguments.of("adjustment", 1)); + } + + /** + * Test {@link CreateChargeByLoanExternalIdCommandStrategy#execute} happy path scenario. + * + * @param command + * the command to pass + * @param noOfArguments + * the number of arguments + */ + @ParameterizedTest + @MethodSource("provideCommandParameters") + public void testExecuteSuccessScenario(final String command, final int noOfArguments) { + final TestContext testContext = new TestContext(); + final String loanExternalId = UUID.randomUUID().toString(); + final BatchRequest batchRequest = getBatchRequest(loanExternalId, command); + final String responseBody = "myResponseBody"; + + when(testContext.loanChargesApiResource.executeLoanCharge(loanExternalId, 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.loanChargesApiResource).executeLoanCharge(loanExternalId, command, batchRequest.getBody()); + } + + /** + * Creates and returns a request with the given loan id and command value. + * + * @param loanExternalId + * the loan external id + * @param command + * the transaction id + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String command) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = "loans/external-id/" + loanExternalId + "/charges"; + if (StringUtils.isNotBlank(command)) { + relativeUrl = relativeUrl + String.format("?command=%s", 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 charges API resource. + */ + @Mock + private LoanChargesApiResource loanChargesApiResource; + + /** + * The {@link CreateChargeByLoanExternalIdCommandStrategy} under test. + */ + private final CreateChargeByLoanExternalIdCommandStrategy subjectToTest; + + /** + * Constructor. + */ + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new CreateChargeByLoanExternalIdCommandStrategy(loanChargesApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategyTest.java index ff63a7dda..2f58fb210 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategyTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategyTest.java @@ -29,10 +29,13 @@ import org.apache.fineract.batch.domain.BatchRequest; import org.apache.fineract.batch.domain.BatchResponse; import org.apache.fineract.infrastructure.dataqueries.api.DatatablesApiResource; import org.apache.http.HttpStatus; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +/** + * Test class for {@link CreateDatatableEntryCommandStrategy}. + */ public class CreateDatatableEntryCommandStrategyTest { /** @@ -55,10 +58,10 @@ public class CreateDatatableEntryCommandStrategyTest { final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); // then - assertEquals(response.getStatusCode(), HttpStatus.SC_OK); - assertEquals(response.getRequestId(), request.getRequestId()); - assertEquals(response.getHeaders(), request.getHeaders()); - assertEquals(response.getBody(), responseBody); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); } /** @@ -88,14 +91,27 @@ public class CreateDatatableEntryCommandStrategyTest { */ private static class TestContext { + /** + * The Mock UriInfo + */ @Mock private UriInfo uriInfo; + /** + * The Mock {@link DatatablesApiResource} + */ @Mock private DatatablesApiResource datatablesApiResource; + /** + * The class under test. + */ private final CreateDatatableEntryCommandStrategy subjectToTest; + /** + * Constructor. + */ + TestContext() { MockitoAnnotations.openMocks(this); subjectToTest = new CreateDatatableEntryCommandStrategy(datatablesApiResource); diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateLoanRescheduleRequestCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateLoanRescheduleRequestCommandStrategyTest.java index 0cdf40599..fc342dc63 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateLoanRescheduleRequestCommandStrategyTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateLoanRescheduleRequestCommandStrategyTest.java @@ -35,7 +35,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * Test class fpr {@link CreateLoanRescheduleRequestCommandStrategy}. + * Test class for {@link CreateLoanRescheduleRequestCommandStrategy}. */ public class CreateLoanRescheduleRequestCommandStrategyTest { diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..a43238663 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategyTest.java @@ -0,0 +1,120 @@ +/** + * 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 java.util.UUID; +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 for {@link CreateTransactionByLoanExternalIdCommandStrategy}. + */ +public class CreateTransactionByLoanExternalIdCommandStrategyTest { + + /** + * Test {@link CreateTransactionByLoanExternalIdCommandStrategy#execute} happy path scenario. + */ + @Test + public void testExecuteSuccessScenario() { + final TestContext testContext = new TestContext(); + final String loanExternalId = UUID.randomUUID().toString(); + final String command = "myCommand"; + final BatchRequest batchRequest = getBatchRequest(loanExternalId, command); + final String responseBody = "myResponseBody"; + + when(testContext.loanTransactionsApiResource.executeLoanTransaction(loanExternalId, 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(loanExternalId, command, batchRequest.getBody()); + } + + /** + * Creates and returns a request with the given loan id and command value. + * + * @param loanExternalId + * the loan external id + * @param command + * the transaction id + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String command) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = "loans/external-id/" + loanExternalId + "/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 CreateTransactionByLoanExternalIdCommandStrategy} under test. + */ + private final CreateTransactionByLoanExternalIdCommandStrategy subjectToTest; + + /** + * Constructor. + */ + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new CreateTransactionByLoanExternalIdCommandStrategy(loanTransactionsApiResource); + } + } +} 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 index c081a2e0c..29636669f 100644 --- 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 @@ -35,7 +35,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * Test class fpr {@link CreateTransactionLoanCommandStrategy}. + * Test class for {@link CreateTransactionLoanCommandStrategy}. */ public class CreateTransactionLoanCommandStrategyTest { diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetChargeByChargeExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetChargeByChargeExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..f484602c5 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetChargeByChargeExternalIdCommandStrategyTest.java @@ -0,0 +1,152 @@ +/** + * 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.assertj.core.api.Assertions.assertThat; +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.UUID; +import java.util.stream.Stream; +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.infrastructure.core.api.MutableUriInfo; +import org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource; +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; + +/** + * The {@link GetChargeByChargeExternalIdCommandStrategy} test class. + */ +public class GetChargeByChargeExternalIdCommandStrategyTest { + + /** + * Query parameter provider. + * + * @return the test data stream + */ + private static Stream provideQueryParameters() { + return Stream.of(Arguments.of(null, 0), Arguments.of("fields=name,amountOrPercentage", 1)); + } + + /** + * Test {@link GetChargeByChargeExternalIdCommandStrategy#execute} happy path scenario. + */ + @ParameterizedTest + @MethodSource("provideQueryParameters") + public void testExecuteSuccessScenario(final String queryParameter, final int numberOfQueryParams) { + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final String chargeExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, chargeExternalId, queryParameter); + final String responseBody = "someResponseBody"; + + given(testContext.loanChargesApiResource.retrieveLoanCharge(eq(loanExternalId), eq(chargeExternalId), any(UriInfo.class))) + .willReturn(responseBody); + + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_OK); + assertThat(response.getRequestId()).isEqualTo(request.getRequestId()); + assertThat(response.getHeaders()).isEqualTo(request.getHeaders()); + assertThat(response.getBody()).isEqualTo(responseBody); + + verify(testContext.loanChargesApiResource).retrieveLoanCharge(eq(loanExternalId), eq(chargeExternalId), + testContext.uriInfoCaptor.capture()); + MutableUriInfo mutableUriInfo = testContext.uriInfoCaptor.getValue(); + assertThat(mutableUriInfo.getAdditionalQueryParameters()).hasSize(numberOfQueryParams); + } + + /** + * Creates and returns a request with the given loan external id and charge external id. + * + * @param loanExternalId + * the loan external id + * @param chargeExternalId + * the charge external id + * @param queryParameter + * the query parameter + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String chargeExternalId, final String queryParameter) { + final BatchRequest br = new BatchRequest(); + String relativeUrl = "loans/external-id/" + loanExternalId + "/charges/external-id/" + chargeExternalId; + + if (queryParameter != null) { + relativeUrl = relativeUrl + "?" + queryParameter; + } + + br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setRelativeUrl(relativeUrl); + br.setMethod(HttpMethod.GET); + 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 { + + /** + * The subject to test + */ + private final GetChargeByChargeExternalIdCommandStrategy subjectToTest; + + /** + * The mock uri info + */ + @Mock + private UriInfo uriInfo; + + /** + * The mock {@link LoanChargesApiResource} object. + */ + @Mock + private LoanChargesApiResource loanChargesApiResource; + + /** + * The uri info captor + */ + @Captor + private ArgumentCaptor uriInfoCaptor; + + /** + * Test Context constructor + */ + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new GetChargeByChargeExternalIdCommandStrategy(loanChargesApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetLoanByExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetLoanByExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..73f87d65d --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetLoanByExternalIdCommandStrategyTest.java @@ -0,0 +1,179 @@ +/** + * 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.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Stream; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.RandomStringUtils; +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.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; + +/** + * Test class for {@link GetLoanByExternalIdCommandStrategy}. + */ +public class GetLoanByExternalIdCommandStrategyTest { + + /** + * The query parameter provider. + * + * @return Arguments. + */ + private static Stream provideQueryParameters() { + return Stream.of(Arguments.of(null, null, null, null, 0), Arguments.of("all", null, null, null, 1), + Arguments.of("repaymentSchedule,transactions", null, "guarantors,futureSchedule", "true", 3), + Arguments.of("repaymentSchedule,transactions", "id,principal,annualInterestRate", null, "false", 3), + Arguments.of("repaymentSchedule,transactions", "id,principal,annualInterestRate", "guarantors,futureSchedule", "false", 4)); + } + + /** + * Test {@link GetLoanByExternalIdCommandStrategy#execute} happy path scenario. + * + */ + @ParameterizedTest + @MethodSource("provideQueryParameters") + public void testExecuteSuccessScenario(final String associations, final String fields, final String exclude, + final String staffInSelectedOfficeOnlyFlag, final int noOfQueryParams) { + // given + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, associations, exclude, fields, staffInSelectedOfficeOnlyFlag); + final Boolean staffInSelectedOfficeOnlyBooleanFlag = BooleanUtils.toBoolean(staffInSelectedOfficeOnlyFlag); + final String responseBody = "{\\\"id\\\":2,\\\"accountNo\\\":\\\"000000002\\\"}"; + + given(testContext.loansApiResource.retrieveLoan(eq(loanExternalId), eq(staffInSelectedOfficeOnlyBooleanFlag), eq(associations), + eq(exclude), eq(fields), any(UriInfo.class))).willReturn(responseBody); + + // when + final BatchResponse response = testContext.underTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + + verify(testContext.loansApiResource).retrieveLoan(eq(loanExternalId), eq(staffInSelectedOfficeOnlyBooleanFlag), eq(associations), + eq(exclude), eq(fields), testContext.uriInfoCaptor.capture()); + final MutableUriInfo mutableUriInfo = testContext.uriInfoCaptor.getValue(); + assertEquals(noOfQueryParams, mutableUriInfo.getAdditionalQueryParameters().size()); + } + + /** + * Creates and returns a request with the given loan external id. + * + * @param loanExternalId + * the loan external id + * @param associations + * the associations query param + * @param exclude + * exclude query param + * @param fields + * fields query param + * @param staffInSelectedOfficeOnlyFlag + * staff in selected office only query param + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String associations, final String exclude, final String fields, + final String staffInSelectedOfficeOnlyFlag) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = "loans/external-id/" + loanExternalId; + + Set queryParams = new HashSet<>(); + if (associations != null) { + queryParams.add("associations=" + associations); + } + if (exclude != null) { + queryParams.add("exclude=" + exclude); + } + if (fields != null) { + queryParams.add("fields=" + fields); + } + if (staffInSelectedOfficeOnlyFlag != null) { + queryParams.add("staffInSelectedOfficeOnly=" + staffInSelectedOfficeOnlyFlag); + } + if (!queryParams.isEmpty()) { + relativeUrl = relativeUrl + "?" + String.join("&", queryParams); + } + + br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setRelativeUrl(relativeUrl); + br.setMethod(HttpMethod.GET); + 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 { + + /** + * The Mock UriInfo + */ + @Mock + private UriInfo uriInfo; + + /** + * The Mock {@link LoansApiResource} + */ + @Mock + private LoansApiResource loansApiResource; + + /** + * The Captor for UriInfo + */ + @Captor + private ArgumentCaptor uriInfoCaptor; + + /** + * The class under test. + */ + private final GetLoanByExternalIdCommandStrategy underTest; + + TestContext() { + MockitoAnnotations.openMocks(this); + underTest = new GetLoanByExternalIdCommandStrategy(loansApiResource); + } + } +} 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 d8327f89c..38eddf866 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 @@ -43,6 +43,9 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +/** + * Test class for {@link GetLoanByIdCommandStrategy}. + */ public class GetLoanByIdCommandStrategyTest { private static Stream provideQueryParameters() { diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..de72e79c1 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByExternalIdCommandStrategyTest.java @@ -0,0 +1,146 @@ +/** + * 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.assertj.core.api.Assertions.assertThat; +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.UUID; +import java.util.stream.Stream; +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.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link GetTransactionByExternalIdCommandStrategy}. + */ +public class GetTransactionByExternalIdCommandStrategyTest { + + private static Stream provideQueryParameters() { + return Stream.of(Arguments.of(null, 0), Arguments.of("id,date,amount", 1)); + } + + /** + * Test {@link GetTransactionByExternalIdCommandStrategy#execute} happy path scenario. + */ + @ParameterizedTest + @MethodSource("provideQueryParameters") + public void testExecuteSuccessScenario(final String fields, final int noOfQueryParams) { + // given + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final String transactionExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, transactionExternalId, fields); + final String responseBody = "{\"id\":12,\"officeId\":1,\"officeName\":\"Head Office\",\"type\":{\"id\":10,\"code\":" + + "\"loanTransactionType.accrual\",\"value\":\"Accrual\",\"disbursement\":false,\"repaymentAtDisbursement\":false," + + "\"repayment\":false,\"contra\":false,\"waiveInterest\":false,\"waiveCharges\":false,\"accrual\":true,\"writeOff\":false," + + "\"recoveryRepayment\":false,\"initiateTransfer\":false,\"approveTransfer\":false,\"withdrawTransfer\":false," + + "\"rejectTransfer\":false,\"chargePayment\":false,\"refund\":false,\"refundForActiveLoans\":false},\"date\":[2022,3,29]," + + "\"currency\":{\"code\":\"EUR\",\"name\":\"Euro\",\"decimalPlaces\":2,\"inMultiplesOf\":0,\"displaySymbol\":\"€\"," + + "\"nameCode\":\"currency.EUR\",\"displayLabel\":\"Euro (€)\"},\"amount\":0.000000,\"netDisbursalAmount\":200.000000," + + "\"principalPortion\":0,\"interestPortion\":0.000000,\"feeChargesPortion\":0,\"penaltyChargesPortion\":0,\"overpaymentPortion\":0," + + "\"unrecognizedIncomePortion\":0,\"outstandingLoanBalance\":0,\"submittedOnDate\":[2022,3,29],\"manuallyReversed\":false," + + "\"loanChargePaidByList\":[],\"numberOfRepayments\":0}"; + + given(testContext.loanTransactionsApiResource.retrieveTransactionByLoanExternalIdAndTransactionExternalId(eq(loanExternalId), + eq(transactionExternalId), eq(fields), any(UriInfo.class))).willReturn(responseBody); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_OK); + assertThat(response.getRequestId()).isEqualTo(request.getRequestId()); + assertThat(response.getHeaders()).isEqualTo(request.getHeaders()); + assertThat(response.getBody()).isEqualTo(responseBody); + verify(testContext.loanTransactionsApiResource).retrieveTransactionByLoanExternalIdAndTransactionExternalId(eq(loanExternalId), + eq(transactionExternalId), eq(fields), any(UriInfo.class)); + } + + /** + * Creates and returns a request with the given loan external id and transaction external id. + * + * @param loanExternalId + * the loan external id + * @param transactionExternalId + * the transaction external id + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String transactionExternalId, final String fields) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = "loans/external-id/" + loanExternalId + "/transactions/external-id/" + transactionExternalId; + if (fields != null) { + relativeUrl = relativeUrl + "?fields=" + fields; + } + + br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setRelativeUrl(relativeUrl); + br.setMethod(HttpMethod.GET); + 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 { + + /** + * The Mock UriInfo + */ + @Mock + private UriInfo uriInfo; + + /** + * The Mock {@link LoanTransactionsApiResource} + */ + @Mock + private LoanTransactionsApiResource loanTransactionsApiResource; + + /** + * The class under test. + */ + private final GetTransactionByExternalIdCommandStrategy subjectToTest; + + /** + * Constructor. + */ + + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new GetTransactionByExternalIdCommandStrategy(loanTransactionsApiResource); + } + } +} 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 60ef582f8..6d8fc136d 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 @@ -37,6 +37,9 @@ import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +/** + * Test class for {@link GetTransactionByIdCommandStrategy}. + */ public class GetTransactionByIdCommandStrategyTest { private static Stream provideQueryParameters() { @@ -110,14 +113,27 @@ public class GetTransactionByIdCommandStrategyTest { */ private static class TestContext { + /** + * The Mock UriInfo + */ @Mock private UriInfo uriInfo; + /** + * The Mock {@link LoanTransactionsApiResource} + */ @Mock private LoanTransactionsApiResource loanTransactionsApiResource; + /** + * The class under test. + */ private final GetTransactionByIdCommandStrategy subjectToTest; + /** + * Constructor. + */ + TestContext() { MockitoAnnotations.openMocks(this); subjectToTest = new GetTransactionByIdCommandStrategy(loanTransactionsApiResource); diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/LoanStateTransistionsByExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/LoanStateTransistionsByExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..ba402c1ba --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/LoanStateTransistionsByExternalIdCommandStrategyTest.java @@ -0,0 +1,170 @@ +/** + * 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.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +import java.util.UUID; +import java.util.stream.Stream; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.batch.domain.BatchRequest; +import org.apache.fineract.batch.domain.BatchResponse; +import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource; +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; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link LoanStateTransistionsByExternalIdCommandStrategy}. + */ +public class LoanStateTransistionsByExternalIdCommandStrategyTest { + + /** + * Test {@link LoanStateTransistionsByExternalIdCommandStrategy#execute} happy path scenario. + * + * @param command + * the command + * @param noOfArguments + * the no. of arguments + */ + @ParameterizedTest + @MethodSource("provideQueryParameters") + public void testLoanStateTransistionsByExternalIdWithCommandSuccessScenario(final String command, final int noOfArguments) { + // given + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, command); + final String responseBody = "{\"loanId\":13,\"resourceId\":16,\"subResourceId\":26,\"changes\":{\"amount\":10.0," + + "\"transactionDate\":[2022,12,7],\"locale\":\"de_DE\"}}"; + + given(testContext.loansApiResource.stateTransitions(eq(loanExternalId), eq(command), eq(request.getBody()))) + .willReturn(responseBody); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loansApiResource).stateTransitions(eq(loanExternalId), eq(command), eq(request.getBody())); + } + + /** + * Query parameter provider. + * + * @return the test data stream + */ + private static Stream provideQueryParameters() { + return Stream.of(Arguments.of("approve", 1), Arguments.of("disburse", 1)); + } + + /** + * Test {@link LoanStateTransistionsByExternalIdCommandStrategy#execute} error scenario. + * + */ + @Test + public void testLoanStateTransistionsByExternalIdWithoutCommandErrorScenario() { + // given + final TestContext testContext = new TestContext(); + + final String loanExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, null); + + // when + final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals("Resource with method " + request.getMethod() + " and relativeUrl " + request.getRelativeUrl() + " doesn't exist", + response.getBody()); + verifyNoInteractions(testContext.loansApiResource); + } + + /** + * Creates and returns a request with the given loan external id. + * + * @param loanExternalId + * the loan external id + * @param chargeCommand + * the charge command + * @return BatchRequest + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String chargeCommand) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = String.format("loans/external-id/%s", loanExternalId); + + br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setRelativeUrl(relativeUrl); + if (StringUtils.isNotBlank(chargeCommand)) { + br.setRelativeUrl(br.getRelativeUrl() + String.format("?command=%s", chargeCommand)); + } + br.setMethod(HttpMethod.POST); + br.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5))); + br.setBody("{\"amount\":7.00,\"locale\":\"en\"}"); + + return br; + } + + /** + * Private test context class used since testng runs in parallel to avoid state between tests + */ + private static class TestContext { + + /** + * The Mock UriInfo + */ + @Mock + private UriInfo uriInfo; + + /** + * The Mock {@link LoansApiResource} + */ + @Mock + private LoansApiResource loansApiResource; + + /** + * The class under test. + */ + private final LoanStateTransistionsByExternalIdCommandStrategy subjectToTest; + + /** + * Constructor. + */ + TestContext() { + MockitoAnnotations.openMocks(this); + subjectToTest = new LoanStateTransistionsByExternalIdCommandStrategy(loansApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationByExternalIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationByExternalIdCommandStrategyTest.java new file mode 100644 index 000000000..ad6e2304f --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationByExternalIdCommandStrategyTest.java @@ -0,0 +1,137 @@ +/** + * 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.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +import java.util.UUID; +import java.util.stream.Stream; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.batch.domain.BatchRequest; +import org.apache.fineract.batch.domain.BatchResponse; +import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource; +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.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link ModifyLoanApplicationByExternalIdCommandStrategy} + */ +public class ModifyLoanApplicationByExternalIdCommandStrategyTest { + + /** + * Test {@link ModifyLoanApplicationByExternalIdCommandStrategy#execute(BatchRequest, UriInfo)} happy path scenario. + */ + @ParameterizedTest + @MethodSource("commandParamDataProvider") + public void testExecuteSuccessScenario(final String command, final String responseBody) { + final TestContext testContext = new TestContext(); + final String loanExternalId = UUID.randomUUID().toString(); + final BatchRequest request = getBatchRequest(loanExternalId, command); + + given(testContext.loansApiResource.modifyLoanApplication(eq(loanExternalId), eq(command), eq(request.getBody()))) + .willReturn(responseBody); + + final BatchResponse response = testContext.testSubject.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loansApiResource).modifyLoanApplication(eq(loanExternalId), eq(command), eq(request.getBody())); + } + + /** + * Command Param data provider + * + * @return test data stream + */ + private static Stream commandParamDataProvider() { + return Stream.of( + Arguments.of("markAsFraud", "{\"officeId\":1,\"clientId\":2,\"loanId\":2,\"resourceId\":2,\"changes\":{\"fraud\":true}}"), + Arguments.of(null, "body")); + } + + /** + * Creates and returns a request with the given loan external id. + * + * @param loanExternalId + * the loan external id + * @param queryParameter + * the command query param + * @return {@link BatchRequest} + */ + private BatchRequest getBatchRequest(final String loanExternalId, final String queryParameter) { + final BatchRequest batchRequest = new BatchRequest(); + + String relativeUrl = String.format("loans/external-id/%s", loanExternalId); + + if (StringUtils.isNotBlank(queryParameter)) { + relativeUrl = relativeUrl + "?command=" + queryParameter; + } + + batchRequest.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + batchRequest.setRelativeUrl(relativeUrl); + batchRequest.setMethod(HttpMethod.PUT); + batchRequest.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5))); + batchRequest.setBody("{\"fraud\": \"true\"}"); + return batchRequest; + } + + /** + * 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 loans api resource + */ + @Mock + private LoansApiResource loansApiResource; + + /** + * {@link ModifyLoanApplicationByExternalIdCommandStrategy} under test + */ + private final ModifyLoanApplicationByExternalIdCommandStrategy testSubject; + + /** + * Constructor + */ + TestContext() { + MockitoAnnotations.openMocks(this); + testSubject = new ModifyLoanApplicationByExternalIdCommandStrategy(loansApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationCommandStrategyTest.java new file mode 100644 index 000000000..ab43b0783 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/ModifyLoanApplicationCommandStrategyTest.java @@ -0,0 +1,135 @@ +/** + * 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.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +import java.util.stream.Stream; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.batch.domain.BatchRequest; +import org.apache.fineract.batch.domain.BatchResponse; +import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource; +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.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link ModifyLoanApplicationCommandStrategy} + */ +public class ModifyLoanApplicationCommandStrategyTest { + + /** + * Test {@link ModifyLoanApplicationCommandStrategy#execute(BatchRequest, UriInfo)} happy path scenario. + */ + @ParameterizedTest + @MethodSource("commandParamDataProvider") + public void testExecuteSuccessScenario(final String command, final String responseBody) { + final TestContext testContext = new TestContext(); + final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4)); + final BatchRequest request = getBatchRequest(loanId, command); + + given(testContext.loansApiResource.modifyLoanApplication(eq(loanId), eq(command), eq(request.getBody()))).willReturn(responseBody); + + final BatchResponse response = testContext.testSubject.execute(request, testContext.uriInfo); + + // then + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); + verify(testContext.loansApiResource).modifyLoanApplication(eq(loanId), eq(command), eq(request.getBody())); + } + + /** + * Command Param data provider + * + * @return test data stream + */ + private static Stream commandParamDataProvider() { + return Stream.of( + Arguments.of("markAsFraud", "{\"officeId\":1,\"clientId\":2,\"loanId\":2,\"resourceId\":2,\"changes\":{\"fraud\":true}}"), + Arguments.of(null, "body")); + } + + /** + * Creates and returns a request with the given loan id. + * + * @param loanId + * the loan id + * @param queryParameter + * the command query param + * @return {@link BatchRequest} + */ + private BatchRequest getBatchRequest(final Long loanId, final String queryParameter) { + final BatchRequest batchRequest = new BatchRequest(); + + String relativeUrl = String.format("loans/%s", loanId); + + if (StringUtils.isNotBlank(queryParameter)) { + relativeUrl = relativeUrl + "?command=" + queryParameter; + } + + batchRequest.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); + batchRequest.setRelativeUrl(relativeUrl); + batchRequest.setMethod(HttpMethod.PUT); + batchRequest.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5))); + batchRequest.setBody("{\"fraud\": \"true\"}"); + return batchRequest; + } + + /** + * 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 loans api resource + */ + @Mock + private LoansApiResource loansApiResource; + + /** + * {@link ModifyLoanApplicationCommandStrategy} under test + */ + private final ModifyLoanApplicationCommandStrategy testSubject; + + /** + * Constructor + */ + TestContext() { + MockitoAnnotations.openMocks(this); + testSubject = new ModifyLoanApplicationCommandStrategy(loansApiResource); + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/UpdateDatatableEntryOneToManyCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/UpdateDatatableEntryOneToManyCommandStrategyTest.java index 7300252f5..4cec6c4db 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/UpdateDatatableEntryOneToManyCommandStrategyTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/UpdateDatatableEntryOneToManyCommandStrategyTest.java @@ -29,10 +29,13 @@ import org.apache.fineract.batch.domain.BatchRequest; import org.apache.fineract.batch.domain.BatchResponse; import org.apache.fineract.infrastructure.dataqueries.api.DatatablesApiResource; import org.apache.http.HttpStatus; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +/** + * Test class for {@link UpdateDatatableEntryOneToManyCommandStrategy}. + */ public class UpdateDatatableEntryOneToManyCommandStrategyTest { /** @@ -56,10 +59,10 @@ public class UpdateDatatableEntryOneToManyCommandStrategyTest { final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); // then - assertEquals(response.getStatusCode(), HttpStatus.SC_OK); - assertEquals(response.getRequestId(), request.getRequestId()); - assertEquals(response.getHeaders(), request.getHeaders()); - assertEquals(response.getBody(), responseBody); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(request.getRequestId(), response.getRequestId()); + assertEquals(request.getHeaders(), response.getHeaders()); + assertEquals(responseBody, response.getBody()); } /** 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 62d2fd93f..7b2ca1f65 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 @@ -37,7 +37,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; import org.apache.fineract.batch.command.internal.AdjustTransactionCommandStrategy; import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy; import org.apache.fineract.batch.domain.BatchRequest; @@ -46,6 +48,7 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.integrationtests.common.BatchHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.CollateralManagementHelper; +import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.charges.ChargesHelper; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; @@ -105,6 +108,7 @@ public class BatchApiTest { this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); this.datatableHelper = new DatatableHelper(this.requestSpec, this.responseSpec); + GlobalConfigurationHelper.updateIsAutomaticExternalIdGenerationEnabled(this.requestSpec, this.responseSpec, true); } /** @@ -365,7 +369,7 @@ public class BatchApiTest { final BatchRequest br3 = BatchHelper.applyLoanRequest(4724L, 4723L, productId, clientCollateralId); // Create a Collect Charges Request - final BatchRequest br4 = BatchHelper.collectChargesRequest(4725L, 4724L); + final BatchRequest br4 = BatchHelper.collectChargesByLoanIdRequest(4725L, 4724L); final List batchRequests = new ArrayList<>(); @@ -426,9 +430,10 @@ public class BatchApiTest { final BatchRequest disburseLoanRequest = BatchHelper.disburseLoanRequest(disburseLoanRequestId, approveLoanRequestId); - final BatchRequest createChargeRequest = BatchHelper.createChargeRequest(createChargeRequestId, disburseLoanRequestId, chargeId); + final BatchRequest createChargeRequest = BatchHelper.createChargeByLoanIdRequest(createChargeRequestId, disburseLoanRequestId, + chargeId); - final BatchRequest getChargeByIdRequest = BatchHelper.getChargeByIdCommandStrategy(getChargeByIdRequestId, createChargeRequestId); + final BatchRequest getChargeByIdRequest = BatchHelper.getChargeByLoanIdChargeId(getChargeByIdRequestId, createChargeRequestId); // Create batch requests list final List batchRequests = Arrays.asList(applyLoanRequest, approveLoanRequest, disburseLoanRequest, @@ -445,6 +450,183 @@ public class BatchApiTest { Assertions.assertEquals(HttpStatus.SC_OK, responses.get(4).getStatusCode(), "Verify Status Code 200 for Get Charge By Id"); } + /** + * Test for a successful charge adjustment. A '200' status code is expected on successful responses. + * + * @see AdjustTransactionCommandStrategy + */ + @Test + public void shouldReturnOkStatusOnSuccessfulChargeAdjustment() { + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal("1000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + final Long applyLoanRequestId = Long.valueOf(RandomStringUtils.randomNumeric(4)); + final Long approveLoanRequestId = applyLoanRequestId + 1; + final Long disburseLoanRequestId = approveLoanRequestId + 1; + final Long createChargeRequestId = disburseLoanRequestId + 1; + final Long adjustChargeRequestId = createChargeRequestId + 1; + final Long getTransactionRequestId = adjustChargeRequestId + 1; + + // 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 charge object and get id + final Integer chargeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec, + ChargesHelper.getLoanSpecifiedDueDateJSON()); + + final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId); + + final BatchRequest approveLoanRequest = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId); + + final BatchRequest disburseLoanRequest = BatchHelper.disburseLoanRequest(disburseLoanRequestId, approveLoanRequestId); + + final BatchRequest createChargeRequest = BatchHelper.createChargeByLoanIdRequest(createChargeRequestId, disburseLoanRequestId, + chargeId); + + final BatchRequest adjustChargeRequest = BatchHelper.adjustChargeRequest(adjustChargeRequestId, createChargeRequestId); + + final BatchRequest getTransactionRequest = BatchHelper.getTransactionByIdRequest(getTransactionRequestId, adjustChargeRequestId, + true); + + // Create batch requests list + final List batchRequests = Arrays.asList(applyLoanRequest, approveLoanRequest, disburseLoanRequest, + createChargeRequest, adjustChargeRequest, getTransactionRequest); + + // Create batch responses list + final List responses = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(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 Create Charge"); + Assertions.assertEquals(HttpStatus.SC_OK, responses.get(4).getStatusCode(), "Verify Status Code 200 for Adjust Charge"); + Assertions.assertEquals(HttpStatus.SC_OK, responses.get(5).getStatusCode(), "Verify Status Code 200 for Get Transaction By Id"); + + final FromJsonHelper jsonHelper = new FromJsonHelper(); + final JsonObject chargeAdjustment = jsonHelper.parse(responses.get(5).getBody()).getAsJsonObject().get("type").getAsJsonObject(); + + Assertions.assertEquals("Charge Adjustment", chargeAdjustment.get("value").getAsString()); + Assertions.assertTrue(chargeAdjustment.get("chargeAdjustment").getAsBoolean()); + } + + /** + * Tests that a new charge was added to a newly created loan and charges are Collected properly 200(OK) status was + * returned for successful responses. It first creates a new client and apply a loan, then creates a new charge for + * the create loan and then fetches all the applied charges using external id + * + * @see org.apache.fineract.batch.command.internal.CollectChargesCommandStrategy + * @see org.apache.fineract.batch.command.internal.CreateChargeCommandStrategy + */ + @Test + public void shouldReturnOkStatusForCreateAndGetChargeByExternalIdCommand() { + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal("1000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + final Long applyLoanRequestId = Long.valueOf(RandomStringUtils.randomNumeric(4)); + final Long approveLoanRequestId = applyLoanRequestId + 1; + final Long disburseLoanRequestId = approveLoanRequestId + 1; + final Long getLoanRequestId = disburseLoanRequestId + 1; + final Long createChargeRequestId = getLoanRequestId + 1; + final Long collectChargesRequestId = createChargeRequestId + 1; + final Long adjustChargeRequestId = createChargeRequestId + 1; + final Long getTransactionByExternalIdRequestId = adjustChargeRequestId + 1; + final Long getChargeByIdRequestId = getTransactionByExternalIdRequestId + 1; + + // 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 charge object and get id + final Integer chargeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec, + ChargesHelper.getLoanSpecifiedDueDateJSON()); + + final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId); + + final BatchRequest approveLoanRequest = BatchHelper.transistionLoanStateByExternalId(approveLoanRequestId, applyLoanRequestId, + LocalDate.now(ZoneId.systemDefault()).minusDays(10), "approve"); + + final BatchRequest disburseLoanRequest = BatchHelper.transistionLoanStateByExternalId(disburseLoanRequestId, approveLoanRequestId, + LocalDate.now(ZoneId.systemDefault()).minusDays(8), "disburse"); + + final BatchRequest getLoanRequest = BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId, + "associations=all"); + + final BatchRequest createChargeRequest = BatchHelper.createChargeByLoanExternalIdRequest(createChargeRequestId, getLoanRequestId, + chargeId); + + final BatchRequest collectChargesRequest = BatchHelper.collectChargesByLoanExternalIdRequest(collectChargesRequestId, + getLoanRequestId); + + // Create batch requests list + final List batchRequests = Arrays.asList(applyLoanRequest, approveLoanRequest, disburseLoanRequest, getLoanRequest, + createChargeRequest, collectChargesRequest); + + // Create batch responses list + final List responses = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(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 Get Loan"); + Assertions.assertEquals(HttpStatus.SC_OK, responses.get(4).getStatusCode(), "Verify Status Code 200 for Create Charge"); + Assertions.assertEquals(HttpStatus.SC_OK, responses.get(5).getStatusCode(), "Verify Status Code 200 for Collect charges"); + + final FromJsonHelper jsonHelper = new FromJsonHelper(); + final String loanExternalId = jsonHelper.parse(responses.get(3).getBody()).getAsJsonObject().get("externalId").getAsString(); + final String chargeExternalId = jsonHelper.parse(responses.get(4).getBody()).getAsJsonObject().get("resourceExternalId") + .getAsString(); + + final BatchRequest adjustChargeByExternalId = BatchHelper.adjustChargeByExternalIdRequest(adjustChargeRequestId, null, + loanExternalId, chargeExternalId); + final BatchRequest getTransactionByExternalIdRequest = BatchHelper + .getTransactionByExternalIdRequest(getTransactionByExternalIdRequestId, adjustChargeRequestId, loanExternalId, true); + final BatchRequest getChargeByIdRequest = BatchHelper.getChargeByLoanExternalIdChargeExternalId(getChargeByIdRequestId, + getTransactionByExternalIdRequestId, loanExternalId, chargeExternalId); + + // Create batch responses list + final List adjustChargeAndGetResponses = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, + this.responseSpec, + BatchHelper.toJsonString(Arrays.asList(adjustChargeByExternalId, getTransactionByExternalIdRequest, getChargeByIdRequest))); + + Assertions.assertEquals(HttpStatus.SC_OK, adjustChargeAndGetResponses.get(0).getStatusCode(), + "Verify Status Code 200 for Adjust Charge By External Id"); + Assertions.assertEquals(HttpStatus.SC_OK, adjustChargeAndGetResponses.get(1).getStatusCode(), + "Verify Status Code 200 for Get Transaction By Id"); + Assertions.assertEquals(HttpStatus.SC_OK, adjustChargeAndGetResponses.get(2).getStatusCode(), + "Verify Status Code 200 for Get Charge By Id"); + + final JsonObject chargeAdjustment = jsonHelper.parse(adjustChargeAndGetResponses.get(1).getBody()).getAsJsonObject().get("type") + .getAsJsonObject(); + + Assertions.assertEquals("Charge Adjustment", chargeAdjustment.get("value").getAsString()); + Assertions.assertTrue(chargeAdjustment.get("chargeAdjustment").getAsBoolean()); + } + /** * Tests that batch repayment for loans is happening properly. Collected properly 200(OK) status was returned for * successful responses. It first creates a new loan and then makes two repayments for it and then verifies that @@ -852,7 +1034,7 @@ public class BatchApiTest { final BatchRequest batchRequest3 = BatchHelper.disburseLoanRequest(disburseLoanRequestId, approveLoanRequestId); // Create a getTransaction Request - final BatchRequest batchRequest4 = BatchHelper.getTransactionByIdRequest(getTransactionRequestId, disburseLoanRequestId); + final BatchRequest batchRequest4 = BatchHelper.getTransactionByIdRequest(getTransactionRequestId, disburseLoanRequestId, false); final List batchRequests = Arrays.asList(batchRequest1, batchRequest2, batchRequest3, batchRequest4); @@ -1391,6 +1573,111 @@ public class BatchApiTest { Assertions.assertEquals(date, reversedOnDate); } + /** + * Test for the successful repayment reversal transaction using loan external id and transaction external id. A + * '200' status code is expected on successful responses. + * + * @see AdjustTransactionCommandStrategy + */ + @Test + public void shouldReturnOkStatusForBatchRepaymentReversalUsingExternalId() { + + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal("10000000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON); + + final LocalDate date = LocalDate.now(Utils.getZoneIdOfTenant()); + final Long applyLoanRequestId = Long.valueOf(RandomStringUtils.randomNumeric(4)); + final Long approveLoanRequestId = applyLoanRequestId + 1; + final Long disburseLoanRequestId = approveLoanRequestId + 1; + final Long getLoanBeforeTxnRequestId = disburseLoanRequestId + 1; + final Long repayLoanRequestId = getLoanBeforeTxnRequestId + 1; + final Long getLoanAfterTxnRequestId = repayLoanRequestId + 1; + final Long repayReversalRequestId = getLoanAfterTxnRequestId + 1; + final Long getLoanAfterReversal = repayReversalRequestId + 1; + + // Create client + final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientId); + final String loanExternalId = UUID.randomUUID().toString(); + + // Create an apply loan request + final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientIdAndExternalId(applyLoanRequestId, clientId, productId, + loanExternalId); + + // Create an approve loan request + final BatchRequest approveLoanRequest = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId); + + // Create a disburse loan request + final BatchRequest disburseLoanRequest = BatchHelper.disburseLoanRequest(disburseLoanRequestId, approveLoanRequestId); + + // Get loan transactions request + final BatchRequest getLoanTransactionsRequestBeforeTxn = BatchHelper.getLoanByIdRequest(getLoanBeforeTxnRequestId, + disburseLoanRequestId, "associations=transactions"); + + // Create a repayment request by external id + final BatchRequest repaymentRequest = BatchHelper.createTransactionRequestByLoanExternalId(repayLoanRequestId, + getLoanBeforeTxnRequestId, "repayment", "500", LocalDate.now(ZoneId.systemDefault())); + + // Get loan transactions request + final BatchRequest getLoanTransactionsRequestAfterTxn = BatchHelper.getLoanByIdRequest(getLoanAfterTxnRequestId, repayLoanRequestId, + "associations=transactions"); + + final List batchRequests = Arrays.asList(applyLoanRequest, approveLoanRequest, disburseLoanRequest, + getLoanTransactionsRequestBeforeTxn, repaymentRequest, getLoanTransactionsRequestAfterTxn); + + // Because loanExternalId & transactionExternalId are coming from 2 different responses, there is no easy way to + // use them as reference in 1 batch api call. + // So we are splitting repayment & reversal into 2 different batch api invocations + final List responses = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + BatchHelper.toJsonString(batchRequests)); + + final FromJsonHelper jsonHelper = new FromJsonHelper(); + final String loanExternalIdDisburseLoanResponse = jsonHelper.parse(responses.get(3).getBody()).getAsJsonObject().get("externalId") + .getAsString(); + final Long loanId = jsonHelper.parse(responses.get(3).getBody()).getAsJsonObject().get("id").getAsLong(); + final String transactionExternalId = jsonHelper.parse(responses.get(4).getBody()).getAsJsonObject().get("resourceExternalId") + .getAsString(); + Assertions.assertNotNull(loanExternalIdDisburseLoanResponse); + Assertions.assertEquals(loanExternalId, loanExternalIdDisburseLoanResponse); + Assertions.assertNotNull(transactionExternalId); + + // Create a repayment reversal request by external id + final BatchRequest repaymentReversalRequest = BatchHelper.createAdjustTransactionByExternalIdRequest(repayReversalRequestId, null, + loanExternalIdDisburseLoanResponse, transactionExternalId, "0", date); + + final BatchRequest getLoanByIdWithTransactions = BatchHelper.getLoanByIdRequest(loanId, getLoanAfterReversal, + repayReversalRequestId, "associations=transactions"); + + final List reversalAndGetBatchRequest = Arrays.asList(repaymentReversalRequest, getLoanByIdWithTransactions); + + final List reversalResponses = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, + this.responseSpec, BatchHelper.toJsonString(reversalAndGetBatchRequest)); + + final JsonObject repayment = jsonHelper.parse(reversalResponses.get(1).getBody()).getAsJsonObject().get("transactions") + .getAsJsonArray().get(2).getAsJsonObject(); + + final JsonArray dateArray = repayment.get("reversedOnDate").getAsJsonArray(); + final LocalDate reversedOnDate = LocalDate.of(dateArray.get(0).getAsInt(), dateArray.get(1).getAsInt(), + dateArray.get(2).getAsInt()); + + Assertions.assertEquals(HttpStatus.SC_OK, (long) reversalResponses.get(0).getStatusCode(), + "Verify Status Code 200 for repayment reversal"); + Assertions.assertEquals("Repayment", repayment.get("type").getAsJsonObject().get("value").getAsString()); + + Assertions.assertTrue(repayment.get("manuallyReversed").getAsBoolean()); + Assertions.assertEquals(date, reversedOnDate); + } + /** * Test for the successful repayment chargeback transaction. A '200' status code is expected on successful * responses. @@ -1798,6 +2085,131 @@ public class BatchApiTest { Assertions.assertEquals(changes.get(columnName2).getAsString(), columnValue2 + "1"); } + /** + * Tests that a loan information was successfully updated through updateLoanCommand. A 'changes' parameter is + * returned as part of response after successful update of loan information. In this test, we are marking an active + * loan account as fraud. + * + * @see org.apache.fineract.batch.command.internal.ModifyLoanApplicationCommandStrategy + */ + @Test + public void shouldReflectChangesOnLoanUpdate() { + + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal("1000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + final Long applyLoanRequestId = RandomUtils.nextLong(100, 1000); + final Long approveLoanRequestId = applyLoanRequestId + 1; + final Long disburseLoanRequestId = approveLoanRequestId + 1; + final Long updateLoanRequestId = disburseLoanRequestId + 1; + + // 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); + + final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId); + + final BatchRequest approveLoanRequest = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId); + + final BatchRequest disburseLoanRequest = BatchHelper.disburseLoanRequest(disburseLoanRequestId, approveLoanRequestId); + + final BatchRequest updateLoanRequest = BatchHelper.createLoanRequestMarkAsFraud(updateLoanRequestId, disburseLoanRequestId); + + // Create batch requests list + final List batchRequests = Arrays.asList(applyLoanRequest, approveLoanRequest, disburseLoanRequest, + updateLoanRequest); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + // Get the changes parameter from updateLoan Response + final JsonObject changes = new FromJsonHelper().parse(response.get(3).getBody()).getAsJsonObject().get("changes").getAsJsonObject(); + + Assertions.assertEquals(HttpStatus.SC_OK, response.get(3).getStatusCode(), "Verify Status Code 200 for update loan application"); + Assertions.assertEquals("true", changes.get("fraud").getAsString()); + } + + /** + * Tests that a loan information was successfully updated through updateLoanCommand using external id. A 'changes' + * parameter is returned as part of response after successful update of loan information. In this test, we are + * marking an active loan account as fraud. + * + * @see org.apache.fineract.batch.command.internal.ModifyLoanApplicationByExternalIdCommandStrategy + */ + @Test + public void shouldReflectChangesOnLoanUpdateByExternalId() { + + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal("1000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + final Long applyLoanRequestId = RandomUtils.nextLong(100, 1000); + final Long approveLoanRequestId = applyLoanRequestId + 1; + final Long disburseLoanRequestId = approveLoanRequestId + 1; + final Long updateLoanRequestId = disburseLoanRequestId + 1; + final Long getLoanRequestId = updateLoanRequestId + 1; + + // 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); + + final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId); + + final BatchRequest approveLoanRequest = BatchHelper.transistionLoanStateByExternalId(approveLoanRequestId, applyLoanRequestId, + LocalDate.now(ZoneId.systemDefault()).minusDays(10), "approve"); + + final BatchRequest disburseLoanRequest = BatchHelper.transistionLoanStateByExternalId(disburseLoanRequestId, approveLoanRequestId, + LocalDate.now(ZoneId.systemDefault()).minusDays(8), "disburse"); + + final BatchRequest updateLoanRequest = BatchHelper.modifyLoanByExternalIdRequest(updateLoanRequestId, approveLoanRequestId); + + final BatchRequest getLoanRequest = BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId, + "associations=all"); + + // Create batch requests list + final List batchRequests = Arrays.asList(applyLoanRequest, approveLoanRequest, disburseLoanRequest, updateLoanRequest, + getLoanRequest); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List responses = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + 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 update loan application"); + Assertions.assertEquals(HttpStatus.SC_OK, responses.get(4).getStatusCode(), "Verify Status Code 200 for Get Loan"); + + // Get the changes parameter from updateLoan Response + final JsonObject changes = new FromJsonHelper().parse(responses.get(3).getBody()).getAsJsonObject().get("changes") + .getAsJsonObject(); + Assertions.assertEquals("true", changes.get("fraud").getAsString()); + } + /** * Delete datatable * diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java index 25ba263d8..203f99e38 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java @@ -28,6 +28,7 @@ import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; +import java.math.BigDecimal; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; @@ -952,17 +953,20 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest { String loanExternalIdStr5 = UUID.randomUUID().toString(); applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr5); - this.loanTransactionHelper.approveLoan(loanExternalIdStr5, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022") - .approvedLoanAmount("1000").expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); - result = this.loanTransactionHelper.disburseLoan(loanExternalIdStr5, new PostLoansLoanIdRequest() - .actualDisbursementDate("2 September 2022").transactionAmount("1000").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.approveLoan(loanExternalIdStr5, + new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) + .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); + result = this.loanTransactionHelper.disburseLoan(loanExternalIdStr5, + new PostLoansLoanIdRequest().actualDisbursementDate("2 September 2022").transactionAmount(new BigDecimal("1000")) + .locale("en").dateFormat("dd MMMM yyyy")); // It's commented out for now, till it got fixed to return the loan externalId as well // assertEquals(loanExternalIdStr5, result.getResourceExternalId()); String loanExternalIdStr6 = UUID.randomUUID().toString(); applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr6); - this.loanTransactionHelper.approveLoan(loanExternalIdStr6, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022") - .approvedLoanAmount("1000").expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.approveLoan(loanExternalIdStr6, + new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) + .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); result = this.loanTransactionHelper.undoApprovalLoan(loanExternalIdStr6, new PostLoansLoanIdRequest()); assertEquals(loanExternalIdStr6, result.getResourceExternalId()); @@ -971,29 +975,36 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest { String loanExternalIdStr7 = UUID.randomUUID().toString(); applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr7, savingsId.toString()); - this.loanTransactionHelper.approveLoan(loanExternalIdStr7, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022") - .approvedLoanAmount("1000").expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); - result = this.loanTransactionHelper.disburseToSavingsLoan(loanExternalIdStr7, new PostLoansLoanIdRequest() - .actualDisbursementDate("2 September 2022").transactionAmount("1000").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.approveLoan(loanExternalIdStr7, + new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) + .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); + result = this.loanTransactionHelper.disburseToSavingsLoan(loanExternalIdStr7, + new PostLoansLoanIdRequest().actualDisbursementDate("2 September 2022").transactionAmount(new BigDecimal("1000")) + .locale("en").dateFormat("dd MMMM yyyy")); assertEquals(loanExternalIdStr7, result.getResourceExternalId()); String loanExternalIdStr8 = UUID.randomUUID().toString(); applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr8); - this.loanTransactionHelper.approveLoan(loanExternalIdStr8, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022") - .approvedLoanAmount("1000").expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); - this.loanTransactionHelper.disburseLoan(loanExternalIdStr8, new PostLoansLoanIdRequest() - .actualDisbursementDate("2 September 2022").transactionAmount("1000").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.approveLoan(loanExternalIdStr8, + new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) + .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.disburseLoan(loanExternalIdStr8, + new PostLoansLoanIdRequest().actualDisbursementDate("2 September 2022").transactionAmount(new BigDecimal("1000")) + .locale("en").dateFormat("dd MMMM yyyy")); result = this.loanTransactionHelper.undoDisbursalLoan(loanExternalIdStr8, new PostLoansLoanIdRequest()); assertEquals(loanExternalIdStr8, result.getResourceExternalId()); String loanExternalIdStr9 = UUID.randomUUID().toString(); applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr9); - this.loanTransactionHelper.approveLoan(loanExternalIdStr9, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022") - .approvedLoanAmount("1000").expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); - this.loanTransactionHelper.disburseLoan(loanExternalIdStr9, new PostLoansLoanIdRequest() - .actualDisbursementDate("2 September 2022").transactionAmount("1000").locale("en").dateFormat("dd MMMM yyyy")); - this.loanTransactionHelper.disburseLoan(loanExternalIdStr9, new PostLoansLoanIdRequest() - .actualDisbursementDate("3 September 2022").transactionAmount("1000").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.approveLoan(loanExternalIdStr9, + new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) + .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.disburseLoan(loanExternalIdStr9, + new PostLoansLoanIdRequest().actualDisbursementDate("2 September 2022").transactionAmount(new BigDecimal("1000")) + .locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.disburseLoan(loanExternalIdStr9, + new PostLoansLoanIdRequest().actualDisbursementDate("3 September 2022").transactionAmount(new BigDecimal("1000")) + .locale("en").dateFormat("dd MMMM yyyy")); result = this.loanTransactionHelper.undoLastDisbursalLoan(loanExternalIdStr9, new PostLoansLoanIdRequest()); assertEquals(loanExternalIdStr9, result.getResourceExternalId()); @@ -1020,7 +1031,7 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest { String loanExternalIdStr13 = UUID.randomUUID().toString(); applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr13); result = this.loanTransactionHelper.approveLoan(loanExternalIdStr13, - new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount("1000") + new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); assertEquals(loanExternalIdStr13, result.getResourceExternalId()); @@ -1032,11 +1043,12 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest { applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr14); String transactionExternalId = UUID.randomUUID().toString(); result = this.loanTransactionHelper.approveLoan(loanExternalIdStr14, - new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount("1000") + new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); assertEquals(loanExternalIdStr14, result.getResourceExternalId()); - this.loanTransactionHelper.disburseLoan(loanExternalIdStr14, new PostLoansLoanIdRequest() - .actualDisbursementDate("2 September 2022").transactionAmount("1000").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.disburseLoan(loanExternalIdStr14, + new PostLoansLoanIdRequest().actualDisbursementDate("2 September 2022").transactionAmount(new BigDecimal("1000")) + .locale("en").dateFormat("dd MMMM yyyy")); PostLoansLoanIdTransactionsResponse closeResult = this.loanTransactionHelper.closeLoan(loanExternalIdStr14, new PostLoansLoanIdTransactionsRequest().transactionDate("3 September 2022").locale("en").dateFormat("dd MMMM yyyy") .externalId(transactionExternalId)); @@ -1046,10 +1058,11 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest { String transactionExternalId2 = UUID.randomUUID().toString(); applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr15); result = this.loanTransactionHelper.approveLoan(loanExternalIdStr15, - new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount("1000") + new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); - this.loanTransactionHelper.disburseLoan(loanExternalIdStr15, new PostLoansLoanIdRequest() - .actualDisbursementDate("2 September 2022").transactionAmount("1000").locale("en").dateFormat("dd MMMM yyyy")); + this.loanTransactionHelper.disburseLoan(loanExternalIdStr15, + new PostLoansLoanIdRequest().actualDisbursementDate("2 September 2022").transactionAmount(new BigDecimal("1000")) + .locale("en").dateFormat("dd MMMM yyyy")); assertEquals(loanExternalIdStr15, result.getResourceExternalId()); PostLoansLoanIdTransactionsResponse forecloseResult = this.loanTransactionHelper.forecloseLoan(loanExternalIdStr15, new PostLoansLoanIdTransactionsRequest().transactionDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy") 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 3f8fca807..e2b38aa6f 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 @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.stream.Collectors; import javax.ws.rs.HttpMethod; import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy; @@ -302,6 +303,25 @@ public final class BatchHelper { * @return {@link BatchRequest} */ public static BatchRequest applyLoanRequestWithClientId(final Long requestId, final Integer clientId, final Integer productId) { + return applyLoanRequestWithClientIdAndExternalId(requestId, clientId, productId, UUID.randomUUID().toString()); + } + + /** + * Creates and returns a {@link org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy} request with + * given clientId, external id and product id. + * + * @param requestId + * the request id + * @param clientId + * the client id + * @param productId + * the product id + * @param externalId + * the external id + * @return {@link BatchRequest} + */ + public static BatchRequest applyLoanRequestWithClientIdAndExternalId(final Long requestId, final Integer clientId, + final Integer productId, final String externalId) { final BatchRequest br = new BatchRequest(); @@ -315,7 +335,7 @@ public final class BatchHelper { + "\"repaymentEvery\": 1, \"repaymentFrequencyType\": 2, \"interestRatePerPeriod\": 10," + "\"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1," + "\"transactionProcessingStrategyCode\": \"mifos-standard-strategy\", \"expectedDisbursementDate\": \"10 Jun 2013\"," - + "\"submittedOnDate\": \"10 Jun 2013\"}", clientId, productId); + + "\"submittedOnDate\": \"10 Jun 2013\", \"externalId\": \"%s\"}", clientId, productId, externalId); br.setBody(body); @@ -349,7 +369,7 @@ public final class BatchHelper { /** * Creates and returns a {@link org.apache.fineract.batch.command.internal.CreateChargeCommandStrategy} Request with - * given requestId and reference + * given requestId and reference based on loan id * * @param requestId * the batch request id. @@ -359,11 +379,46 @@ public final class BatchHelper { * the charge id used for getting charge type. * @return BatchRequest */ - public static BatchRequest createChargeRequest(final Long requestId, final Long reference, final Integer chargeId) { + public static BatchRequest createChargeByLoanIdRequest(final Long requestId, final Long reference, final Integer chargeId) { + return createChargeRequest(requestId, reference, "loans/$.loanId/charges", chargeId); + } + + /** + * Creates and returns a + * {@link org.apache.fineract.batch.command.internal.CreateChargeByLoanExternalIdCommandStrategy} Request with given + * requestId and reference based on loan external id + * + * @param requestId + * the batch request id. + * @param reference + * the reference id. + * @param chargeId + * the charge id used for getting charge type. + * @return BatchRequest + */ + public static BatchRequest createChargeByLoanExternalIdRequest(final Long requestId, final Long reference, final Integer chargeId) { + return createChargeRequest(requestId, reference, "loans/external-id/$.externalId/charges", chargeId); + } + + /** + * Creates and returns a Batch Request with given requestId and reference + * + * @param requestId + * the batch request id. + * @param reference + * the reference id. + * @param relativeUrl + * the relative url reference. + * @param chargeId + * the charge id used for getting charge type. + * @return BatchRequest + */ + private static BatchRequest createChargeRequest(final Long requestId, final Long reference, final String relativeUrl, + final Integer chargeId) { final BatchRequest br = new BatchRequest(); br.setRequestId(requestId); - br.setRelativeUrl("loans/$.loanId/charges"); + br.setRelativeUrl(relativeUrl); br.setMethod("POST"); br.setReference(reference); @@ -378,20 +433,103 @@ public final class BatchHelper { return br; } + /** + * Creates and returns a {@link org.apache.fineract.batch.command.internal.AdjustChargeCommandStrategy} Request with + * given requestId and reference + * + * @param requestId + * the batch request id. + * @param reference + * the reference id. + * @return BatchRequest + */ + public static BatchRequest adjustChargeRequest(final Long requestId, final Long reference) { + + final BatchRequest br = new BatchRequest(); + br.setRequestId(requestId); + br.setRelativeUrl("loans/$.loanId/charges/$.resourceId?command=adjustment"); + br.setMethod("POST"); + br.setReference(reference); + br.setBody("{\"amount\":7.00,\"locale\":\"en\"}"); + + return br; + } + + /** + * Creates and returns a + * {@link org.apache.fineract.batch.command.internal.AdjustChargeByChargeExternalIdCommandStrategy} Request with + * given requestId and reference + * + * @param requestId + * the batch request id. + * @param reference + * the reference id. + * @param loanExternalId + * the loan external id. + * @param chargeExternalId + * the charge external id + * @return BatchRequest + */ + public static BatchRequest adjustChargeByExternalIdRequest(final Long requestId, final Long reference, final String loanExternalId, + final String chargeExternalId) { + + final BatchRequest br = new BatchRequest(); + br.setRequestId(requestId); + br.setRelativeUrl( + String.format("loans/external-id/%s/charges/external-id/%s?command=adjustment", loanExternalId, chargeExternalId)); + br.setMethod("POST"); + br.setReference(reference); + br.setBody("{\"amount\":7.00,\"locale\":\"en\"}"); + + return br; + } + /** * Creates and returns a {@link org.apache.fineract.batch.command.internal.CollectChargesCommandStrategy} Request * with given requestId and reference. * * @param requestId + * the request id * @param reference + * the reference id * @return BatchRequest */ - public static BatchRequest collectChargesRequest(final Long requestId, final Long reference) { + public static BatchRequest collectChargesByLoanIdRequest(final Long requestId, final Long reference) { + return collectChargesRequest(requestId, reference, "loans/$.loanId/charges"); + } + + /** + * Creates and returns a + * {@link org.apache.fineract.batch.command.internal.CollectChargesByLoanExternalIdCommandStrategy} Request with + * given requestId and reference. + * + * @param requestId + * the request id + * @param reference + * the reference id + * @return BatchRequest + */ + public static BatchRequest collectChargesByLoanExternalIdRequest(final Long requestId, final Long reference) { + return collectChargesRequest(requestId, reference, "loans/external-id/$.externalId/charges"); + } + + /** + * Creates and returns a Batch Request with given requestId and reference. + * + * @param requestId + * the request id + * @param reference + * the reference id + * @param relativeUrl + * the relative url + * @return BatchRequest + */ + private static BatchRequest collectChargesRequest(final Long requestId, final Long reference, final String relativeUrl) { final BatchRequest br = new BatchRequest(); br.setRequestId(requestId); - br.setRelativeUrl("loans/$.loanId/charges"); + br.setRelativeUrl(relativeUrl); br.setReference(reference); br.setMethod("GET"); br.setBody("{ }"); @@ -399,6 +537,29 @@ public final class BatchHelper { return br; } + /** + * Creates and returns a Batch request with given requestId and reference. + * + * @param requestId + * the request id + * @param reference + * the reference + * @param relativeUrl + * the relative url + * @return the {@link BatchRequest} + */ + private static BatchRequest getChargeById(final Long requestId, final Long reference, final String relativeUrl) { + + final BatchRequest br = new BatchRequest(); + br.setRequestId(requestId); + br.setRelativeUrl(relativeUrl); + br.setMethod(HttpMethod.GET); + br.setReference(reference); + br.setBody("{}"); + + return br; + } + /** * Creates and returns a {@link org.apache.fineract.batch.command.internal.GetChargeByIdCommandStrategy} request * with given requestId and reference. @@ -409,18 +570,25 @@ public final class BatchHelper { * the reference * @return the {@link BatchRequest} */ - public static BatchRequest getChargeByIdCommandStrategy(final Long requestId, final Long reference) { + public static BatchRequest getChargeByLoanIdChargeId(final Long requestId, final Long reference) { + return getChargeById(requestId, reference, "loans/$.loanId/charges/$.resourceId"); + } - final BatchRequest br = new BatchRequest(); - String relativeUrl = "loans/$.loanId/charges/$.resourceId"; - - br.setRequestId(requestId); - br.setRelativeUrl(relativeUrl); - br.setMethod(HttpMethod.GET); - br.setReference(reference); - br.setBody("{}"); - - return br; + /** + * Creates and returns a + * {@link org.apache.fineract.batch.command.internal.GetChargeByChargeExternalIdCommandStrategy} request with given + * requestId and reference. + * + * @param requestId + * the request id + * @param reference + * the reference + * @return the {@link BatchRequest} + */ + public static BatchRequest getChargeByLoanExternalIdChargeExternalId(final Long requestId, final Long reference, + final String loanExternalId, final String chargeExternalId) { + return getChargeById(requestId, reference, + String.format("loans/external-id/%s/charges/external-id/%s", loanExternalId, chargeExternalId)); } /** @@ -528,6 +696,41 @@ public final class BatchHelper { return br; } + /** + * Creates and returns a + * {@link org.apache.fineract.batch.command.internal.LoanStateTransistionsByExternalIdCommandStrategy} Request with + * given requestId and reference. + * + * + * @param requestId + * the request ID + * @param reference + * the reference ID + * @param date + * the actual disbursement date + * @param command + * the action to transistion + * @return BatchRequest the batch request + */ + public static BatchRequest transistionLoanStateByExternalId(final Long requestId, final Long reference, final LocalDate date, + final String command) { + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setRelativeUrl("loans/external-id/$.resourceExternalId?command=" + command); + br.setReference(reference); + br.setMethod("POST"); + String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + if ("disburse".equals(command)) { + br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"actualDisbursementDate\": \"" + dateString + "\"}"); + } else if ("approve".equals(command)) { + br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"approvedOnDate\": \"" + dateString + "\"," + + "\"note\": \"Loan approval note\"}"); + } + + return br; + } + /** * Creates and returns a {@link CreateTransactionLoanCommandStrategy} Request with given requestId. * @@ -572,6 +775,37 @@ public final class BatchHelper { return br; } + /** + * Creates and returns a {@link CreateTransactionLoanCommandStrategy} Request with given requestId. + * + * @param requestId + * the request ID + * @param reference + * the reference ID + * @param transactionCommand + * the transaction command to process + * @param amount + * the amount + * @param date + * the transaction date + * @return BatchRequest the batch request + */ + public static BatchRequest createTransactionRequestByLoanExternalId(final Long requestId, final Long reference, + final String transactionCommand, final String amount, final LocalDate date) { + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setReference(reference); + br.setRelativeUrl(String.format("loans/external-id/$.externalId/transactions?command=%s", transactionCommand)); + 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; + } + /** * Creates and returns a {@link CreateTransactionLoanCommandStrategy} request with given request ID. * @@ -725,12 +959,50 @@ public final class BatchHelper { * the request id * @param reference * the reference + * @param subResourceId + * whether the subResourceId is used * @return the {@link BatchRequest} */ - public static BatchRequest getTransactionByIdRequest(final Long requestId, final Long reference) { + public static BatchRequest getTransactionByIdRequest(final Long requestId, final Long reference, final Boolean subResourceId) { final BatchRequest br = new BatchRequest(); - String relativeUrl = "loans/$.loanId/transactions/$.resourceId"; + String relativeUrl; + if (subResourceId) { + relativeUrl = "loans/$.loanId/transactions/$.subResourceId"; + } else { + relativeUrl = "loans/$.loanId/transactions/$.resourceId"; + } + + br.setRequestId(requestId); + br.setRelativeUrl(relativeUrl); + br.setMethod(HttpMethod.GET); + br.setReference(reference); + br.setBody("{}"); + + return br; + } + + /** + * Creates and returns a + * {@link org.apache.fineract.batch.command.internal.GetTransactionByExternalIdCommandStrategy} request with given + * requestId and reference. + * + * @param requestId + * the request id + * @param reference + * the reference + * @return the {@link BatchRequest} + */ + public static BatchRequest getTransactionByExternalIdRequest(final Long requestId, final Long reference, final String loanExternalId, + final Boolean subResourceExternalId) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl; + if (subResourceExternalId) { + relativeUrl = String.format("loans/external-id/%s/transactions/external-id/$.subResourceExternalId", loanExternalId); + } else { + relativeUrl = String.format("loans/external-id/%s/transactions/external-id/$.resourceExternalId", loanExternalId); + } br.setRequestId(requestId); br.setRelativeUrl(relativeUrl); @@ -770,6 +1042,35 @@ public final class BatchHelper { return br; } + /** + * Creates and returns a {@link org.apache.fineract.batch.command.internal.GetLoanByExternalIdCommandStrategy} + * request with given requestId and reference. + * + * @param requestId + * the request id + * @param reference + * the reference + * @param queryParameter + * the query parameters + * @return the {@link BatchRequest} + */ + public static BatchRequest getLoanByExternalIdRequest(final Long requestId, final Long reference, final String queryParameter) { + + final BatchRequest br = new BatchRequest(); + String relativeUrl = "loans/external-id/$.resourceExternalId"; + if (queryParameter != null) { + relativeUrl = relativeUrl + "?" + queryParameter; + } + + br.setRequestId(requestId); + br.setRelativeUrl(relativeUrl); + br.setMethod(HttpMethod.GET); + br.setReference(reference); + br.setBody("{}"); + + return br; + } + /** * Creates and returns a {@link org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy} request with * given loan id and query param. @@ -781,13 +1082,33 @@ public final class BatchHelper { * @return the {@link BatchRequest} */ public static BatchRequest getLoanByIdRequest(final Long loanId, final String queryParameter) { + return getLoanByIdRequest(loanId, 4567L, null, queryParameter); + } + + /** + * 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 requestId + * the request id + * @param referenceId + * the reference id + * @param queryParameter + * the query parameters + * @return the {@link BatchRequest} + */ + public static BatchRequest getLoanByIdRequest(final Long loanId, final Long requestId, final Long referenceId, + 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.setRequestId(requestId); + br.setReference(referenceId); br.setRelativeUrl(relativeUrl); br.setMethod(HttpMethod.GET); br.setBody("{}"); @@ -912,6 +1233,39 @@ public final class BatchHelper { return br; } + /** + * Creates and returns a batch request to create an adjust transaction request using external id. + * + * @param requestId + * the request ID + * @param reference + * the reference + * @param loanExternalId + * the loan external id + * @param transactionExternalId + * the transaction external id + * @param amount + * the amount + * @param date + * the date + * @return the {@link BatchRequest} + */ + public static BatchRequest createAdjustTransactionByExternalIdRequest(final Long requestId, final Long reference, + final String loanExternalId, final String transactionExternalId, final String amount, final LocalDate date) { + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setReference(reference); + br.setRelativeUrl(String.format("loans/external-id/%s/transactions/external-id/%s", loanExternalId, transactionExternalId)); + 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; + } + /** * Creates and returns a batch request to create a chargeback transaction request. * @@ -937,6 +1291,50 @@ public final class BatchHelper { } + /** + * Creates and returns a batch request to update a Loan account as fraud. + * + * @param requestId + * the request ID + * @param reference + * the reference + * @return the {@link BatchRequest} + */ + public static BatchRequest createLoanRequestMarkAsFraud(final Long requestId, final Long reference) { + + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setRelativeUrl("loans/$.loanId?command=markAsFraud"); + br.setMethod("PUT"); + br.setReference(reference); + br.setBody("{\"fraud\": \"true\"}"); + + return br; + } + + /** + * Creates and returns a batch request to update a Loan account as fraud by loan external id. + * + * @param requestId + * the request ID + * @param reference + * the reference + * @return the {@link BatchRequest} + */ + public static BatchRequest modifyLoanByExternalIdRequest(final Long requestId, final Long reference) { + + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setRelativeUrl("loans/external-id/$.resourceExternalId?command=markAsFraud"); + br.setMethod("PUT"); + br.setReference(reference); + br.setBody("{\"fraud\": \"true\"}"); + + return br; + } + /** * Creates and returns a batch request to query datatable entry. * diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java index 041e0b1f1..d1100d57a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java @@ -629,4 +629,10 @@ public class GlobalConfigurationHelper { assertEquals(updatedConfiguration.getEnabled(), enabled); } + public static Integer updateIsAutomaticExternalIdGenerationEnabled(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final boolean enabled) { + long configId = 50; + return updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, configId, enabled); + } + }