FINERACT-1724: Added Add periodic accrual as a Loan COB business step
This commit is contained in:
committed by
taskain7
parent
3744ad54ee
commit
f927dd4ff9
+54
@@ -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";
|
||||
}
|
||||
}
|
||||
+3
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
+8
@@ -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 {
|
||||
|
||||
+2
@@ -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();
|
||||
|
||||
+9
-1
@@ -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());
|
||||
|
||||
@@ -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>
|
||||
|
||||
+32
@@ -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>
|
||||
+107
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user