This is an automated email from the ASF dual-hosted git repository.
arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 1d2fc7371 FINERACT-1971: Internal server error fix for handling batch
API hard locked loan
1d2fc7371 is described below
commit 1d2fc737150d00ad1d76a4ea84c40063e3b3867a
Author: Arnold Galovics <[email protected]>
AuthorDate: Mon Feb 12 17:39:35 2024 +0100
FINERACT-1971: Internal server error fix for handling batch API hard locked
loan
---
.../jobs/filter/LoanCOBFilterHelper.java | 11 +++-
.../integrationtests/BaseLoanIntegrationTest.java | 14 +++++
.../integrationtests/BatchLoanIntegrationTest.java | 63 ++++++++++++++++++++++
.../fineract/integrationtests/common/Utils.java | 7 ++-
.../common/loans/LoanAccountLockHelper.java | 3 +-
5 files changed, 93 insertions(+), 5 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBFilterHelper.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBFilterHelper.java
index c412a2dea..6225d7f9c 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBFilterHelper.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBFilterHelper.java
@@ -29,6 +29,7 @@ import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
@@ -173,6 +174,10 @@ public class LoanCOBFilterHelper {
}
}
+ private boolean isLoanHardLocked(Long... loanIds) {
+ return isLoanHardLocked(Arrays.asList(loanIds));
+ }
+
private boolean isLoanHardLocked(List<Long> loanIds) {
return
loanIds.stream().anyMatch(loanAccountLockService::isLoanHardLocked);
}
@@ -208,7 +213,11 @@ public class LoanCOBFilterHelper {
// check the body for Loan ID
Long loanId = getTopLevelLoanIdFromBatchRequest(batchRequest);
if (loanId != null) {
- loanIds.add(loanId);
+ if (isLoanHardLocked(loanId)) {
+ throw new LoanIdsHardLockedException(loanId);
+ } else {
+ loanIds.add(loanId);
+ }
}
}
return loanIds;
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
index 1352ff0cb..790751528 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
@@ -75,6 +75,8 @@ import
org.apache.fineract.integrationtests.common.accounting.Account;
import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
import
org.apache.fineract.integrationtests.common.accounting.JournalEntryHelper;
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
+import org.apache.fineract.integrationtests.common.error.ErrorResponse;
+import org.apache.fineract.integrationtests.common.loans.LoanAccountLockHelper;
import org.apache.fineract.integrationtests.common.loans.LoanProductHelper;
import
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import
org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
@@ -113,6 +115,9 @@ public abstract class BaseLoanIntegrationTest {
protected final InlineLoanCOBHelper inlineLoanCOBHelper = new
InlineLoanCOBHelper(requestSpec, responseSpec);
protected BusinessDateHelper businessDateHelper = new BusinessDateHelper();
+
+ protected final LoanAccountLockHelper loanAccountLockHelper = new
LoanAccountLockHelper(requestSpec,
+ createResponseSpecification(Matchers.is(202)));
protected DateTimeFormatter dateTimeFormatter =
DateTimeFormatter.ofPattern(DATETIME_PATTERN);
// asset
@@ -342,6 +347,10 @@ public abstract class BaseLoanIntegrationTest {
}
}
+ protected void placeHardLockOnLoan(Long loanId) {
+ loanAccountLockHelper.placeSoftLockOnLoanAccount(loanId.intValue(),
"LOAN_COB_CHUNK_PROCESSING");
+ }
+
protected void executeInlineCOB(Long loanId) {
inlineLoanCOBHelper.executeInlineCOB(List.of(loanId));
}
@@ -634,6 +643,11 @@ public abstract class BaseLoanIntegrationTest {
public List<BatchResponse> executeEnclosingTransaction() {
return
BatchHelper.postBatchRequestsWithEnclosingTransaction(requestSpec,
responseSpec, BatchHelper.toJsonString(requests));
}
+
+ public ErrorResponse
executeEnclosingTransactionError(ResponseSpecification responseSpec) {
+ return
BatchHelper.postBatchRequestsWithoutEnclosingTransactionError(requestSpec,
responseSpec,
+ BatchHelper.toJsonString(requests));
+ }
}
@ToString
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchLoanIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchLoanIntegrationTest.java
index 3fcc49dd7..0cb26879c 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchLoanIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchLoanIntegrationTest.java
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.integrationtests;
+import io.restassured.builder.ResponseSpecBuilder;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
@@ -28,6 +29,7 @@ import
org.apache.fineract.client.models.PostLoansLoanIdResponse;
import org.apache.fineract.client.models.PostLoansRequest;
import org.apache.fineract.client.models.PostLoansResponse;
import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.error.ErrorResponse;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -98,4 +100,65 @@ public class BatchLoanIntegrationTest extends
BaseLoanIntegrationTest {
});
});
}
+
+ @Test
+ public void
test_InlineLoanCOB_ShouldExecute_WhenLoanIsHardLocked_And_RescheduleIsRequestedViaBatchApi()
{
+ AtomicLong createdLoanId = new AtomicLong();
+
+ runAt("01 January 2023", () -> {
+ // Create Client
+ Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
+
+ int numberOfRepayments = 24;
+ int repaymentEvery = 1;
+
+ // Create Loan Product
+ PostLoanProductsRequest product =
createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct() //
+ .numberOfRepayments(numberOfRepayments) //
+ .repaymentEvery(repaymentEvery) //
+
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()); //
+
+ PostLoanProductsResponse loanProductResponse =
loanProductHelper.createLoanProduct(product);
+ Long loanProductId = loanProductResponse.getResourceId();
+
+ // Apply and Approve Loan
+ double amount = 1250.0;
+
+ PostLoansRequest applicationRequest = applyLoanRequest(clientId,
loanProductId, "01 January 2023", amount, numberOfRepayments)//
+ .repaymentEvery(repaymentEvery)//
+ .loanTermFrequency(numberOfRepayments)//
+ .repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
+ .loanTermFrequencyType(RepaymentFrequencyType.MONTHS);
+
+ PostLoansResponse postLoansResponse =
loanTransactionHelper.applyLoan(applicationRequest);
+
+ PostLoansLoanIdResponse approvedLoanResult =
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
+ approveLoanRequest(amount, "01 January 2023"));
+
+ Long loanId = approvedLoanResult.getLoanId();
+
+ // disburse Loan
+ disburseLoan(loanId, BigDecimal.valueOf(1250.0), "01 January
2023");
+
+ createdLoanId.set(loanId);
+ });
+
+ runAt("02 January 2023", () -> {
+ executeInlineCOB(createdLoanId.get());
+ });
+
+ runAt("05 January 2023", () -> {
+ long loanId = createdLoanId.get();
+ placeHardLockOnLoan(loanId);
+ runAsNonByPass(() -> {
+
+ ErrorResponse response = batchRequest() //
+ .rescheduleLoan(1L, loanId, "01 January 2023", "01
February 2023", "01 March 2023") //
+ .approveRescheduleLoan(2L, 1L, "01 January 2023") //
+ .executeEnclosingTransactionError(new
ResponseSpecBuilder().expectStatusCode(409).build()); //
+
+ Assertions.assertEquals(HttpStatus.SC_CONFLICT,
Integer.parseInt(response.getHttpStatusCode()));
+ });
+ });
+ }
}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java
index 261f7b976..d842eb55b 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java
@@ -251,8 +251,11 @@ public final class Utils {
public static <T> T performServerPost(final RequestSpecification
requestSpec, final ResponseSpecification responseSpec,
final String postURL, final String jsonBodyToSend, final String
jsonAttributeToGetBack) {
LOG.info("JSON {}", jsonBodyToSend);
- final String json =
given().spec(requestSpec).body(jsonBodyToSend).expect().spec(responseSpec).log().ifError().when().post(postURL)
- .andReturn().asString();
+ RequestSpecification spec = given().spec(requestSpec);
+ if (StringUtils.isNotBlank(jsonBodyToSend)) {
+ spec = spec.body(jsonBodyToSend);
+ }
+ final String json =
spec.expect().spec(responseSpec).log().ifError().when().post(postURL).andReturn().asString();
if (jsonAttributeToGetBack == null) {
return (T) json;
}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanAccountLockHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanAccountLockHelper.java
index 5bfa9887f..a9b9f52a4 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanAccountLockHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanAccountLockHelper.java
@@ -43,8 +43,7 @@ public class LoanAccountLockHelper extends IntegrationTest {
public String placeSoftLockOnLoanAccount(Integer loanId, String lockOwner,
String error) {
return Utils.performServerPost(requestSpec, responseSpec,
- INTERNAL_PLACE_LOCK_ON_LOAN_ACCOUNT_URL + loanId +
"/place-lock/" + lockOwner + "?" + Utils.TENANT_IDENTIFIER,
- error == null ? GSON.toJson(null) : error);
+ INTERNAL_PLACE_LOCK_ON_LOAN_ACCOUNT_URL + loanId +
"/place-lock/" + lockOwner + "?" + Utils.TENANT_IDENTIFIER, error);
}
}