Skip to content

Commit 5edd18a

Browse files
ruchiDadamsaghy
authored andcommitted
FINERACT-1992: Backdated delinquency pause events
1 parent cd2f2f8 commit 5edd18a

3 files changed

Lines changed: 128 additions & 6 deletions

File tree

fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanDelinquencyRangeChangeBusinessEventSerializer.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,13 @@ private List<LoanInstallmentDelinquencyBucketDataV1> calculateInstallmentLevelDe
157157
.build();
158158

159159
// get list of charges for installments in same range
160-
List<LoanCharge> chargesForInstallmentsInSameRange = loan.getLoanCharges().stream()
161-
.filter(loanCharge -> !loanCharge.isPaid() && delinquentInstallmentsInSameRange.stream().anyMatch(
162-
installmentForCharge -> (DateUtils.isAfter(loanCharge.getDueDate(), installmentForCharge.getFromDate())
163-
|| DateUtils.isEqual(loanCharge.getDueDate(), installmentForCharge.getFromDate()))
164-
&& (DateUtils.isBefore(loanCharge.getDueDate(), installmentForCharge.getDueDate())
165-
|| DateUtils.isEqual(loanCharge.getDueDate(), installmentForCharge.getDueDate()))))
160+
List<LoanCharge> chargesForInstallmentsInSameRange = loan.getLoanCharges().stream().filter(loanCharge -> !loanCharge
161+
.isPaid()
162+
&& delinquentInstallmentsInSameRange.stream().anyMatch(installmentForCharge -> (DateUtils
163+
.isAfter(loanCharge.getEffectiveDueDate(), installmentForCharge.getFromDate())
164+
|| DateUtils.isEqual(loanCharge.getEffectiveDueDate(), installmentForCharge.getFromDate()))
165+
&& (DateUtils.isBefore(loanCharge.getEffectiveDueDate(), installmentForCharge.getDueDate())
166+
|| DateUtils.isEqual(loanCharge.getEffectiveDueDate(), installmentForCharge.getDueDate()))))
166167
.toList();
167168

168169
List<LoanChargeDataRangeViewV1> charges = new ArrayList<>();

fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ public CommandProcessingResult createDelinquencyAction(Long loanId, JsonCommand
236236
if (DateUtils.isBefore(parsedDelinquencyAction.getStartDate(), businessDate)
237237
&& DelinquencyAction.PAUSE.equals(parsedDelinquencyAction.getAction())) {
238238
recalculateLoanDelinquencyData(loan);
239+
// if pause end date is after current business date, loan delinquency pause flag is changed, emit event
240+
if (DateUtils.isAfter(parsedDelinquencyAction.getEndDate(), businessDate)) {
241+
businessEventNotifierService.notifyPostBusinessEvent(new LoanDelinquencyRangeChangeBusinessEvent(loan));
242+
}
239243
}
240244
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccountDelinquencyPauseChangedBusinessEvent(loan));
241245
return new CommandProcessingResultBuilder().withCommandId(command.commandId()) //

fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static org.junit.jupiter.api.Assertions.assertNotNull;
2323
import static org.mockito.ArgumentMatchers.any;
2424
import static org.mockito.ArgumentMatchers.anyIterable;
25+
import static org.mockito.ArgumentMatchers.anyList;
2526
import static org.mockito.ArgumentMatchers.anyLong;
2627
import static org.mockito.Mockito.times;
2728
import static org.mockito.Mockito.verify;
@@ -30,6 +31,7 @@
3031
import java.math.BigDecimal;
3132
import java.time.LocalDate;
3233
import java.time.ZoneId;
34+
import java.util.ArrayList;
3335
import java.util.Arrays;
3436
import java.util.Collections;
3537
import java.util.HashMap;
@@ -38,23 +40,31 @@
3840
import java.util.Map;
3941
import java.util.Optional;
4042
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
43+
import org.apache.fineract.infrastructure.core.api.JsonCommand;
4144
import org.apache.fineract.infrastructure.core.domain.ActionContext;
4245
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
4346
import org.apache.fineract.infrastructure.core.service.DateUtils;
4447
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
48+
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAccountDelinquencyPauseChangedBusinessEvent;
4549
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanDelinquencyRangeChangeBusinessEvent;
4650
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
51+
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
4752
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
4853
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketMappingsRepository;
4954
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository;
5055
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange;
5156
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRangeRepository;
57+
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
58+
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyActionRepository;
5259
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory;
5360
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistoryRepository;
5461
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTag;
5562
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTagRepository;
63+
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
64+
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
5665
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformServiceImpl;
5766
import org.apache.fineract.portfolio.delinquency.service.LoanDelinquencyDomainService;
67+
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParseAndValidator;
5868
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketParseAndValidator;
5969
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
6070
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
@@ -100,6 +110,14 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
100110
private LoanDelinquencyDomainService loanDelinquencyDomainService;
101111
@Mock
102112
private LoanInstallmentDelinquencyTagRepository loanInstallmentDelinquencyTagRepository;
113+
@Mock
114+
private DelinquencyReadPlatformService delinquencyReadPlatformService;
115+
@Mock
116+
private DelinquencyActionParseAndValidator delinquencyActionParseAndValidator;
117+
@Mock
118+
private LoanDelinquencyActionRepository loanDelinquencyActionRepository;
119+
@Mock
120+
private DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
103121

104122
@InjectMocks
105123
private DelinquencyWritePlatformServiceImpl underTest;
@@ -498,4 +516,103 @@ public void givenLoanAccountEnableInstallmentLevelDelinquencyWhenLoanIsOutOfDeli
498516
assertEquals(loanForProcessing, loanPayloadForEvent);
499517

