You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2023/02/17 12:09:33 UTC
[fineract] branch develop updated: [FINERACT-1884] write API calls on loan makes Inline COB and catches up the loan to the current COB business date
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 3744ad54e [FINERACT-1884] write API calls on loan makes Inline COB and catches up the loan to the current COB business date
3744ad54e is described below
commit 3744ad54eee32b78c87fecd39aab29ca765780d2
Author: taskain7 <ta...@gmail.com>
AuthorDate: Thu Feb 16 12:51:27 2023 +0100
[FINERACT-1884] write API calls on loan makes Inline COB and catches up the loan to the current COB business date
---
.../jobs/filter/LoanCOBApiFilter.java | 16 +++++--
.../jobs/filter/LoanCOBApiFilterTest.java | 33 +++++++++++++-
.../inlinecob/InlineLoanCOBTest.java | 51 +++++++++++++++++++++-
3 files changed, 94 insertions(+), 6 deletions(-)
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java
index 9dd401fec..571fb3a25 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java
@@ -31,18 +31,22 @@ import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.UriInfo;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
import org.apache.fineract.cob.service.InlineLoanCOBExecutorServiceImpl;
import org.apache.fineract.cob.service.LoanAccountLockService;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
import org.apache.fineract.infrastructure.core.filters.BatchFilter;
import org.apache.fineract.infrastructure.core.filters.BatchFilterChain;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.useradministration.exception.UnAuthenticatedUserException;
import org.apache.http.HttpStatus;
import org.springframework.http.HttpMethod;
@@ -57,6 +61,7 @@ public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchFilte
private final LoanAccountLockService loanAccountLockService;
private final PlatformSecurityContext context;
private final InlineLoanCOBExecutorServiceImpl inlineLoanCOBExecutorService;
+ private final LoanRepository loanRepository;
private static final List<HttpMethod> HTTP_METHODS = List.of(HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE);
@@ -115,9 +120,9 @@ public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchFilte
proceed(filterChain, request, response);
} else {
try {
- List<Long> result = calculateRelevantLoanIds(request.getPathInfo());
- if (isLoanSoftLocked(result)) {
- executeInlineCob(result);
+ List<Long> loanIds = calculateRelevantLoanIds(request.getPathInfo());
+ if (isLoanSoftLocked(loanIds) || isLoanBehind(loanIds)) {
+ executeInlineCob(loanIds);
}
proceed(filterChain, request, response);
} catch (LoanIdsHardLockedException e) {
@@ -130,6 +135,11 @@ public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchFilte
}
}
+ private boolean isLoanBehind(List<Long> loanIds) {
+ return CollectionUtils.isNotEmpty(loanRepository
+ .findAllNonClosedLoansBehindByLoanIds(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE), loanIds));
+ }
+
private List<Long> calculateRelevantLoanIds(String pathInfo) {
boolean isGlim = isGlim(pathInfo);
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java
index f37895f34..0ccf932f3 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java
@@ -18,6 +18,8 @@
*/
package org.apache.fineract.infrastructure.jobs.filter;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -27,15 +29,22 @@ import com.sun.research.ws.wadl.HTTPMethods;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.ZoneId;
import java.util.Collections;
+import java.util.HashMap;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import org.apache.fineract.cob.service.InlineLoanCOBExecutorServiceImpl;
import org.apache.fineract.cob.service.LoanAccountLockService;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Assertions;
@@ -63,6 +72,8 @@ class LoanCOBApiFilterTest {
private PlatformSecurityContext context;
@Mock
private InlineLoanCOBExecutorServiceImpl inlineLoanCOBExecutorService;
+ @Mock
+ private LoanRepository loanRepository;
@Test
void shouldLoanAndExternalMatchToo() {
@@ -117,34 +128,52 @@ class LoanCOBApiFilterTest {
}
@Test
- void shouldProceedWhenLoanIsNotLocked() throws ServletException, IOException {
+ void shouldProceedWhenLoanIsNotLockedAndNoLoanIsBehind() throws ServletException, IOException {
MockHttpServletRequest request = mock(MockHttpServletRequest.class);
MockHttpServletResponse response = mock(MockHttpServletResponse.class);
FilterChain filterChain = mock(FilterChain.class);
AppUser appUser = mock(AppUser.class);
+ ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
+ HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>();
+ LocalDate businessDate = LocalDate.now(ZoneId.systemDefault());
+ businessDates.put(BusinessDateType.BUSINESS_DATE, businessDate);
+ businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1));
+ ThreadLocalContextUtil.setBusinessDates(businessDates);
given(request.getPathInfo()).willReturn("/loans/2/charges");
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(false);
given(context.authenticatedUser()).willReturn(appUser);
+ given(loanRepository.findAllNonClosedLoansBehindByLoanIds(
+ eq(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)), anyList()))
+ .willReturn(Collections.emptyList());
testObj.doFilterInternal(request, response, filterChain);
verify(filterChain, times(1)).doFilter(request, response);
}
@Test
- void shouldProceedWhenExternalLoanIsNotLocked() throws ServletException, IOException {
+ void shouldProceedWhenExternalLoanIsNotLockedAndNotBehind() throws ServletException, IOException {
MockHttpServletRequest request = mock(MockHttpServletRequest.class);
MockHttpServletResponse response = mock(MockHttpServletResponse.class);
FilterChain filterChain = mock(FilterChain.class);
AppUser appUser = mock(AppUser.class);
+ ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
+ HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>();
+ LocalDate businessDate = LocalDate.now(ZoneId.systemDefault());
+ businessDates.put(BusinessDateType.BUSINESS_DATE, businessDate);
+ businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1));
+ ThreadLocalContextUtil.setBusinessDates(businessDates);
given(request.getPathInfo()).willReturn("/loans/external-id/2/charges");
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(false);
given(context.authenticatedUser()).willReturn(appUser);
+ given(loanRepository.findAllNonClosedLoansBehindByLoanIds(
+ eq(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)), anyList()))
+ .willReturn(Collections.emptyList());
testObj.doFilterInternal(request, response, filterChain);
verify(filterChain, times(1)).doFilter(request, response);
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java
index 71cd3cc39..984cc6959 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java
@@ -230,7 +230,7 @@ public class InlineLoanCOBTest {
}
@Test
- public void testInlineCOBOnRepayment() {
+ public void testInlineCOBOnRepaymentWithSoftLockedLoan() {
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 2));
GlobalConfigurationHelper.updateValueForGlobalConfiguration(this.requestSpec, this.responseSpec, "10", "0");
@@ -280,6 +280,55 @@ public class InlineLoanCOBTest {
Assertions.assertEquals(LocalDate.of(2020, 3, 9), loan.getLastClosedBusinessDate());
}
+ @Test
+ public void testInlineCOBCatchUpOnRepaymentWithNotLockedLoan() {
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
+ BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 2));
+ GlobalConfigurationHelper.updateValueForGlobalConfiguration(this.requestSpec, this.responseSpec, "10", "0");
+ loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
+ loanAccountLockHelper = new LoanAccountLockHelper(requestSpec, new ResponseSpecBuilder().expectStatusCode(202).build());
+
+ final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec);
+ Assertions.assertNotNull(clientID);
+
+ Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, responseSpec,
+ ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("1"));
+ Assertions.assertNotNull(overdueFeeChargeId);
+
+ final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
+ Assertions.assertNotNull(loanProductID);
+ HashMap loanStatusHashMap;
+ final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2020");
+
+ Assertions.assertNotNull(loanID);
+
+ loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
+ LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+ loanStatusHashMap = loanTransactionHelper.approveLoan("01 March 2020", loanID);
+ LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+
+ String loanDetails = loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
+ loanStatusHashMap = loanTransactionHelper.disburseLoanWithNetDisbursalAmount("02 March 2020", loanID,
+ JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
+ LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+
+ BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.COB_DATE, LocalDate.of(2020, 3, 2));
+ inlineLoanCOBHelper.executeInlineCOB(List.of(loanID.longValue()));
+ GetLoansLoanIdResponse loan = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanID);
+ Assertions.assertEquals(LocalDate.of(2020, 3, 2), loan.getLastClosedBusinessDate());
+
+ BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 10));
+
+ createNewSimpleUserWithoutBypassPermission();
+ loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
+
+ loanTransactionHelper.makeRepayment("10 March 2020", 10.0f, loanID);
+
+ loan = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanID);
+ Assertions.assertEquals(LocalDate.of(2020, 3, 9), loan.getLastClosedBusinessDate());
+ }
+
@Test
public void testInlineCOBOnBatchAPI() {
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);