Skip to content

Commit

Permalink
FINERACT-1992: Backdated delinquency pause events
Browse files Browse the repository at this point in the history
  • Loading branch information
ruchiD authored and adamsaghy committed Dec 15, 2023
1 parent cd2f2f8 commit 5edd18a
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,13 @@ private List<LoanInstallmentDelinquencyBucketDataV1> calculateInstallmentLevelDe
.build();

// get list of charges for installments in same range
List<LoanCharge> chargesForInstallmentsInSameRange = loan.getLoanCharges().stream()
.filter(loanCharge -> !loanCharge.isPaid() && delinquentInstallmentsInSameRange.stream().anyMatch(
installmentForCharge -> (DateUtils.isAfter(loanCharge.getDueDate(), installmentForCharge.getFromDate())
|| DateUtils.isEqual(loanCharge.getDueDate(), installmentForCharge.getFromDate()))
&& (DateUtils.isBefore(loanCharge.getDueDate(), installmentForCharge.getDueDate())
|| DateUtils.isEqual(loanCharge.getDueDate(), installmentForCharge.getDueDate()))))
List<LoanCharge> chargesForInstallmentsInSameRange = loan.getLoanCharges().stream().filter(loanCharge -> !loanCharge
.isPaid()
&& delinquentInstallmentsInSameRange.stream().anyMatch(installmentForCharge -> (DateUtils
.isAfter(loanCharge.getEffectiveDueDate(), installmentForCharge.getFromDate())
|| DateUtils.isEqual(loanCharge.getEffectiveDueDate(), installmentForCharge.getFromDate()))
&& (DateUtils.isBefore(loanCharge.getEffectiveDueDate(), installmentForCharge.getDueDate())
|| DateUtils.isEqual(loanCharge.getEffectiveDueDate(), installmentForCharge.getDueDate()))))
.toList();

List<LoanChargeDataRangeViewV1> charges = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ public CommandProcessingResult createDelinquencyAction(Long loanId, JsonCommand
if (DateUtils.isBefore(parsedDelinquencyAction.getStartDate(), businessDate)
&& DelinquencyAction.PAUSE.equals(parsedDelinquencyAction.getAction())) {
recalculateLoanDelinquencyData(loan);
// if pause end date is after current business date, loan delinquency pause flag is changed, emit event
if (DateUtils.isAfter(parsedDelinquencyAction.getEndDate(), businessDate)) {
businessEventNotifierService.notifyPostBusinessEvent(new LoanDelinquencyRangeChangeBusinessEvent(loan));
}
}
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccountDelinquencyPauseChangedBusinessEvent(loan));
return new CommandProcessingResultBuilder().withCommandId(command.commandId()) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyIterable;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand All @@ -30,6 +31,7 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -38,23 +40,31 @@
import java.util.Map;
import java.util.Optional;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.ActionContext;
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.LoanAccountDelinquencyPauseChangedBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanDelinquencyRangeChangeBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketMappingsRepository;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRangeRepository;
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyActionRepository;
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory;
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistoryRepository;
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTag;
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTagRepository;
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformServiceImpl;
import org.apache.fineract.portfolio.delinquency.service.LoanDelinquencyDomainService;
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParseAndValidator;
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketParseAndValidator;
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
Expand Down Expand Up @@ -100,6 +110,14 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
private LoanDelinquencyDomainService loanDelinquencyDomainService;
@Mock
private LoanInstallmentDelinquencyTagRepository loanInstallmentDelinquencyTagRepository;
@Mock
private DelinquencyReadPlatformService delinquencyReadPlatformService;
@Mock
private DelinquencyActionParseAndValidator delinquencyActionParseAndValidator;
@Mock
private LoanDelinquencyActionRepository loanDelinquencyActionRepository;
@Mock
private DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;

@InjectMocks
private DelinquencyWritePlatformServiceImpl underTest;
Expand Down Expand Up @@ -498,4 +516,103 @@ public void givenLoanAccountEnableInstallmentLevelDelinquencyWhenLoanIsOutOfDeli
assertEquals(loanForProcessing, loanPayloadForEvent);

}

