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);
+ }
+}