FINERACT-1734-Repayment-due-event
This commit is contained in:
committed by
Arnold Gálovics
parent
11e22f6117
commit
6c72ee49d8
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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 java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRepaymentDueBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CheckLoanRepaymentDueBusinessStep implements LoanCOBBusinessStep {
|
||||||
|
|
||||||
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Loan execute(Loan loan) {
|
||||||
|
Long numberOfDaysBeforeDueDateToRaiseEvent = configurationDomainService.retrieveRepaymentDueDays();
|
||||||
|
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
|
||||||
|
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||||
|
for (LoanRepaymentScheduleInstallment repaymentSchedule : loanRepaymentScheduleInstallments) {
|
||||||
|
LocalDate repaymentDate = repaymentSchedule.getDueDate();
|
||||||
|
if (repaymentDate.minusDays(numberOfDaysBeforeDueDateToRaiseEvent).equals(currentDate)) {
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanRepaymentDueBusinessEvent(loan));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEnumStyledName() {
|
||||||
|
return "CHECK_LOAN_REPAYMENT_DUE";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHumanReadableName() {
|
||||||
|
return "Check loan repayment due";
|
||||||
|
}
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* 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 java.time.LocalDate;
|
||||||
|
import java.util.Collection;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRepaymentOverdueBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CheckLoanRepaymentOverdueBusinessStep implements LoanCOBBusinessStep {
|
||||||
|
|
||||||
|
private final LoanReadPlatformService loanReadPlatformService;
|
||||||
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Loan execute(Loan loan) {
|
||||||
|
Long numberOfDaysAfterDueDateToRaiseEvent = configurationDomainService.retrieveRepaymentOverdueDays();
|
||||||
|
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
|
||||||
|
final Collection<OverdueLoanScheduleData> overdueInstallmentsForLoan = loanReadPlatformService
|
||||||
|
.retrieveAllOverdueInstallmentsForLoan(loan);
|
||||||
|
for (OverdueLoanScheduleData overdueInstallment : overdueInstallmentsForLoan) {
|
||||||
|
LocalDate installmentDueDate = LocalDate.parse(overdueInstallment.getDueDate());
|
||||||
|
if (installmentDueDate.plusDays(numberOfDaysAfterDueDateToRaiseEvent).equals(currentDate)) {
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanRepaymentOverdueBusinessEvent(loan));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEnumStyledName() {
|
||||||
|
return "CHECK_LOAN_REPAYMENT_OVERDUE";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHumanReadableName() {
|
||||||
|
return "Check loan repayment overdue";
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
@@ -120,4 +120,8 @@ public interface ConfigurationDomainService {
|
|||||||
boolean isReversalTransactionAllowed();
|
boolean isReversalTransactionAllowed();
|
||||||
|
|
||||||
Long retrieveExternalEventsPurgeDaysCriteria();
|
Long retrieveExternalEventsPurgeDaysCriteria();
|
||||||
|
|
||||||
|
Long retrieveRepaymentDueDays();
|
||||||
|
|
||||||
|
Long retrieveRepaymentOverdueDays();
|
||||||
}
|
}
|
||||||
|
|||||||
+14
@@ -41,6 +41,8 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
|
|||||||
public static final String ENABLE_BUSINESS_DATE = "enable_business_date";
|
public static final String ENABLE_BUSINESS_DATE = "enable_business_date";
|
||||||
public static final String ENABLE_AUTOMATIC_COB_DATE_ADJUSTMENT = "enable_automatic_cob_date_adjustment";
|
public static final String ENABLE_AUTOMATIC_COB_DATE_ADJUSTMENT = "enable_automatic_cob_date_adjustment";
|
||||||
public static final String EXTERNAL_EVENTS_PURGE_DAYS = "purge-external-events-older-than-days";
|
public static final String EXTERNAL_EVENTS_PURGE_DAYS = "purge-external-events-older-than-days";
|
||||||
|
private static final String DAYS_BEFORE_REPAYMENT_IS_DUE = "days-before-repayment-is-due";
|
||||||
|
private static final String DAYS_AFTER_REPAYMENT_IS_OVERDUE = "days-after-repayment-is-overdue";
|
||||||
private final PermissionRepository permissionRepository;
|
private final PermissionRepository permissionRepository;
|
||||||
private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
|
private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
|
||||||
private final PlatformCacheRepository cacheTypeRepository;
|
private final PlatformCacheRepository cacheTypeRepository;
|
||||||
@@ -459,4 +461,16 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
|
|||||||
return property.getValue();
|
return property.getValue();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long retrieveRepaymentDueDays() {
|
||||||
|
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(DAYS_BEFORE_REPAYMENT_IS_DUE);
|
||||||
|
return property.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long retrieveRepaymentOverdueDays() {
|
||||||
|
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(DAYS_AFTER_REPAYMENT_IS_OVERDUE);
|
||||||
|
return property.getValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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.business.domain.loan;
|
||||||
|
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
|
||||||
|
public class LoanRepaymentDueBusinessEvent extends LoanBusinessEvent {
|
||||||
|
|
||||||
|
private static final String TYPE = "LoanRepaymentDueBusinessEvent";
|
||||||
|
|
||||||
|
public LoanRepaymentDueBusinessEvent(Loan value) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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.business.domain.loan;
|
||||||
|
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
|
||||||
|
public class LoanRepaymentOverdueBusinessEvent extends LoanBusinessEvent {
|
||||||
|
|
||||||
|
private static final String TYPE = "LoanRepaymentOverdueBusinessEvent";
|
||||||
|
|
||||||
|
public LoanRepaymentOverdueBusinessEvent(Loan value) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -86,4 +86,5 @@
|
|||||||
<include file="parts/0064_refactor_loan_transaction_strategy.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0064_refactor_loan_transaction_strategy.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0065_add_bypass_loan_write_transaction_permission.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0065_add_bypass_loan_write_transaction_permission.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0066_delinquency_classification_chargeback.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0066_delinquency_classification_chargeback.xml" relativeToChangelogFile="true"/>
|
||||||
|
<include file="parts/0067_add_configurations_for_repayment_due_business_steps.xml" relativeToChangelogFile="true"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
<?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" context="postgresql">
|
||||||
|
<sql>
|
||||||
|
SELECT SETVAL('c_configuration_id_seq', COALESCE(MAX(id), 0)+1, false ) FROM c_configuration;
|
||||||
|
</sql>
|
||||||
|
</changeSet>
|
||||||
|
<changeSet author="fineract" id="2">
|
||||||
|
<insert tableName="c_configuration">
|
||||||
|
<column name="name" value="days-before-repayment-is-due"/>
|
||||||
|
<column name="value" valueNumeric="1"/>
|
||||||
|
<column name="date_value"/>
|
||||||
|
<column name="string_value"/>
|
||||||
|
<column name="enabled" valueBoolean="false"/>
|
||||||
|
<column name="is_trap_door" valueBoolean="false"/>
|
||||||
|
<column name="description" value="Number of days before repayment is due to raise event"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="c_configuration">
|
||||||
|
<column name="name" value="days-after-repayment-is-overdue"/>
|
||||||
|
<column name="value" valueNumeric="1"/>
|
||||||
|
<column name="date_value"/>
|
||||||
|
<column name="string_value"/>
|
||||||
|
<column name="enabled" valueBoolean="false"/>
|
||||||
|
<column name="is_trap_door" valueBoolean="false"/>
|
||||||
|
<column name="description" value="Number of days after repayment overdue to raise event"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_external_event_configuration">
|
||||||
|
<column name="type" value="LoanRepaymentDueBusinessEvent"/>
|
||||||
|
<column name="enabled" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_external_event_configuration">
|
||||||
|
<column name="type" value="LoanRepaymentOverdueBusinessEvent"/>
|
||||||
|
<column name="enabled" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_batch_business_steps">
|
||||||
|
<column name="job_name" value="LOAN_CLOSE_OF_BUSINESS"/>
|
||||||
|
<column name="step_name" value="CHECK_LOAN_REPAYMENT_DUE"/>
|
||||||
|
<column name="step_order" value="3"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_batch_business_steps">
|
||||||
|
<column name="job_name" value="LOAN_CLOSE_OF_BUSINESS"/>
|
||||||
|
<column name="step_name" value="CHECK_LOAN_REPAYMENT_OVERDUE"/>
|
||||||
|
<column name="step_order" value="4"/>
|
||||||
|
</insert>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* 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.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||||
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRepaymentDueBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
public class CheckLoanRepaymentDueBusinessStepTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ConfigurationDomainService configurationDomainService;
|
||||||
|
@Mock
|
||||||
|
private BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
private CheckLoanRepaymentDueBusinessStep 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 CheckLoanRepaymentDueBusinessStep(configurationDomainService, businessEventNotifierService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenLoanWithInstallmentDueAfterConfiguredDaysWhenStepExecutionThenBusinessEventIsRaised() {
|
||||||
|
ArgumentCaptor<LoanRepaymentDueBusinessEvent> loanRepaymentDueEvent = ArgumentCaptor.forClass(LoanRepaymentDueBusinessEvent.class);
|
||||||
|
// given
|
||||||
|
when(configurationDomainService.retrieveRepaymentDueDays()).thenReturn(1L);
|
||||||
|
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().plusDays(1);
|
||||||
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays
|
||||||
|
.asList(new LoanRepaymentScheduleInstallment(loanForProcessing, 1, LocalDate.now(ZoneId.systemDefault()),
|
||||||
|
loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
|
BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)));
|
||||||
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
|
// then
|
||||||
|
verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanRepaymentDueEvent.capture());
|
||||||
|
Loan loanPayloadForEvent = loanRepaymentDueEvent.getValue().get();
|
||||||
|
assertEquals(loanForProcessing, loanPayloadForEvent);
|
||||||
|
assertEquals(processedLoan, loanPayloadForEvent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenLoanWithNoInstallmentDueAfterConfiguredDaysWhenStepExecutionThenNoBusinessEventIsRaised() {
|
||||||
|
// given
|
||||||
|
when(configurationDomainService.retrieveRepaymentDueDays()).thenReturn(1L);
|
||||||
|
LocalDate loanInstallmentRepaymentDueDateAfter5Days = DateUtils.getBusinessLocalDate().plusDays(5);
|
||||||
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays
|
||||||
|
.asList(new LoanRepaymentScheduleInstallment(loanForProcessing, 1, LocalDate.now(ZoneId.systemDefault()),
|
||||||
|
loanInstallmentRepaymentDueDateAfter5Days, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)));
|
||||||
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
|
// then
|
||||||
|
verify(businessEventNotifierService, times(0)).notifyPostBusinessEvent(any());
|
||||||
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* 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.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||||
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRepaymentOverdueBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
public class CheckLoanRepaymentOverdueBusinessStepTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private LoanReadPlatformService loanReadPlatformService;
|
||||||
|
@Mock
|
||||||
|
private ConfigurationDomainService configurationDomainService;
|
||||||
|
@Mock
|
||||||
|
private BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
private CheckLoanRepaymentOverdueBusinessStep 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 CheckLoanRepaymentOverdueBusinessStep(loanReadPlatformService, configurationDomainService,
|
||||||
|
businessEventNotifierService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenLoanWithInstallmentOverdueAfterConfiguredDaysWhenStepExecutionThenBusinessEventIsRaised() {
|
||||||
|
ArgumentCaptor<LoanRepaymentOverdueBusinessEvent> loanRepaymentOverdueBusinessEventArgumentCaptor = ArgumentCaptor
|
||||||
|
.forClass(LoanRepaymentOverdueBusinessEvent.class);
|
||||||
|
// given
|
||||||
|
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L);
|
||||||
|
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().minusDays(1);
|
||||||
|
Collection<OverdueLoanScheduleData> overdueInstallmentsForLoan = Arrays
|
||||||
|
.asList(new OverdueLoanScheduleData(1L, 1L, loanInstallmentRepaymentDueDate.toString(), BigDecimal.valueOf(0.0), "", "",
|
||||||
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), 1));
|
||||||
|
when(loanReadPlatformService.retrieveAllOverdueInstallmentsForLoan(any())).thenReturn(overdueInstallmentsForLoan);
|
||||||
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
// when
|
||||||
|
Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
|
// then
|
||||||
|
verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanRepaymentOverdueBusinessEventArgumentCaptor.capture());
|
||||||
|
Loan loanPayloadForEvent = loanRepaymentOverdueBusinessEventArgumentCaptor.getValue().get();
|
||||||
|
assertEquals(loanForProcessing, loanPayloadForEvent);
|
||||||
|
assertEquals(processedLoan, loanPayloadForEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenLoanWithNoInstallmentOverdueAfterConfiguredDaysWhenStepExecutionThenNoBusinessEventIsRaised() {
|
||||||
|
// given
|
||||||
|
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L);
|
||||||
|
LocalDate loanInstallmentRepaymentDueDateBefore5Days = DateUtils.getBusinessLocalDate().minusDays(5);
|
||||||
|
Collection<OverdueLoanScheduleData> overdueInstallmentsForLoan = Arrays
|
||||||
|
.asList(new OverdueLoanScheduleData(1L, 1L, loanInstallmentRepaymentDueDateBefore5Days.toString(), BigDecimal.valueOf(0.0),
|
||||||
|
"", "", BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), 1));
|
||||||
|
when(loanReadPlatformService.retrieveAllOverdueInstallmentsForLoan(any())).thenReturn(overdueInstallmentsForLoan);
|
||||||
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
// when
|
||||||
|
Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
|
// then
|
||||||
|
verify(businessEventNotifierService, times(0)).notifyPostBusinessEvent(any());
|
||||||
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-4
@@ -73,8 +73,9 @@ public class ExternalEventConfigurationValidationServiceTest {
|
|||||||
"LoanInitiateTransferBusinessEvent", "LoanInterestRecalculationBusinessEvent", "LoanProductCreateBusinessEvent",
|
"LoanInitiateTransferBusinessEvent", "LoanInterestRecalculationBusinessEvent", "LoanProductCreateBusinessEvent",
|
||||||
"LoanReassignOfficerBusinessEvent", "LoanRefundPostBusinessEvent", "LoanRefundPreBusinessEvent",
|
"LoanReassignOfficerBusinessEvent", "LoanRefundPostBusinessEvent", "LoanRefundPreBusinessEvent",
|
||||||
"LoanRejectedBusinessEvent", "LoanRejectTransferBusinessEvent", "LoanRemoveOfficerBusinessEvent",
|
"LoanRejectedBusinessEvent", "LoanRejectTransferBusinessEvent", "LoanRemoveOfficerBusinessEvent",
|
||||||
"LoanRescheduledDueCalendarChangeBusinessEvent", "LoanRescheduledDueHolidayBusinessEvent",
|
"LoanRepaymentDueBusinessEvent", "LoanRepaymentOverdueBusinessEvent", "LoanRescheduledDueCalendarChangeBusinessEvent",
|
||||||
"LoanScheduleVariationsAddedBusinessEvent", "LoanScheduleVariationsDeletedBusinessEvent", "LoanStatusChangedBusinessEvent",
|
"LoanRescheduledDueHolidayBusinessEvent", "LoanScheduleVariationsAddedBusinessEvent",
|
||||||
|
"LoanScheduleVariationsDeletedBusinessEvent", "LoanStatusChangedBusinessEvent",
|
||||||
"LoanTransactionGoodwillCreditPostBusinessEvent", "LoanTransactionGoodwillCreditPreBusinessEvent",
|
"LoanTransactionGoodwillCreditPostBusinessEvent", "LoanTransactionGoodwillCreditPreBusinessEvent",
|
||||||
"LoanTransactionMakeRepaymentPostBusinessEvent", "LoanTransactionMakeRepaymentPreBusinessEvent",
|
"LoanTransactionMakeRepaymentPostBusinessEvent", "LoanTransactionMakeRepaymentPreBusinessEvent",
|
||||||
"LoanTransactionMerchantIssuedRefundPostBusinessEvent", "LoanTransactionMerchantIssuedRefundPreBusinessEvent",
|
"LoanTransactionMerchantIssuedRefundPostBusinessEvent", "LoanTransactionMerchantIssuedRefundPreBusinessEvent",
|
||||||
@@ -144,8 +145,9 @@ public class ExternalEventConfigurationValidationServiceTest {
|
|||||||
"LoanInitiateTransferBusinessEvent", "LoanInterestRecalculationBusinessEvent", "LoanProductCreateBusinessEvent",
|
"LoanInitiateTransferBusinessEvent", "LoanInterestRecalculationBusinessEvent", "LoanProductCreateBusinessEvent",
|
||||||
"LoanReassignOfficerBusinessEvent", "LoanRefundPostBusinessEvent", "LoanRefundPreBusinessEvent",
|
"LoanReassignOfficerBusinessEvent", "LoanRefundPostBusinessEvent", "LoanRefundPreBusinessEvent",
|
||||||
"LoanRejectedBusinessEvent", "LoanRejectTransferBusinessEvent", "LoanRemoveOfficerBusinessEvent",
|
"LoanRejectedBusinessEvent", "LoanRejectTransferBusinessEvent", "LoanRemoveOfficerBusinessEvent",
|
||||||
"LoanRescheduledDueCalendarChangeBusinessEvent", "LoanRescheduledDueHolidayBusinessEvent",
|
"LoanRepaymentDueBusinessEvent", "LoanRepaymentOverdueBusinessEvent", "LoanRescheduledDueCalendarChangeBusinessEvent",
|
||||||
"LoanScheduleVariationsAddedBusinessEvent", "LoanScheduleVariationsDeletedBusinessEvent", "LoanStatusChangedBusinessEvent",
|
"LoanRescheduledDueHolidayBusinessEvent", "LoanScheduleVariationsAddedBusinessEvent",
|
||||||
|
"LoanScheduleVariationsDeletedBusinessEvent", "LoanStatusChangedBusinessEvent",
|
||||||
"LoanTransactionGoodwillCreditPostBusinessEvent", "LoanTransactionGoodwillCreditPreBusinessEvent",
|
"LoanTransactionGoodwillCreditPostBusinessEvent", "LoanTransactionGoodwillCreditPreBusinessEvent",
|
||||||
"LoanTransactionMakeRepaymentPostBusinessEvent", "LoanTransactionMakeRepaymentPreBusinessEvent",
|
"LoanTransactionMakeRepaymentPostBusinessEvent", "LoanTransactionMakeRepaymentPreBusinessEvent",
|
||||||
"LoanTransactionMerchantIssuedRefundPostBusinessEvent", "LoanTransactionMerchantIssuedRefundPreBusinessEvent",
|
"LoanTransactionMerchantIssuedRefundPostBusinessEvent", "LoanTransactionMerchantIssuedRefundPreBusinessEvent",
|
||||||
|
|||||||
+10
@@ -220,6 +220,16 @@ public class ExternalEventConfigurationHelper {
|
|||||||
loanRemoveOfficerBusinessEvent.put("enabled", false);
|
loanRemoveOfficerBusinessEvent.put("enabled", false);
|
||||||
defaults.add(loanRemoveOfficerBusinessEvent);
|
defaults.add(loanRemoveOfficerBusinessEvent);
|
||||||
|
|
||||||
|
Map<String, Object> loanRepaymentDueBusinessEvent = new HashMap<>();
|
||||||
|
loanRepaymentDueBusinessEvent.put("type", "LoanRepaymentDueBusinessEvent");
|
||||||
|
loanRepaymentDueBusinessEvent.put("enabled", false);
|
||||||
|
defaults.add(loanRepaymentDueBusinessEvent);
|
||||||
|
|
||||||
|
Map<String, Object> loanRepaymentOverdueBusinessEvent = new HashMap<>();
|
||||||
|
loanRepaymentOverdueBusinessEvent.put("type", "LoanRepaymentOverdueBusinessEvent");
|
||||||
|
loanRepaymentOverdueBusinessEvent.put("enabled", false);
|
||||||
|
defaults.add(loanRepaymentOverdueBusinessEvent);
|
||||||
|
|
||||||
Map<String, Object> loanRescheduledDueCalendarChangeBusinessEvent = new HashMap<>();
|
Map<String, Object> loanRescheduledDueCalendarChangeBusinessEvent = new HashMap<>();
|
||||||
loanRescheduledDueCalendarChangeBusinessEvent.put("type", "LoanRescheduledDueCalendarChangeBusinessEvent");
|
loanRescheduledDueCalendarChangeBusinessEvent.put("type", "LoanRescheduledDueCalendarChangeBusinessEvent");
|
||||||
loanRescheduledDueCalendarChangeBusinessEvent.put("enabled", false);
|
loanRescheduledDueCalendarChangeBusinessEvent.put("enabled", false);
|
||||||
|
|||||||
+18
-2
@@ -99,8 +99,8 @@ public class GlobalConfigurationHelper {
|
|||||||
ArrayList<HashMap> actualGlobalConfigurations = getAllGlobalConfigurations(requestSpec, responseSpec);
|
ArrayList<HashMap> actualGlobalConfigurations = getAllGlobalConfigurations(requestSpec, responseSpec);
|
||||||
|
|
||||||
// There are currently 37 global configurations.
|
// There are currently 37 global configurations.
|
||||||
Assertions.assertEquals(42, expectedGlobalConfigurations.size());
|
Assertions.assertEquals(44, expectedGlobalConfigurations.size());
|
||||||
Assertions.assertEquals(42, actualGlobalConfigurations.size());
|
Assertions.assertEquals(44, actualGlobalConfigurations.size());
|
||||||
|
|
||||||
for (int i = 0; i < expectedGlobalConfigurations.size(); i++) {
|
for (int i = 0; i < expectedGlobalConfigurations.size(); i++) {
|
||||||
|
|
||||||
@@ -472,6 +472,22 @@ public class GlobalConfigurationHelper {
|
|||||||
purgeExternalEventsOlderThanDaysDefault.put("trapDoor", false);
|
purgeExternalEventsOlderThanDaysDefault.put("trapDoor", false);
|
||||||
defaults.add(purgeExternalEventsOlderThanDaysDefault);
|
defaults.add(purgeExternalEventsOlderThanDaysDefault);
|
||||||
|
|
||||||
|
HashMap<String, Object> loanRepaymentDueDaysDefault = new HashMap<>();
|
||||||
|
loanRepaymentDueDaysDefault.put("id", 48);
|
||||||
|
loanRepaymentDueDaysDefault.put("name", "days-before-repayment-is-due");
|
||||||
|
loanRepaymentDueDaysDefault.put("value", 1);
|
||||||
|
loanRepaymentDueDaysDefault.put("enabled", false);
|
||||||
|
loanRepaymentDueDaysDefault.put("trapDoor", false);
|
||||||
|
defaults.add(loanRepaymentDueDaysDefault);
|
||||||
|
|
||||||
|
HashMap<String, Object> loanRepaymentOverdueDaysDefault = new HashMap<>();
|
||||||
|
loanRepaymentOverdueDaysDefault.put("id", 49);
|
||||||
|
loanRepaymentOverdueDaysDefault.put("name", "days-after-repayment-is-overdue");
|
||||||
|
loanRepaymentOverdueDaysDefault.put("value", 1);
|
||||||
|
loanRepaymentOverdueDaysDefault.put("enabled", false);
|
||||||
|
loanRepaymentOverdueDaysDefault.put("trapDoor", false);
|
||||||
|
defaults.add(loanRepaymentOverdueDaysDefault);
|
||||||
|
|
||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user