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 7be193dd0 [FINERACT-1678] Reject write API calls for hard-locked loan 
accounts
7be193dd0 is described below

commit 7be193dd0b95f7f5b51a23908e08e843f22881a3
Author: taskain7 <[email protected]>
AuthorDate: Mon Oct 17 12:12:48 2022 +0200

    [FINERACT-1678] Reject write API calls for hard-locked loan accounts
---
 .../cob/service/LoanAccountLockService.java        |   2 +
 .../cob/service/LoanAccountLockServiceImpl.java    |  12 ++
 .../infrastructure/core/config/SecurityConfig.java |   4 +
 .../core/data/ApiGlobalErrorResponse.java          |  10 ++
 .../jobs/filter/LoanCOBApiFilter.java              | 133 ++++++++++++++++++++
 .../LoanWritePlatformServiceJpaRepositoryImpl.java |  29 +++--
 .../jobs/filter/LoanCOBApiFilterTest.java          | 135 +++++++++++++++++++++
 7 files changed, 317 insertions(+), 8 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanAccountLockService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanAccountLockService.java
index e1daca429..7f584d6ba 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanAccountLockService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanAccountLockService.java
@@ -24,4 +24,6 @@ import org.apache.fineract.cob.domain.LoanAccountLock;
 public interface LoanAccountLockService {
 
     List<LoanAccountLock> getLockedLoanAccountByPage(int page, int limit);
+
+    boolean isLoanHardLocked(Long loanId);
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanAccountLockServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanAccountLockServiceImpl.java
index 63a2cd606..4eeb31570 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanAccountLockServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanAccountLockServiceImpl.java
@@ -19,9 +19,12 @@
 package org.apache.fineract.cob.service;
 
 import java.util.List;
+import java.util.Optional;
 import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.cob.domain.LoanAccountLock;
 import org.apache.fineract.cob.domain.LoanAccountLockRepository;
+import org.apache.fineract.cob.domain.LockOwner;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
@@ -39,4 +42,13 @@ public class LoanAccountLockServiceImpl implements 
LoanAccountLockService {
         Page<LoanAccountLock> loanAccountLocks = 
loanAccountLockRepository.findAll(loanAccountLockPage);
         return loanAccountLocks.getContent();
     }
+
+    @Override
+    public boolean isLoanHardLocked(Long loanId) {
+        Optional<LoanAccountLock> loanAccountLockOptional = 
loanAccountLockRepository.findById(loanId);
+        return loanAccountLockOptional //
+                .filter(loanAccountLock -> 
LockOwner.LOAN_COB_CHUNK_PROCESSING.equals(loanAccountLock.getLockOwner()) //
+                        || 
LockOwner.LOAN_INLINE_COB_PROCESSING.equals(loanAccountLock.getLockOwner())) //
+                .filter(loanAccountLock -> 
StringUtils.isBlank(loanAccountLock.getError())).isPresent();
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
index eb3005199..3901e092f 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
@@ -20,6 +20,7 @@
 package org.apache.fineract.infrastructure.core.config;
 
 import 
org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter;
+import org.apache.fineract.infrastructure.jobs.filter.LoanCOBApiFilter;
 import 
org.apache.fineract.infrastructure.security.filter.TenantAwareBasicAuthenticationFilter;
 import 
org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
 import 
org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService;
@@ -56,6 +57,8 @@ public class SecurityConfig extends 
WebSecurityConfigurerAdapter {
 
     @Autowired
     private FineractInstanceModeApiFilter fineractInstanceModeApiFilter;
+    @Autowired
+    private LoanCOBApiFilter loanCOBApiFilter;
 
     @Autowired
     private FineractProperties fineractProperties;
@@ -86,6 +89,7 @@ public class SecurityConfig extends 
WebSecurityConfigurerAdapter {
                 .and() //
                 .addFilterAfter(fineractInstanceModeApiFilter, 
SecurityContextPersistenceFilter.class) //
                 .addFilterAfter(tenantAwareBasicAuthenticationFilter(), 
FineractInstanceModeApiFilter.class) //
+                .addFilterAfter(loanCOBApiFilter, 
TenantAwareBasicAuthenticationFilter.class) //
                 .addFilterAfter(twoFactorAuthenticationFilter, 
BasicAuthenticationFilter.class); //
 
         if (serverProperties.getSsl().isEnabled()) {
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java
index 753fe555b..8bf5e4664 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java
@@ -89,6 +89,16 @@ public class ApiGlobalErrorResponse {
         return globalErrorResponse;
     }
 
+    public static ApiGlobalErrorResponse loanIsLocked(final Long loanId) {
+        final ApiGlobalErrorResponse globalErrorResponse = new 
ApiGlobalErrorResponse();
+        globalErrorResponse.setHttpStatusCode(Status.CONFLICT.toString());
+        globalErrorResponse.setDeveloperMessage("Loan is locked by the COB 
job. Loan ID: " + loanId);
+        
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.loan.locked");
+        globalErrorResponse.setDefaultUserMessage("Loan is locked by the COB 
job. Loan ID: \" + loanId");
+
+        return globalErrorResponse;
+    }
+
     public static ApiGlobalErrorResponse unAuthorized(final String 
defaultUserMessage) {
         final ApiGlobalErrorResponse globalErrorResponse = new 
ApiGlobalErrorResponse();
         globalErrorResponse.setHttpStatusCode("403");
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
new file mode 100644
index 000000000..099161fd0
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java
@@ -0,0 +1,133 @@
+/**
+ * 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.infrastructure.jobs.filter;
+
+import com.google.common.base.Splitter;
+import com.sun.research.ws.wadl.HTTPMethods;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.fineract.cob.service.LoanAccountLockService;
+import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
+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.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+@Component
+@RequiredArgsConstructor
+public class LoanCOBApiFilter extends OncePerRequestFilter {
+
+    private final GLIMAccountInfoRepository glimAccountInfoRepository;
+    private final LoanAccountLockService loanAccountLockService;
+
+    private static final List<HTTPMethods> HTTP_METHODS = 
List.of(HTTPMethods.POST, HTTPMethods.PUT, HTTPMethods.DELETE);
+    private static final Function<String, Boolean> URL_FUNCTION = s -> 
s.matches("/loans/\\d+.*") || s.matches("/loans/glimAccount/\\d+.*");
+    private static final Integer LOAN_ID_INDEX_IN_URL = 2;
+    private static final Integer GLIM_ID_INDEX_IN_URL = 3;
+    private static final Integer GLIM_STRING_INDEX_IN_URL = 2;
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, 
HttpServletResponse response, FilterChain filterChain)
+            throws ServletException, IOException {
+        if (!isOnApiList(request)) {
+            proceed(filterChain, request, response);
+        } else {
+            Iterable<String> split = 
Splitter.on('/').split(request.getPathInfo());
+            Supplier<Stream<String>> streamSupplier = () -> 
StreamSupport.stream(split.spliterator(), false);
+            boolean isGlim = isGlim(streamSupplier);
+            Long loanId = getLoanId(isGlim, streamSupplier);
+            if (isLoanLocked(loanId, isGlim)) {
+                reject(loanId, response);
+            } else {
+                proceed(filterChain, request, response);
+            }
+        }
+    }
+
+    private boolean isLoanLocked(Long loanId, boolean isGlim) {
+        if (!isGlim) {
+            return loanAccountLockService.isLoanHardLocked(loanId);
+        } else {
+            GroupLoanIndividualMonitoringAccount glimAccount = 
glimAccountInfoRepository.findOneByIsAcceptingChildAndApplicationId(true,
+                    BigDecimal.valueOf(loanId));
+            if (glimAccount != null) {
+                Set<Loan> loans = glimAccount.getChildLoan();
+                List<Long> loanIds = loans.stream().map(Loan::getId).toList();
+                return 
loanIds.stream().anyMatch(loanAccountLockService::isLoanHardLocked);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    private void proceed(FilterChain filterChain, HttpServletRequest request, 
HttpServletResponse response)
+            throws IOException, ServletException {
+        filterChain.doFilter(request, response);
+    }
+
+    private void reject(Long loanId, HttpServletResponse response) throws 
IOException {
+        response.setStatus(HttpStatus.SC_CONFLICT);
+        ApiGlobalErrorResponse errorResponse = 
ApiGlobalErrorResponse.loanIsLocked(loanId);
+        response.getWriter().write(errorResponse.toJson());
+    }
+
+    private Long getLoanId(boolean isGlim, Supplier<Stream<String>> 
streamSupplier) {
+        if (!isGlim) {
+            if (streamSupplier.get().count() >= LOAN_ID_INDEX_IN_URL + 1) {
+                return 
Long.valueOf(streamSupplier.get().skip(LOAN_ID_INDEX_IN_URL).findFirst().get());
+            } else {
+                return null;
+            }
+        } else {
+            if (streamSupplier.get().count() >= GLIM_ID_INDEX_IN_URL + 1) {
+                return 
Long.valueOf(streamSupplier.get().skip(GLIM_ID_INDEX_IN_URL).findFirst().get());
+            } else {
+                return null;
+            }
+        }
+    }
+
+    private boolean isOnApiList(HttpServletRequest request) {
+        if (StringUtils.isBlank(request.getPathInfo())) {
+            return false;
+        }
+        return 
HTTP_METHODS.contains(HTTPMethods.fromValue(request.getMethod())) && 
URL_FUNCTION.apply(request.getPathInfo());
+    }
+
+    private boolean isGlim(Supplier<Stream<String>> streamSupplier) {
+        if (streamSupplier.get().count() >= GLIM_STRING_INDEX_IN_URL + 1) {
+            return 
"glimAccount".equals(streamSupplier.get().skip(GLIM_STRING_INDEX_IN_URL).findFirst().get());
+        }
+        return false;
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 349546f1c..1db95735b 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -39,6 +39,9 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import 
org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
+import org.apache.fineract.cob.domain.LoanAccountLockRepository;
+import 
org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException;
+import org.apache.fineract.cob.service.LoanAccountLockService;
 import org.apache.fineract.infrastructure.codes.domain.CodeValue;
 import 
org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
 import 
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
@@ -278,6 +281,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
     private final PostDatedChecksRepository postDatedChecksRepository;
     private final LoanDisbursementDetailsRepository 
loanDisbursementDetailsRepository;
     private final LoanRepaymentScheduleInstallmentRepository 
loanRepaymentScheduleInstallmentRepository;
+    private final LoanAccountLockRepository loanAccountLockRepository;
+    private final LoanAccountLockService loanAccountLockService;
 
     private static boolean isPartOfThisInstallment(LoanCharge loanCharge, 
LoanRepaymentScheduleInstallment e) {
         return e.getFromDate().isBefore(loanCharge.getDueDate()) && 
!loanCharge.getDueDate().isAfter(e.getDueDate());
@@ -2551,20 +2556,28 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
         final Staff fromLoanOfficer = 
this.loanAssembler.findLoanOfficerByIdIfProvided(fromLoanOfficerId);
         final Staff toLoanOfficer = 
this.loanAssembler.findLoanOfficerByIdIfProvided(toLoanOfficerId);
+        List<Long> lockedLoanIds = new ArrayList<>();
 
         for (final String loanIdString : loanIds) {
             final Long loanId = Long.valueOf(loanIdString);
             final Loan loan = this.loanAssembler.assembleFrom(loanId);
-            businessEventNotifierService.notifyPreBusinessEvent(new 
LoanReassignOfficerBusinessEvent(loan));
-            checkClientOrGroupActive(loan);
+            if (loanAccountLockService.isLoanHardLocked(loanId)) {
+                lockedLoanIds.add(loanId);
+            } else {
+                businessEventNotifierService.notifyPreBusinessEvent(new 
LoanReassignOfficerBusinessEvent(loan));
+                checkClientOrGroupActive(loan);
 
-            if (!loan.hasLoanOfficer(fromLoanOfficer)) {
-                throw new LoanOfficerAssignmentException(loanId, 
fromLoanOfficerId);
-            }
+                if (!loan.hasLoanOfficer(fromLoanOfficer)) {
+                    throw new LoanOfficerAssignmentException(loanId, 
fromLoanOfficerId);
+                }
 
-            loan.reassignLoanOfficer(toLoanOfficer, 
dateOfLoanOfficerAssignment);
-            saveLoanWithDataIntegrityViolationChecks(loan);
-            businessEventNotifierService.notifyPostBusinessEvent(new 
LoanReassignOfficerBusinessEvent(loan));
+                loan.reassignLoanOfficer(toLoanOfficer, 
dateOfLoanOfficerAssignment);
+                saveLoanWithDataIntegrityViolationChecks(loan);
+                businessEventNotifierService.notifyPostBusinessEvent(new 
LoanReassignOfficerBusinessEvent(loan));
+            }
+        }
+        if (!lockedLoanIds.isEmpty()) {
+            throw new LoanAccountLockCannotBeOverruledException("There are 
hard-lcoked loan accounts: " + lockedLoanIds);
         }
         this.loanRepositoryWrapper.flush();
 
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
new file mode 100644
index 000000000..de7bf1ce1
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.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.infrastructure.jobs.filter;
+
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.sun.research.ws.wadl.HTTPMethods;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.math.BigDecimal;
+import java.util.Collections;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import org.apache.fineract.cob.service.LoanAccountLockService;
+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.http.HttpStatus;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+class LoanCOBApiFilterTest {
+
+    @InjectMocks
+    private LoanCOBApiFilter testObj;
+    @Mock
+    private LoanAccountLockService loanAccountLockService;
+    @Mock
+    private GLIMAccountInfoRepository glimAccountInfoRepository;
+
+    @Test
+    void shouldProceedWhenUrlDoesNotMatch() throws ServletException, 
IOException {
+        MockHttpServletRequest request = mock(MockHttpServletRequest.class);
+        given(request.getPathInfo()).willReturn("/jobs/2/inline");
+        given(request.getMethod()).willReturn(HTTPMethods.POST.value());
+        MockHttpServletResponse response = mock(MockHttpServletResponse.class);
+        FilterChain filterChain = mock(FilterChain.class);
+        testObj.doFilterInternal(request, response, filterChain);
+        verify(filterChain, times(1)).doFilter(request, response);
+    }
+
+    @Test
+    void shouldProceedWhenLoanIsNotLocked() throws ServletException, 
IOException {
+        MockHttpServletRequest request = mock(MockHttpServletRequest.class);
+        MockHttpServletResponse response = mock(MockHttpServletResponse.class);
+        FilterChain filterChain = mock(FilterChain.class);
+
+        given(request.getPathInfo()).willReturn("/loans/2/charges");
+        given(request.getMethod()).willReturn(HTTPMethods.POST.value());
+        given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
+
+        testObj.doFilterInternal(request, response, filterChain);
+        verify(filterChain, times(1)).doFilter(request, response);
+    }
+
+    @Test
+    void shouldProceedWhenLoanIsSoftLocked() throws ServletException, 
IOException {
+        MockHttpServletRequest request = mock(MockHttpServletRequest.class);
+        MockHttpServletResponse response = mock(MockHttpServletResponse.class);
+        FilterChain filterChain = mock(FilterChain.class);
+
+        given(request.getPathInfo()).willReturn("/loans/2/charges");
+        given(request.getMethod()).willReturn(HTTPMethods.POST.value());
+        given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
+
+        testObj.doFilterInternal(request, response, filterChain);
+        verify(filterChain, times(1)).doFilter(request, response);
+    }
+
+    @Test
+    void shouldRejectWhenLoanIsHardLocked() throws ServletException, 
IOException {
+        MockHttpServletRequest request = mock(MockHttpServletRequest.class);
+        MockHttpServletResponse response = mock(MockHttpServletResponse.class);
+        FilterChain filterChain = mock(FilterChain.class);
+        PrintWriter writer = mock(PrintWriter.class);
+
+        given(request.getPathInfo()).willReturn("/loans/2/charges");
+        given(request.getMethod()).willReturn(HTTPMethods.POST.value());
+        given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(true);
+        given(response.getWriter()).willReturn(writer);
+
+        testObj.doFilterInternal(request, response, filterChain);
+        verify(response, times(1)).setStatus(HttpStatus.SC_CONFLICT);
+    }
+
+    @Test
+    void shouldRejectWhenGlimLoanIsHardLocked() throws ServletException, 
IOException {
+        MockHttpServletRequest request = mock(MockHttpServletRequest.class);
+        MockHttpServletResponse response = mock(MockHttpServletResponse.class);
+        FilterChain filterChain = mock(FilterChain.class);
+        PrintWriter writer = mock(PrintWriter.class);
+        GroupLoanIndividualMonitoringAccount glimAccount = 
mock(GroupLoanIndividualMonitoringAccount.class);
+        Loan loan = mock(Loan.class);
+        Long loanId = 2L;
+
+        given(request.getPathInfo()).willReturn("/loans/glimAccount/2");
+        given(request.getMethod()).willReturn(HTTPMethods.POST.value());
+        
given(glimAccountInfoRepository.findOneByIsAcceptingChildAndApplicationId(true, 
BigDecimal.valueOf(2))).willReturn(glimAccount);
+        
given(glimAccount.getChildLoan()).willReturn(Collections.singleton(loan));
+        given(loan.getId()).willReturn(loanId);
+        
given(loanAccountLockService.isLoanHardLocked(loanId)).willReturn(true);
+        given(response.getWriter()).willReturn(writer);
+
+        testObj.doFilterInternal(request, response, filterChain);
+        verify(response, times(1)).setStatus(HttpStatus.SC_CONFLICT);
+    }
+}

Reply via email to