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/01/20 13:47:30 UTC

[fineract] branch develop updated: [FINERACT-1859] Avro schema for LoanAccountsStayedLockedBusinessEvent

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 ef153c2b6 [FINERACT-1859] Avro schema for LoanAccountsStayedLockedBusinessEvent
ef153c2b6 is described below

commit ef153c2b69b5427e2045a57fa8d01ffc83490eb5
Author: taskain7 <ta...@gmail.com>
AuthorDate: Wed Jan 18 12:49:47 2023 +0100

    [FINERACT-1859] Avro schema for LoanAccountsStayedLockedBusinessEvent
---
 .../loan/v1/LoanAccountStayedLockedDataV1.avsc     | 27 +++++++++++
 .../loan/v1/LoanAccountsStayedLockedDataV1.avsc    | 12 +++++
 .../LoanAccountStayedLockedData.java}              | 35 ++++----------
 .../LoanAccountsStayedLockedData.java}             | 31 +++----------
 .../LoanIdAndExternalIdAndAccountNo.java}          | 29 +++---------
 .../fineract/cob/domain/LoanAccountLock.java       |  8 ++++
 .../LoanAccountsStayedLockedBusinessEvent.java     |  6 +--
 .../cob/loan/LoanCOBManagerConfiguration.java      |  5 +-
 .../cob/loan/StayedLockedLoansTasklet.java         | 29 +++++++++---
 .../loan/LoanAccountsStayedLockedDataMapper.java}  | 33 ++++---------
 ...ccountsStayedLockedBusinessEventSerializer.java | 54 ++++++++++++++++++++++
 .../loanaccount/domain/LoanRepository.java         |  6 +++
 .../db/changelog/tenant/changelog-tenant.xml       |  1 +
 ...add_cob_business_date_to_loan_account_locks.xml | 31 +++++++++++++
 14 files changed, 199 insertions(+), 108 deletions(-)

diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountStayedLockedDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountStayedLockedDataV1.avsc
new file mode 100644
index 000000000..172fceae3
--- /dev/null
+++ b/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountStayedLockedDataV1.avsc
@@ -0,0 +1,27 @@
+{
+    "name": "LoanAccountStayedLockedDataV1",
+    "namespace": "org.apache.fineract.avro.loan.v1",
+    "type": "record",
+    "fields": [
+        {
+            "name": "id",
+            "type": "long"
+        },
+        {
+            "default": null,
+            "name": "externalId",
+            "type": [
+                "null",
+                "string"
+            ]
+        },
+        {
+            "default": null,
+            "name": "accountNo",
+            "type": [
+                "null",
+                "string"
+            ]
+        }
+    ]
+}
diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountsStayedLockedDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountsStayedLockedDataV1.avsc
new file mode 100644
index 000000000..2f9db112f
--- /dev/null
+++ b/fineract-avro-schemas/src/main/avro/loan/v1/LoanAccountsStayedLockedDataV1.avsc
@@ -0,0 +1,12 @@
+{
+    "name": "LoanAccountsStayedLockedDataV1",
+    "namespace": "org.apache.fineract.avro.loan.v1",
+    "type": "record",
+    "fields": [{
+        "name": "loanAccounts",
+        "type": {
+            "type": "array",
+            "items": "org.apache.fineract.avro.loan.v1.LoanAccountStayedLockedDataV1"
+        }
+    }]
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanAccountStayedLockedData.java
similarity index 53%
copy from fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
copy to fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanAccountStayedLockedData.java
index d9280ae56..c37ac5647 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanAccountStayedLockedData.java
@@ -16,32 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.cob.loan;
+package org.apache.fineract.cob.data;
 
-import java.util.List;
-import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
 
-public class LoanAccountsStayedLockedBusinessEvent extends AbstractBusinessEvent<List<Long>> {
+@Getter
+@AllArgsConstructor
+public class LoanAccountStayedLockedData {
 
-    private static final String CATEGORY = "Loan COB";
-    private static final String TYPE = "LoanAccountsStayedLockedBusinessEvent";
-
-    public LoanAccountsStayedLockedBusinessEvent(List<Long> value) {
-        super(value);
-    }
-
-    @Override
-    public String getType() {
-        return TYPE;
-    }
-
-    @Override
-    public String getCategory() {
-        return CATEGORY;
-    }
-
-    @Override
-    public Long getAggregateRootId() {
-        return null;
-    }
+    private Long id;
+    private ExternalId externalId;
+    private String accountNo;
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanAccountsStayedLockedData.java
similarity index 54%
copy from fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
copy to fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanAccountsStayedLockedData.java
index d9280ae56..9b171663c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanAccountsStayedLockedData.java
@@ -16,32 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.cob.loan;
+package org.apache.fineract.cob.data;
 
 import java.util.List;
-import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
 
-public class LoanAccountsStayedLockedBusinessEvent extends AbstractBusinessEvent<List<Long>> {
+@Getter
+@AllArgsConstructor
+public class LoanAccountsStayedLockedData {
 
-    private static final String CATEGORY = "Loan COB";
-    private static final String TYPE = "LoanAccountsStayedLockedBusinessEvent";
-
-    public LoanAccountsStayedLockedBusinessEvent(List<Long> value) {
-        super(value);
-    }
-
-    @Override
-    public String getType() {
-        return TYPE;
-    }
-
-    @Override
-    public String getCategory() {
-        return CATEGORY;
-    }
-
-    @Override
-    public Long getAggregateRootId() {
-        return null;
-    }
+    private List<LoanAccountStayedLockedData> loanAccounts;
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanIdAndExternalIdAndAccountNo.java
similarity index 53%
copy from fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
copy to fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanIdAndExternalIdAndAccountNo.java
index d9280ae56..b7a94b13f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanIdAndExternalIdAndAccountNo.java
@@ -16,32 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.cob.loan;
+package org.apache.fineract.cob.data;
 
-import java.util.List;
-import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
 
-public class LoanAccountsStayedLockedBusinessEvent extends AbstractBusinessEvent<List<Long>> {
+public interface LoanIdAndExternalIdAndAccountNo {
 
-    private static final String CATEGORY = "Loan COB";
-    private static final String TYPE = "LoanAccountsStayedLockedBusinessEvent";
+    Long getId();
 
-    public LoanAccountsStayedLockedBusinessEvent(List<Long> value) {
-        super(value);
-    }
+    ExternalId getExternalId();
 
-    @Override
-    public String getType() {
-        return TYPE;
-    }
-
-    @Override
-    public String getCategory() {
-        return CATEGORY;
-    }
-
-    @Override
-    public Long getAggregateRootId() {
-        return null;
-    }
+    String getAccountNo();
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/domain/LoanAccountLock.java b/fineract-provider/src/main/java/org/apache/fineract/cob/domain/LoanAccountLock.java
index e490bde89..7d6266b3d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/domain/LoanAccountLock.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/domain/LoanAccountLock.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.cob.domain;
 
+import java.time.LocalDate;
 import java.time.OffsetDateTime;
 import javax.persistence.Column;
 import javax.persistence.Entity;
@@ -28,7 +29,9 @@ import javax.persistence.Table;
 import javax.persistence.Version;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
 
 @Entity
 @Table(name = "m_loan_account_locks")
@@ -57,10 +60,14 @@ public class LoanAccountLock {
     @Column(name = "stacktrace")
     private String stacktrace;
 
+    @Column(name = "lock_placed_on_cob_business_date")
+    private LocalDate lockPlacedOnCobBusinessDate;
+
     public LoanAccountLock(Long loanId, LockOwner lockOwner) {
         this.loanId = loanId;
         this.lockOwner = lockOwner;
         this.lockPlacedOn = DateUtils.getOffsetDateTimeOfTenant();
+        this.lockPlacedOnCobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
     }
 
     public void setError(String errorMessage, String stacktrace) {
@@ -71,5 +78,6 @@ public class LoanAccountLock {
     public void setNewLockOwner(LockOwner newLockOwner) {
         this.lockOwner = newLockOwner;
         this.lockPlacedOn = DateUtils.getOffsetDateTimeOfTenant();
+        this.lockPlacedOnCobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
     }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
index d9280ae56..d14038c6b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
@@ -18,15 +18,15 @@
  */
 package org.apache.fineract.cob.loan;
 
-import java.util.List;
+import org.apache.fineract.cob.data.LoanAccountsStayedLockedData;
 import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent;
 
-public class LoanAccountsStayedLockedBusinessEvent extends AbstractBusinessEvent<List<Long>> {
+public class LoanAccountsStayedLockedBusinessEvent extends AbstractBusinessEvent<LoanAccountsStayedLockedData> {
 
     private static final String CATEGORY = "Loan COB";
     private static final String TYPE = "LoanAccountsStayedLockedBusinessEvent";
 
-    public LoanAccountsStayedLockedBusinessEvent(List<Long> value) {
+    public LoanAccountsStayedLockedBusinessEvent(LoanAccountsStayedLockedData value) {
         super(value);
     }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
index 1990bbdd5..4fa8ca2e3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
@@ -26,6 +26,7 @@ import org.apache.fineract.cob.listener.COBExecutionListenerRunner;
 import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
 import org.apache.fineract.infrastructure.jobs.service.JobName;
 import org.apache.fineract.infrastructure.springbatch.PropertyService;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
 import org.springframework.batch.core.Job;
 import org.springframework.batch.core.Step;
 import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
@@ -76,6 +77,8 @@ public class LoanCOBManagerConfiguration {
     private BusinessEventNotifierService businessEventNotifierService;
     @Autowired
     private CustomJobParameterResolver customJobParameterResolver;
+    @Autowired
+    private LoanRepository loanRepository;
 
     @Bean
     @JobScope
@@ -120,7 +123,7 @@ public class LoanCOBManagerConfiguration {
     @Bean
     @JobScope
     public StayedLockedLoansTasklet stayedLockedTasklet() {
-        return new StayedLockedLoansTasklet(accountLockRepository, businessEventNotifierService);
+        return new StayedLockedLoansTasklet(businessEventNotifierService, loanRepository);
     }
 
     @Bean(name = "loanCOBJob")
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/StayedLockedLoansTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/StayedLockedLoansTasklet.java
index f3ea0a6b9..f34d80739 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/StayedLockedLoansTasklet.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/StayedLockedLoansTasklet.java
@@ -18,12 +18,18 @@
  */
 package org.apache.fineract.cob.loan;
 
+import java.time.LocalDate;
+import java.util.ArrayList;
 import java.util.List;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.fineract.cob.domain.LoanAccountLock;
-import org.apache.fineract.cob.domain.LoanAccountLockRepository;
+import org.apache.fineract.cob.data.LoanAccountStayedLockedData;
+import org.apache.fineract.cob.data.LoanAccountsStayedLockedData;
+import org.apache.fineract.cob.data.LoanIdAndExternalIdAndAccountNo;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
 import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
 import org.springframework.batch.core.StepContribution;
 import org.springframework.batch.core.scope.context.ChunkContext;
 import org.springframework.batch.core.step.tasklet.Tasklet;
@@ -33,16 +39,25 @@ import org.springframework.batch.repeat.RepeatStatus;
 @RequiredArgsConstructor
 public class StayedLockedLoansTasklet implements Tasklet {
 
-    private final LoanAccountLockRepository loanAccountLockRepository;
     private final BusinessEventNotifierService businessEventNotifierService;
+    private final LoanRepository loanRepository;
 
     @Override
     public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
-        List<LoanAccountLock> loanAccountLocks = loanAccountLockRepository.findAll();
-        if (!loanAccountLocks.isEmpty()) {
-            List<Long> loanIds = loanAccountLocks.stream().map(LoanAccountLock::getLoanId).toList();
-            businessEventNotifierService.notifyPostBusinessEvent(new LoanAccountsStayedLockedBusinessEvent(loanIds));
+        LoanAccountsStayedLockedData lockedLoanAccounts = buildLoanAccountData();
+        if (!lockedLoanAccounts.getLoanAccounts().isEmpty()) {
+            businessEventNotifierService.notifyPostBusinessEvent(new LoanAccountsStayedLockedBusinessEvent(lockedLoanAccounts));
         }
         return RepeatStatus.FINISHED;
     }
+
+    private LoanAccountsStayedLockedData buildLoanAccountData() {
+        LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+        List<LoanIdAndExternalIdAndAccountNo> stayedLockedLoanAccounts = loanRepository.findAllStayedLockedByLoanIds(cobBusinessDate);
+        List<LoanAccountStayedLockedData> loanAccounts = new ArrayList<>();
+        stayedLockedLoanAccounts.forEach(loanAccount -> {
+            loanAccounts.add(new LoanAccountStayedLockedData(loanAccount.getId(), loanAccount.getExternalId(), loanAccount.getAccountNo()));
+        });
+        return new LoanAccountsStayedLockedData(loanAccounts);
+    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountsStayedLockedDataMapper.java
similarity index 53%
copy from fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
copy to fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountsStayedLockedDataMapper.java
index d9280ae56..d030632f9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanAccountsStayedLockedBusinessEvent.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountsStayedLockedDataMapper.java
@@ -16,32 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.cob.loan;
+package org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan;
 
-import java.util.List;
-import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent;
+import org.apache.fineract.avro.loan.v1.LoanAccountsStayedLockedDataV1;
+import org.apache.fineract.cob.data.LoanAccountsStayedLockedData;
+import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroMapperConfig;
+import org.mapstruct.Mapper;
 
-public class LoanAccountsStayedLockedBusinessEvent extends AbstractBusinessEvent<List<Long>> {
+@Mapper(config = AvroMapperConfig.class)
+public interface LoanAccountsStayedLockedDataMapper {
 
-    private static final String CATEGORY = "Loan COB";
-    private static final String TYPE = "LoanAccountsStayedLockedBusinessEvent";
-
-    public LoanAccountsStayedLockedBusinessEvent(List<Long> value) {
-        super(value);
-    }
-
-    @Override
-    public String getType() {
-        return TYPE;
-    }
-
-    @Override
-    public String getCategory() {
-        return CATEGORY;
-    }
-
-    @Override
-    public Long getAggregateRootId() {
-        return null;
-    }
+    LoanAccountsStayedLockedDataV1 map(LoanAccountsStayedLockedData loanAccountStayedLockedData);
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountsStayedLockedBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountsStayedLockedBusinessEventSerializer.java
new file mode 100644
index 000000000..8ff06cbd5
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountsStayedLockedBusinessEventSerializer.java
@@ -0,0 +1,54 @@
+/**
+ * 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.event.external.service.serialization.serializer.loan;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.avro.generic.GenericContainer;
+import org.apache.fineract.avro.generator.ByteBufferSerializable;
+import org.apache.fineract.avro.loan.v1.LoanAccountsStayedLockedDataV1;
+import org.apache.fineract.cob.data.LoanAccountsStayedLockedData;
+import org.apache.fineract.cob.loan.LoanAccountsStayedLockedBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
+import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanAccountsStayedLockedDataMapper;
+import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.AbstractBusinessEventSerializer;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class LoanAccountsStayedLockedBusinessEventSerializer extends AbstractBusinessEventSerializer {
+
+    private final LoanAccountsStayedLockedDataMapper mapper;
+
+    @Override
+    public <T> boolean canSerialize(BusinessEvent<T> event) {
+        return event instanceof LoanAccountsStayedLockedBusinessEvent;
+    }
+
+    @Override
+    protected <T> ByteBufferSerializable toAvroDTO(BusinessEvent<T> rawEvent) {
+        LoanAccountsStayedLockedBusinessEvent event = (LoanAccountsStayedLockedBusinessEvent) rawEvent;
+        LoanAccountsStayedLockedData loanAccounts = event.get();
+        return mapper.map(loanAccounts);
+    }
+
+    @Override
+    public Class<? extends GenericContainer> getSupportedSchema() {
+        return LoanAccountsStayedLockedDataV1.class;
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
index 605377861..4d20391d3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain;
 import java.time.LocalDate;
 import java.util.Collection;
 import java.util.List;
+import org.apache.fineract.cob.data.LoanIdAndExternalIdAndAccountNo;
 import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
 import org.apache.fineract.infrastructure.core.domain.ExternalId;
 import org.springframework.data.jpa.repository.JpaRepository;
@@ -88,6 +89,8 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
     String FIND_ALL_NON_CLOSED_LOANS_BEHIND_BY_LOAN_IDS = "select loan.id, loan.lastClosedBusinessDate from Loan loan where loan.id IN :loanIds and loan.loanStatus in (100,200,300,303,304) and (loan.lastClosedBusinessDate <> :cobBusinessDate or "
             + "loan.lastClosedBusinessDate is null)";
 
+    String FIND_ALL_STAYED_LOCKED_BY_LOAN_IDS = "select loan.id, loan.externalId, loan.accountNumber from LoanAccountLock lock left join Loan loan on lock.loanId = loan.id where lock.lockPlacedOnCobBusinessDate = :cobBusinessDate";
+
     @Query(FIND_GROUP_LOANS_DISBURSED_AFTER)
     List<Loan> getGroupLoansDisbursedAfter(@Param("disbursementDate") LocalDate disbursementDate, @Param("groupId") Long groupId,
             @Param("loanType") Integer loanType);
@@ -194,4 +197,7 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
     @Query(FIND_OLDEST_COB_PROCESSED_LOAN)
     List<LoanIdAndLastClosedBusinessDate> findOldestCOBProcessedLoan(@Param("cobBusinessDate") LocalDate cobBusinessDate);
 
+    @Query(FIND_ALL_STAYED_LOCKED_BY_LOAN_IDS)
+    List<LoanIdAndExternalIdAndAccountNo> findAllStayedLockedByLoanIds(@Param("cobBusinessDate") LocalDate cobBusinessDate);
+
 }
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index d81bba3f1..9c6ed1e14 100644
--- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -105,4 +105,5 @@
     <include file="parts/0083_add_loan_transaction_enum_values.xml" relativeToChangelogFile="true" />
     <include file="parts/0084_add_general_accounting_table_reports.xml" relativeToChangelogFile="true" />
     <include file="parts/0085_add_aggregate_root_id_external_events.xml" relativeToChangelogFile="true" />
+    <include file="parts/0086_add_cob_business_date_to_loan_account_locks.xml" relativeToChangelogFile="true" />
 </databaseChangeLog>
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0086_add_cob_business_date_to_loan_account_locks.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0086_add_cob_business_date_to_loan_account_locks.xml
new file mode 100644
index 000000000..409fc273a
--- /dev/null
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0086_add_cob_business_date_to_loan_account_locks.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                   xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
+    <changeSet author="fineract" id="1">
+        <addColumn tableName="m_loan_account_locks">
+            <column name="lock_placed_on_cob_business_date" type="DATE">
+            </column>
+        </addColumn>
+    </changeSet>
+</databaseChangeLog>