FINERACT-1992 Fixing consecutive pause periods
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidator.java
index 163ee27..5627495 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidator.java
@@ -162,11 +162,38 @@
}
}
- private boolean isOverlapping(LoanDelinquencyAction parsedDelinquencyAction, LoanDelinquencyActionData ldad) {
- return ((!parsedDelinquencyAction.getStartDate().isAfter(ldad.getStartDate())
- && !ldad.getStartDate().isAfter(parsedDelinquencyAction.getEndDate()))
- || (!parsedDelinquencyAction.getStartDate().isAfter(ldad.getEndDate())
- && !ldad.getEndDate().isAfter(parsedDelinquencyAction.getEndDate())));
+ /**
+ * <pre>
+ * we have an overlap when
+ * (parsed.endDate > existing.startDate AND parsed.endDate < existing.endDate)
+ *
+ * existing |------------|
+ * parsed |----------------|
+ *
+ * we also have an overlap when
+ * (parsed.startDate > existing.startDate AND parsed.startDate < existing.endDate)
+ *
+ * existing |------------|
+ * parsed |----------------|
+ *
+ * There is no overlap like when they are right after each other:
+ *
+ * existing |------------|
+ * parsed |----------------|
+ *
+ * or
+ *
+ * existing |------------|
+ * parsed |-------------|
+ * </pre>
+ *
+ * @param parsed
+ * @param existing
+ * @return
+ */
+ private boolean isOverlapping(LoanDelinquencyAction parsed, LoanDelinquencyActionData existing) {
+ return (parsed.getEndDate().isAfter(existing.getStartDate()) && parsed.getEndDate().isBefore(existing.getEndDate()))
+ || (parsed.getStartDate().isAfter(existing.getStartDate()) && parsed.getStartDate().isBefore(existing.getEndDate()));
}
@org.jetbrains.annotations.NotNull
diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidatorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidatorTest.java
index cc8ee21..3401123 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidatorTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidatorTest.java
@@ -112,32 +112,6 @@
}
@Test
- public void testNewPauseEndIsTheSameAsExistingPauseStart() throws JsonProcessingException {
- Loan loan = Mockito.mock(Loan.class);
- Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
-
- List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "15 September 2022", "22 September 2022"));
- JsonCommand command = delinquencyAction("pause", "09 September 2022", "15 September 2022");
-
- assertPlatformValidationException("Delinquency pause period cannot overlap with another pause period",
- "loan-delinquency-action-overlapping",
- () -> underTest.validateAndParseUpdate(command, loan, existing, localDate("09 September 2022")));
- }
-
- @Test
- public void testNewPauseEndIsTheSameAsExistingPauseEnd() throws JsonProcessingException {
- Loan loan = Mockito.mock(Loan.class);
- Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
-
- List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "15 September 2022", "22 September 2022"));
- JsonCommand command = delinquencyAction("pause", "22 September 2022", "25 September 2022");
-
- assertPlatformValidationException("Delinquency pause period cannot overlap with another pause period",
- "loan-delinquency-action-overlapping",
- () -> underTest.validateAndParseUpdate(command, loan, existing, localDate("09 September 2022")));
- }
-
- @Test
public void testNewPauseEndIsOverlappingWithExistingPause() throws JsonProcessingException {
Loan loan = Mockito.mock(Loan.class);
Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
@@ -276,6 +250,57 @@
.validateAndParseUpdate(delinquencyAction("resume", null, null), loan, List.of(), localDate("09 September 2022")));
}
+ @Test
+ public void testNewPausePeriodStartingOnExistingEndDate() throws JsonProcessingException {
+ Loan loan = Mockito.mock(Loan.class);
+ Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
+
+ JsonCommand command = delinquencyAction("pause", "18 September 2022", "20 September 2022");
+
+ List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "15 September 2022", "18 September 2022"));
+
+ LoanDelinquencyAction parsedDelinquencyAction = underTest.validateAndParseUpdate(command, loan, existing,
+ localDate("18 September 2022"));
+ Assertions.assertEquals(PAUSE, parsedDelinquencyAction.getAction());
+ Assertions.assertEquals(localDate("18 September 2022"), parsedDelinquencyAction.getStartDate());
+ Assertions.assertEquals(localDate("20 September 2022"), parsedDelinquencyAction.getEndDate());
+ }
+
+ @Test
+ public void testNewPauseEndingOnExistingStartDate() throws JsonProcessingException {
+ Loan loan = Mockito.mock(Loan.class);
+ Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
+
+ JsonCommand command = delinquencyAction("pause", "18 September 2022", "20 September 2022");
+
+ List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "20 September 2022", "25 September 2022"));
+
+ LoanDelinquencyAction parsedDelinquencyAction = underTest.validateAndParseUpdate(command, loan, existing,
+ localDate("18 September 2022"));
+ Assertions.assertEquals(PAUSE, parsedDelinquencyAction.getAction());
+ Assertions.assertEquals(localDate("18 September 2022"), parsedDelinquencyAction.getStartDate());
+ Assertions.assertEquals(localDate("20 September 2022"), parsedDelinquencyAction.getEndDate());
+ }
+
+ @Test
+ public void testNewPausePeriodStartingOnExistingEffectiveEndDate() throws JsonProcessingException {
+ Loan loan = Mockito.mock(Loan.class);
+ Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
+
+ JsonCommand command = delinquencyAction("pause", "18 September 2022", "20 September 2022");
+
+ List<LoanDelinquencyAction> existing = List.of(//
+ loanDelinquencyAction(PAUSE, "15 September 2022", "20 September 2022"), //
+ loanDelinquencyAction(RESUME, "18 September 2022") //
+ );
+
+ LoanDelinquencyAction parsedDelinquencyAction = underTest.validateAndParseUpdate(command, loan, existing,
+ localDate("18 September 2022"));
+ Assertions.assertEquals(PAUSE, parsedDelinquencyAction.getAction());
+ Assertions.assertEquals(localDate("18 September 2022"), parsedDelinquencyAction.getStartDate());
+ Assertions.assertEquals(localDate("20 September 2022"), parsedDelinquencyAction.getEndDate());
+ }
+
@NotNull
private JsonCommand delinquencyAction(@Nullable String action, @Nullable String startDate, @Nullable String endDate)
throws JsonProcessingException {