500518
}
519+
520+
@Test
521+
public void givenLoanAccountWhenBackdatedPauseActionThenLoanDelinquencyPauseChangeBusinessEventIsRaisedTest() {
522+
ArgumentCaptor<LoanAccountDelinquencyPauseChangedBusinessEvent> loanDelinquencyPauseChangeEvent = ArgumentCaptor
523+
.forClass(LoanAccountDelinquencyPauseChangedBusinessEvent.class);
524+
// given
525+
Loan loanForProcessing = Mockito.mock(Loan.class);
526+
loanForProcessing.setId(1L);
527+
528+
JsonCommand command = Mockito.mock(JsonCommand.class);
529+
530+
// Pause period
531+
LocalDate startDate = DateUtils.getBusinessLocalDate().minusDays(8);
532+
LocalDate endDate = DateUtils.getBusinessLocalDate().minusDays(1);
533+
534+
List<LoanDelinquencyAction> delinquencyActions = new ArrayList<>();
535+
List<LoanDelinquencyActionData> effectiveDelinquency = new ArrayList<>();
536+
CollectionData loanCollectionData = CollectionData.template();
537+
538+
when(loanRepository.findOneWithNotFoundDetection(anyLong())).thenReturn(loanForProcessing);
539+
540+
when(delinquencyReadPlatformService.retrieveLoanDelinquencyActions(anyLong())).thenReturn(delinquencyActions);
541+
LoanDelinquencyAction backdatedPauseAction = Mockito.mock(LoanDelinquencyAction.class);
542+
backdatedPauseAction.setId(1L);
543+
544+
when(delinquencyActionParseAndValidator.validateAndParseUpdate(command, loanForProcessing, delinquencyActions,
545+
DateUtils.getBusinessLocalDate())).thenReturn(backdatedPauseAction);
546+
when(backdatedPauseAction.getStartDate()).thenReturn(startDate);
547+
when(backdatedPauseAction.getEndDate()).thenReturn(endDate);
548+
when(backdatedPauseAction.getAction()).thenReturn(DelinquencyAction.PAUSE);
549+
550+
when(loanDelinquencyActionRepository.saveAndFlush(backdatedPauseAction)).thenReturn(backdatedPauseAction);
551+
552+
when(delinquencyEffectivePauseHelper.calculateEffectiveDelinquencyList(delinquencyActions)).thenReturn(effectiveDelinquency);
553+
when(loanDelinquencyDomainService.getOverdueCollectionData(any(), anyList())).thenReturn(loanCollectionData);
554+
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
555+
556+
// when
557+
underTest.createDelinquencyAction(loanForProcessing.getId(), command);
558+
559+
// then
560+
// verify event is raised
561+
verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanDelinquencyPauseChangeEvent.capture());
562+
563+
Loan loanPayloadForEvent = loanDelinquencyPauseChangeEvent.getValue().get();
564+
assertEquals(loanForProcessing, loanPayloadForEvent);
565+
566+
// verify no range change event for pause flag change as both start and end date are backdated
567+
verify(businessEventNotifierService, times(0)).notifyPostBusinessEvent(any(LoanDelinquencyRangeChangeBusinessEvent.class));
568+
569+
}
570+
571+
@Test
572+
public void givenLoanAccountWhenBackdatedPauseActionThenLoanDelinquencyRangeChangeBusinessEventIsRaisedIfPauseFlagChangeTest() {
573+
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDelinquencyRangeChangeEvent = ArgumentCaptor
574+
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
575+
// given
576+
Loan loanForProcessing = Mockito.mock(Loan.class);
577+
loanForProcessing.setId(1L);
578+
579+
JsonCommand command = Mockito.mock(JsonCommand.class);
580+
581+
// Pause period
582+
LocalDate startDate = DateUtils.getBusinessLocalDate().minusDays(2);
583+
LocalDate endDate = DateUtils.getBusinessLocalDate().plusDays(10);
584+
585+
List<LoanDelinquencyAction> delinquencyActions = new ArrayList<>();
586+
List<LoanDelinquencyActionData> effectiveDelinquency = new ArrayList<>();
587+
CollectionData loanCollectionData = CollectionData.template();
588+
589+
when(loanRepository.findOneWithNotFoundDetection(anyLong())).thenReturn(loanForProcessing);
590+
591+
when(delinquencyReadPlatformService.retrieveLoanDelinquencyActions(anyLong())).thenReturn(delinquencyActions);
592+
LoanDelinquencyAction backdatedPauseAction = Mockito.mock(LoanDelinquencyAction.class);
593+
backdatedPauseAction.setId(1L);
594+
595+
when(delinquencyActionParseAndValidator.validateAndParseUpdate(command, loanForProcessing, delinquencyActions,
596+
DateUtils.getBusinessLocalDate())).thenReturn(backdatedPauseAction);
597+
when(backdatedPauseAction.getStartDate()).thenReturn(startDate);
598+
when(backdatedPauseAction.getEndDate()).thenReturn(endDate);
599+
when(backdatedPauseAction.getAction()).thenReturn(DelinquencyAction.PAUSE);
600+
601+
when(loanDelinquencyActionRepository.saveAndFlush(backdatedPauseAction)).thenReturn(backdatedPauseAction);
602+
603+
when(delinquencyEffectivePauseHelper.calculateEffectiveDelinquencyList(delinquencyActions)).thenReturn(effectiveDelinquency);
604+
when(loanDelinquencyDomainService.getOverdueCollectionData(any(), anyList())).thenReturn(loanCollectionData);
605+
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
606+
607+
// when
608+
underTest.createDelinquencyAction(loanForProcessing.getId(), command);
609+
610+
// then
611+
// verify event is raised
612+
verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanDelinquencyRangeChangeEvent.capture());
613+
614+
Loan loanPayloadForEvent = loanDelinquencyRangeChangeEvent.getValue().get();
615+
assertEquals(loanForProcessing, loanPayloadForEvent);
616+
}
617+
501618
}

0 commit comments

Comments
 (0)