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 &gt; existing.startDate AND parsed.endDate &lt; existing.endDate)
+     *
+     *  existing       |------------|
+     *  parsed               |----------------|
+     *
+     *  we also  have an overlap when
+     *  (parsed.startDate &gt; existing.startDate AND parsed.startDate &lt; 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 {