You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ta...@apache.org on 2023/02/17 13:58:46 UTC

[fineract] branch develop updated: FINERACT-1724: Added Add periodic accrual as a Loan COB business step

This is an automated email from the ASF dual-hosted git repository.

taskain 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 f927dd4ff FINERACT-1724: Added Add periodic accrual as a Loan COB business step
f927dd4ff is described below

commit f927dd4ff93f1a84c72bf47f3ec943158fa0805c
Author: Arnold Galovics <ga...@gmail.com>
AuthorDate: Wed Feb 15 16:41:27 2023 +0100

    FINERACT-1724: Added Add periodic accrual as a Loan COB business step
---
 .../AddPeriodicAccrualEntriesBusinessStep.java     |  54 +++++++++++
 .../service/LoanAccrualPlatformService.java        |   3 +
 .../service/LoanAccrualPlatformServiceImpl.java    |   8 ++
 .../service/LoanReadPlatformService.java           |   2 +
 .../service/LoanReadPlatformServiceImpl.java       |  10 +-
 .../db/changelog/tenant/changelog-tenant.xml       |   1 +
 ..._add_periodic_accrual_entries_business_step.xml |  32 ++++++
 .../AddPeriodicAccrualEntriesBusinessStepTest.java | 107 +++++++++++++++++++++
 8 files changed, 216 insertions(+), 1 deletion(-)

diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStep.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStep.java
new file mode 100644
index 000000000..8d727e1ff
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStep.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.cob.loan;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.exceptions.BusinessStepException;
+import org.apache.fineract.infrastructure.core.exception.MultiException;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualPlatformService;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class AddPeriodicAccrualEntriesBusinessStep implements LoanCOBBusinessStep {
+
+    private final LoanAccrualPlatformService loanAccrualPlatformService;
+
+    @Override
+    public Loan execute(Loan loan) {
+        try {
+            loanAccrualPlatformService.addPeriodicAccruals(DateUtils.getBusinessLocalDate(), loan);
+        } catch (MultiException e) {
+            throw new BusinessStepException(String.format("Fail to process period accrual for loan id [%s]", loan.getId()), e);
+        }
+        return loan;
+    }
+
+    @Override
+    public String getEnumStyledName() {
+        return "ADD_PERIODIC_ACCRUAL_ENTRIES";
+    }
+
+    @Override
+    public String getHumanReadableName() {
+        return "Add periodic accrual entries";
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java
index 32e4f9b2c..46111fbb6 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java
@@ -22,11 +22,14 @@ import java.time.LocalDate;
 import java.util.Collection;
 import org.apache.fineract.infrastructure.core.exception.MultiException;
 import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 
 public interface LoanAccrualPlatformService {
 
     void addPeriodicAccruals(LocalDate tilldate) throws MultiException;
 
+    void addPeriodicAccruals(LocalDate tilldate, Loan loan) throws MultiException;
+
     void addPeriodicAccruals(LocalDate tilldate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas) throws MultiException;
 
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java
index 590fbb56b..abe7867f3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java
@@ -28,6 +28,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
 import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.springframework.stereotype.Service;
 
 @Service
@@ -45,6 +46,13 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
         addPeriodicAccruals(tillDate, loanScheduleAccrualDataList);
     }
 
+    @Override
+    public void addPeriodicAccruals(final LocalDate tillDate, Loan loan) throws JobExecutionException {
+        Collection<LoanScheduleAccrualData> loanScheduleAccrualDataList = this.loanReadPlatformService.retrievePeriodicAccrualData(tillDate,
+                loan);
+        addPeriodicAccruals(tillDate, loanScheduleAccrualDataList);
+    }
+
     @Override
     public void addPeriodicAccruals(final LocalDate tillDate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDataList)
             throws JobExecutionException {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
index 220141156..235b6b87f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
@@ -116,6 +116,8 @@ public interface LoanReadPlatformService {
 
     Collection<LoanScheduleAccrualData> retrievePeriodicAccrualData(LocalDate tillDate);
 
+    Collection<LoanScheduleAccrualData> retrievePeriodicAccrualData(LocalDate tillDate, Loan loan);
+
     LoanTransactionData retrieveLoanChargeOffTemplate(Long loanId);
 
     Collection<Long> fetchLoansForInterestRecalculation();
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index 0e5acbb8b..3ea603324 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -1761,7 +1761,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
 
     @Override
     public Collection<LoanScheduleAccrualData> retrievePeriodicAccrualData(final LocalDate tillDate) {
+        return retrievePeriodicAccrualData(tillDate, null);
+    }
 
+    @Override
+    public Collection<LoanScheduleAccrualData> retrievePeriodicAccrualData(final LocalDate tillDate, final Loan loan) {
         LoanSchedulePeriodicAccrualMapper mapper = new LoanSchedulePeriodicAccrualMapper();
         LocalDate organisationStartDate = this.configurationDomainService.retrieveOrganisationStartDate();
         final StringBuilder sqlBuilder = new StringBuilder(400);
@@ -1772,11 +1776,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
                 .append(" or (ls.interest_amount <> COALESCE(ls.accrual_interest_derived, 0)))")
                 .append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and (loan.closedon_date <= :tillDate or loan.closedon_date is null)")
                 .append(" and loan.is_npa=false and (ls.duedate <= :tillDate or (ls.duedate > :tillDate and ls.fromdate < :tillDate))) ");
-        Map<String, Object> paramMap = new HashMap<>(4);
+        Map<String, Object> paramMap = new HashMap<>(5);
         if (organisationStartDate != null) {
             sqlBuilder.append(" and ls.duedate > :organisationStartDate ");
             paramMap.put("organisationStartDate", organisationStartDate);
         }
+        if (loan != null) {
+            sqlBuilder.append(" and loan.id= :loanId ");
+            paramMap.put("loanId", loan.getId());
+        }
         sqlBuilder.append(" order by loan.id,ls.duedate ");
         paramMap.put("active", LoanStatus.ACTIVE.getValue());
         paramMap.put("type", AccountingRuleType.ACCRUAL_PERIODIC.getValue());
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 ec1c1fcd8..56d37e5a8 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
@@ -111,4 +111,5 @@
     <include file="parts/0089_add_update_loan_arrears_aging_business_step.xml" relativeToChangelogFile="true" />
     <include file="parts/0090_add_report_export_s3_folder_configuration.xml" relativeToChangelogFile="true" />
     <include file="parts/0091_modify_parameter_value_type_in_job_parameters_table.xml" relativeToChangelogFile="true" />
+    <include file="parts/0092_add_periodic_accrual_entries_business_step.xml" relativeToChangelogFile="true" />
 </databaseChangeLog>
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0092_add_periodic_accrual_entries_business_step.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0092_add_periodic_accrual_entries_business_step.xml
new file mode 100644
index 000000000..d161b254c
--- /dev/null
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0092_add_periodic_accrual_entries_business_step.xml
@@ -0,0 +1,32 @@
+<?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.1.xsd">
+    <changeSet id="1" author="fineract">
+        <insert tableName="m_batch_business_steps">
+            <column name="job_name" value="LOAN_CLOSE_OF_BUSINESS"/>
+            <column name="step_name" value="ADD_PERIODIC_ACCRUAL_ENTRIES"/>
+            <column name="step_order" value="6"/>
+        </insert>
+    </changeSet>
+</databaseChangeLog>
diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStepTest.java
new file mode 100644
index 000000000..a77f4f0da
--- /dev/null
+++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/AddPeriodicAccrualEntriesBusinessStepTest.java
@@ -0,0 +1,107 @@
+/**
+ * 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.cob.loan;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.fineract.cob.exceptions.BusinessStepException;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
+import org.apache.fineract.infrastructure.core.exception.MultiException;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualPlatformService;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public class AddPeriodicAccrualEntriesBusinessStepTest {
+
+    @Mock
+    private LoanAccrualPlatformService loanAccrualPlatformService;
+
+    private AddPeriodicAccrualEntriesBusinessStep underTest;
+
+    @BeforeEach
+    public void setUp() {
+        ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
+        ThreadLocalContextUtil
+                .setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
+        underTest = new AddPeriodicAccrualEntriesBusinessStep(loanAccrualPlatformService);
+    }
+
+    @Test
+    public void givenLoanWithAccrual() throws MultiException {
+        // given
+        final Loan loanForProcessing = Mockito.mock(Loan.class);
+        // when
+        final Loan processedLoan = underTest.execute(loanForProcessing);
+        // then
+        verify(loanAccrualPlatformService, times(1)).addPeriodicAccruals(any(LocalDate.class), eq(loanForProcessing));
+        assertEquals(processedLoan, loanForProcessing);
+    }
+
+    @Test
+    public void givenLoanWithAccrualThrowException() throws MultiException {
+        // given
+        final Long loanId = RandomUtils.nextLong();
+        final Loan loanForProcessing = Mockito.mock(Loan.class);
+        when(loanForProcessing.getId()).thenReturn(loanId);
+        doThrow(new MultiException(Collections.singletonList(new RuntimeException()))).when(loanAccrualPlatformService)
+                .addPeriodicAccruals(any(LocalDate.class), eq(loanForProcessing));
+        // when
+        final BusinessStepException businessStepException = Assert.assertThrows(BusinessStepException.class,
+                () -> underTest.execute(loanForProcessing));
+        // then
+        verify(loanAccrualPlatformService, times(1)).addPeriodicAccruals(any(LocalDate.class), eq(loanForProcessing));
+        assertEquals(String.format("Fail to process period accrual for loan id [%s]", loanId), businessStepException.getMessage());
+    }
+
+    @Test
+    public void testGetEnumStyledNameSuccessScenario() {
+        final String actualEnumName = underTest.getEnumStyledName();
+        assertNotNull(actualEnumName);
+        assertEquals("ADD_PERIODIC_ACCRUAL_ENTRIES", actualEnumName);
+    }
+
+    @Test
+    public void testGetHumanReadableNameSuccessScenario() {
+        final String actualEnumName = underTest.getHumanReadableName();
+        assertNotNull(actualEnumName);
+        assertEquals("Add periodic accrual entries", actualEnumName);
+    }
+}