@Test
public void givenLoanAccountWhenBackdatedPauseActionThenLoanDelinquencyPauseChangeBusinessEventIsRaisedTest() {
ArgumentCaptor<LoanAccountDelinquencyPauseChangedBusinessEvent> loanDelinquencyPauseChangeEvent = ArgumentCaptor
.forClass(LoanAccountDelinquencyPauseChangedBusinessEvent.class);
// given
Loan loanForProcessing = Mockito.mock(Loan.class);
loanForProcessing.setId(1L);

JsonCommand command = Mockito.mock(JsonCommand.class);

// Pause period
LocalDate startDate = DateUtils.getBusinessLocalDate().minusDays(8);
LocalDate endDate = DateUtils.getBusinessLocalDate().minusDays(1);

List<LoanDelinquencyAction> delinquencyActions = new ArrayList<>();
List<LoanDelinquencyActionData> effectiveDelinquency = new ArrayList<>();
CollectionData loanCollectionData = CollectionData.template();

when(loanRepository.findOneWithNotFoundDetection(anyLong())).thenReturn(loanForProcessing);

when(delinquencyReadPlatformService.retrieveLoanDelinquencyActions(anyLong())).thenReturn(delinquencyActions);
LoanDelinquencyAction backdatedPauseAction = Mockito.mock(LoanDelinquencyAction.class);
backdatedPauseAction.setId(1L);

when(delinquencyActionParseAndValidator.validateAndParseUpdate(command, loanForProcessing, delinquencyActions,
DateUtils.getBusinessLocalDate())).thenReturn(backdatedPauseAction);
when(backdatedPauseAction.getStartDate()).thenReturn(startDate);
when(backdatedPauseAction.getEndDate()).thenReturn(endDate);
when(backdatedPauseAction.getAction()).thenReturn(DelinquencyAction.PAUSE);

when(loanDelinquencyActionRepository.saveAndFlush(backdatedPauseAction)).thenReturn(backdatedPauseAction);

when(delinquencyEffectivePauseHelper.calculateEffectiveDelinquencyList(delinquencyActions)).thenReturn(effectiveDelinquency);
when(loanDelinquencyDomainService.getOverdueCollectionData(any(), anyList())).thenReturn(loanCollectionData);
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());

// when
underTest.createDelinquencyAction(loanForProcessing.getId(), command);

// then
// verify event is raised
verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanDelinquencyPauseChangeEvent.capture());

Loan loanPayloadForEvent = loanDelinquencyPauseChangeEvent.getValue().get();
assertEquals(loanForProcessing, loanPayloadForEvent);

// verify no range change event for pause flag change as both start and end date are backdated
verify(businessEventNotifierService, times(0)).notifyPostBusinessEvent(any(LoanDelinquencyRangeChangeBusinessEvent.class));

}

@Test
public void givenLoanAccountWhenBackdatedPauseActionThenLoanDelinquencyRangeChangeBusinessEventIsRaisedIfPauseFlagChangeTest() {
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDelinquencyRangeChangeEvent = ArgumentCaptor
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
// given
Loan loanForProcessing = Mockito.mock(Loan.class);
loanForProcessing.setId(1L);

JsonCommand command = Mockito.mock(JsonCommand.class);

// Pause period
LocalDate startDate = DateUtils.getBusinessLocalDate().minusDays(2);
LocalDate endDate = DateUtils.getBusinessLocalDate().plusDays(10);

List<LoanDelinquencyAction> delinquencyActions = new ArrayList<>();
List<LoanDelinquencyActionData> effectiveDelinquency = new ArrayList<>();
CollectionData loanCollectionData = CollectionData.template();

when(loanRepository.findOneWithNotFoundDetection(anyLong())).thenReturn(loanForProcessing);

when(delinquencyReadPlatformService.retrieveLoanDelinquencyActions(anyLong())).thenReturn(delinquencyActions);
LoanDelinquencyAction backdatedPauseAction = Mockito.mock(LoanDelinquencyAction.class);
backdatedPauseAction.setId(1L);

when(delinquencyActionParseAndValidator.validateAndParseUpdate(command, loanForProcessing, delinquencyActions,
DateUtils.getBusinessLocalDate())).thenReturn(backdatedPauseAction);
when(backdatedPauseAction.getStartDate()).thenReturn(startDate);
when(backdatedPauseAction.getEndDate()).thenReturn(endDate);
when(backdatedPauseAction.getAction()).thenReturn(DelinquencyAction.PAUSE);

when(loanDelinquencyActionRepository.saveAndFlush(backdatedPauseAction)).thenReturn(backdatedPauseAction);

when(delinquencyEffectivePauseHelper.calculateEffectiveDelinquencyList(delinquencyActions)).thenReturn(effectiveDelinquency);
when(loanDelinquencyDomainService.getOverdueCollectionData(any(), anyList())).thenReturn(loanCollectionData);
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());

// when
underTest.createDelinquencyAction(loanForProcessing.getId(), command);

// then
// verify event is raised
verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanDelinquencyRangeChangeEvent.capture());

Loan loanPayloadForEvent = loanDelinquencyRangeChangeEvent.getValue().get();
assertEquals(loanForProcessing, loanPayloadForEvent);
}

}

0 comments on commit 5edd18a

Please sign in to comment.