FINERACT-1724 - Reschedule Loan fix
- [x] Reschedule loan COB API filter fix - [x] Unit test for filter
This commit is contained in:
+13
-4
@@ -48,6 +48,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepositor
|
||||
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.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
|
||||
import org.apache.fineract.useradministration.exception.UnAuthenticatedUserException;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.springframework.http.HttpMethod;
|
||||
@@ -64,12 +65,14 @@ public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchFilte
|
||||
private final InlineLoanCOBExecutorServiceImpl inlineLoanCOBExecutorService;
|
||||
private final LoanRepository loanRepository;
|
||||
|
||||
private final LoanRescheduleRequestRepository loanRescheduleRequestRepository;
|
||||
|
||||
private static final List<HttpMethod> HTTP_METHODS = List.of(HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE);
|
||||
|
||||
public static final Pattern IGNORE_LOAN_PATH_PATTERN = Pattern.compile("\\/loans\\/catch-up");
|
||||
public static final Pattern LOAN_PATH_PATTERN = Pattern.compile("\\/?loans\\/(?:external-id\\/)?([^\\/\\?]+).*");
|
||||
public static final Pattern LOAN_PATH_PATTERN = Pattern.compile("\\/(?:reschedule)?loans\\/(?:external-id\\/)?([^\\/\\?]+).*");
|
||||
|
||||
public static final Pattern LOAN_GLIMACCOUNT_PATH_PATTERN = Pattern.compile("\\/?loans\\/glimAccount\\/(\\d+).*");
|
||||
public static final Pattern LOAN_GLIMACCOUNT_PATH_PATTERN = Pattern.compile("\\/loans\\/glimAccount\\/(\\d+).*");
|
||||
private static final Predicate<String> URL_FUNCTION = s -> LOAN_PATH_PATTERN.matcher(s).find()
|
||||
|| LOAN_GLIMACCOUNT_PATH_PATTERN.matcher(s).find();
|
||||
private static final String JOB_NAME = "INLINE_LOAN_COB";
|
||||
@@ -123,7 +126,7 @@ public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchFilte
|
||||
} else {
|
||||
try {
|
||||
List<Long> loanIds = calculateRelevantLoanIds(request.getPathInfo());
|
||||
if (isLoanSoftLocked(loanIds) || isLoanBehind(loanIds)) {
|
||||
if (!loanIds.isEmpty() && (isLoanSoftLocked(loanIds) || isLoanBehind(loanIds))) {
|
||||
executeInlineCob(loanIds);
|
||||
}
|
||||
proceed(filterChain, request, response);
|
||||
@@ -207,6 +210,8 @@ public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchFilte
|
||||
if (isExternal(pathInfo)) {
|
||||
String externalId = id;
|
||||
return loanRepository.findIdByExternalId(new ExternalId(externalId));
|
||||
} else if (isRescheduleLoans(pathInfo)) {
|
||||
return loanRescheduleRequestRepository.getLoanIdByRescheduleRequestId(Long.valueOf(id)).orElse(null);
|
||||
} else if (StringUtils.isNumeric(id)) {
|
||||
return Long.valueOf(id);
|
||||
} else {
|
||||
@@ -221,6 +226,10 @@ public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchFilte
|
||||
return LOAN_PATH_PATTERN.matcher(pathInfo).matches() && pathInfo.contains("external-id");
|
||||
}
|
||||
|
||||
private boolean isRescheduleLoans(String pathInfo) {
|
||||
return LOAN_PATH_PATTERN.matcher(pathInfo).matches() && pathInfo.contains("/rescheduleloans/");
|
||||
}
|
||||
|
||||
private boolean isOnApiList(String pathInfo, String method) {
|
||||
if (StringUtils.isBlank(pathInfo)) {
|
||||
return false;
|
||||
@@ -245,7 +254,7 @@ public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchFilte
|
||||
} else {
|
||||
try {
|
||||
List<Long> result = calculateRelevantLoanIds("/" + batchRequest.getRelativeUrl());
|
||||
if (isLoanSoftLocked(result) || isLoanBehind(result)) {
|
||||
if (!result.isEmpty() && (isLoanSoftLocked(result) || isLoanBehind(result))) {
|
||||
executeInlineCob(result);
|
||||
}
|
||||
return chain.serviceCall(batchRequest, uriInfo);
|
||||
|
||||
+4
@@ -18,10 +18,14 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface LoanRescheduleRequestRepository
|
||||
extends JpaRepository<LoanRescheduleRequest, Long>, JpaSpecificationExecutor<LoanRescheduleRequest> {
|
||||
|
||||
@Query("select lrr.loan.id from LoanRescheduleRequest lrr where lrr.id = :rescheduleRequestId")
|
||||
Optional<Long> getLoanIdByRescheduleRequestId(Long rescheduleRequestId);
|
||||
}
|
||||
|
||||
+41
@@ -34,6 +34,7 @@ import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -48,6 +49,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepositor
|
||||
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.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
@@ -78,16 +81,25 @@ class LoanCOBApiFilterTest {
|
||||
@Mock
|
||||
private LoanRepository loanRepository;
|
||||
|
||||
@Mock
|
||||
private LoanRescheduleRequestRepository loanRescheduleRequestRepository;
|
||||
|
||||
@Test
|
||||
void shouldLoanAndExternalMatchToo() {
|
||||
String externalId = UUID.randomUUID().toString();
|
||||
Assertions.assertTrue(LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/loans/12").matches());
|
||||
Assertions.assertTrue(LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/loans/12?correct=parameter").matches());
|
||||
Assertions.assertTrue(LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/loans/12?correct=parameter").matches());
|
||||
Assertions.assertTrue(LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/rescheduleloans/12").matches());
|
||||
Assertions.assertTrue(LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/rescheduleloans/12?correct=parameter").matches());
|
||||
Assertions.assertTrue(LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/rescheduleloans/12?correct=parameter").matches());
|
||||
Assertions.assertTrue(LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/loans/external-id/" + externalId).matches());
|
||||
Assertions.assertTrue(
|
||||
LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/loans/external-id/" + externalId + "?additional=parameter").matches());
|
||||
Assertions.assertEquals("12", LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/loans/12").replaceAll("$1"));
|
||||
Assertions.assertEquals("12", LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/loans/12?correct=parameter").replaceAll("$1"));
|
||||
Assertions.assertEquals("12", LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/rescheduleloans/12").replaceAll("$1"));
|
||||
Assertions.assertEquals("12", LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/rescheduleloans/12?correct=parameter").replaceAll("$1"));
|
||||
Assertions.assertEquals(externalId,
|
||||
LoanCOBApiFilter.LOAN_PATH_PATTERN.matcher("/loans/external-id/" + externalId).replaceAll("$1"));
|
||||
Assertions.assertEquals(externalId,
|
||||
@@ -210,6 +222,35 @@ class LoanCOBApiFilterTest {
|
||||
verify(filterChain, times(1)).doFilter(request, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldProceedWhenRescheduleLoanIsNotLockedAndNotBehind() 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);
|
||||
Long resourceId = 123L;
|
||||
given(request.getPathInfo()).willReturn("/rescheduleloans/" + resourceId + "/charges");
|
||||
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
|
||||
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
|
||||
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(false);
|
||||
LoanRescheduleRequest rescheduleRequest = mock(LoanRescheduleRequest.class);
|
||||
given(loanRescheduleRequestRepository.getLoanIdByRescheduleRequestId(resourceId)).willReturn(Optional.of(2L));
|
||||
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 shouldRunInlineCOBAndProceedWhenLoanIsSoftLocked() throws ServletException, IOException {
|
||||
MockHttpServletRequest request = mock(MockHttpServletRequest.class);
|
||||
|
||||
Reference in New Issue
Block a user