You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ad...@apache.org on 2024/10/30 12:16:47 UTC

(fineract) branch develop updated: FINERACT-2107: Interest Refund - Partial Repayment

This is an automated email from the ASF dual-hosted git repository.

adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 001d586e3 FINERACT-2107: Interest Refund - Partial Repayment
001d586e3 is described below

commit 001d586e30073671a733355cf52743988c921595
Author: Soma Sörös <so...@dpc.hu>
AuthorDate: Tue Oct 29 17:52:41 2024 +0100

    FINERACT-2107: Interest Refund - Partial Repayment
---
 .../loanproduct/calc/ProgressiveEMICalculator.java |   5 +
 .../ProgressiveLoanInterestRefundServiceImpl.java  |  69 +++--
 .../integrationtests/BaseLoanIntegrationTest.java  |   7 +-
 .../integrationtests/LoanInterestRefundTest.java   | 305 ++++++++++++++++++---
 4 files changed, 312 insertions(+), 74 deletions(-)

diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
index 97b1d3bcc..f39e5d391 100644
--- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
+++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
@@ -165,6 +165,11 @@ public final class ProgressiveEMICalculator implements EMICalculator {
             interestPeriod = repaymentPeriod.getInterestPeriods().stream()
                     .filter(ip -> targetDate.isAfter(ip.getFromDate()) && !targetDate.isAfter(ip.getDueDate())).findFirst().orElseThrow();
         }
+        scheduleModelCopy.repaymentPeriods().stream()
+                .filter(rp -> targetDate.isAfter(rp.getFromDate()) && !targetDate.isAfter(rp.getDueDate())).findFirst()
+                .ifPresent(rp -> rp.getInterestPeriods().stream()
+                        .filter(ip -> targetDate.isAfter(ip.getFromDate()) && !targetDate.isAfter(ip.getDueDate()))
+                        .reduce((one, two) -> two).ifPresent(ip -> ip.setDueDate(targetDate)));
         interestPeriod.setDueDate(adjustedTargetDate);
         int index = repaymentPeriod.getInterestPeriods().indexOf(interestPeriod);
         repaymentPeriod.getInterestPeriods().subList(index + 1, repaymentPeriod.getInterestPeriods().size()).clear();
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanInterestRefundServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanInterestRefundServiceImpl.java
index 13253ac7c..16f1cb3ec 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanInterestRefundServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanInterestRefundServiceImpl.java
@@ -18,15 +18,15 @@
  */
 package org.apache.fineract.portfolio.loanaccount.service;
 
+import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REPAYMENT;
+
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
@@ -54,53 +54,48 @@ public class ProgressiveLoanInterestRefundServiceImpl implements InterestRefundS
         return loan != null && loan.isInterestBearing() && processor.accept(loan.getTransactionProcessingStrategyCode());
     }
 
-    private static boolean omitDisbursements(LoanTransaction lt, final AtomicReference<BigDecimal> refundFinal) {
+    private static void simulateRepaymentForDisbursements(LoanTransaction lt, final AtomicReference<BigDecimal> refundFinal,
+            List<LoanTransaction> collect) {
+        collect.add(lt);
         if (lt.getTypeOf().isDisbursement() && refundFinal.get().compareTo(BigDecimal.ZERO) > 0) {
             if (lt.getAmount().compareTo(refundFinal.get()) <= 0) {
+                collect.add(
+                        new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT.getValue(), lt.getDateOf(), lt.getAmount(),
+                                BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
                 refundFinal.set(refundFinal.get().subtract(lt.getAmount()));
-                return false;
+            } else {
+                collect.add(
+                        new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT.getValue(), lt.getDateOf(), refundFinal.get(),
+                                BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
+                refundFinal.set(BigDecimal.ZERO);
             }
         }
-        return true;
-    }
-
-    private static LoanTransaction calculateReducedAmountDisbursements(LoanTransaction lt, final AtomicReference<BigDecimal> refundFinal) {
-        if (lt.getTypeOf().isDisbursement() && refundFinal.get().compareTo(BigDecimal.ZERO) > 0) {
-            LoanTransaction result = new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), lt.getTypeOf().getValue(), lt.getDateOf(),
-                    lt.getAmount().subtract(refundFinal.get()), lt.getPrincipalPortion(), lt.getInterestPortion(),
-                    lt.getFeeChargesPortion(), lt.getPenaltyChargesPortion(),
-                    lt.getOverPaymentPortion(lt.getLoan().getCurrency()).getAmount(), lt.isReversed(), lt.getPaymentDetail(),
-                    lt.getExternalId());
-            refundFinal.set(BigDecimal.ZERO);
-            return result;
-        }
-        return lt;
     }
 
     private BigDecimal totalInterest(final Loan loan, BigDecimal refundAmount, LocalDate relatedRefundTransactionDate) {
         final AtomicReference<BigDecimal> refundFinal = new AtomicReference<>(refundAmount);
-        List<LoanTransaction> transactionsToReprocess = loan.getLoanTransactions().stream().filter(lt -> !lt.isReversed()) //
-                .filter(lt -> !lt.isAccrual() && !lt.isAccrualActivity()) //
-                .filter(lt -> omitDisbursements(lt, refundFinal)) //
-                .map(lt -> calculateReducedAmountDisbursements(lt, refundFinal)).toList();
 
-        List<LoanRepaymentScheduleInstallment> installmentsToReprocess = new ArrayList<>(
-                loan.getRepaymentScheduleInstallments().stream().filter(i -> !i.isReAged() && !i.isAdditional()).toList());
-
-        ProgressiveLoanInterestScheduleModel modelAfter = processor.reprocessProgressiveLoanTransactions(loan.getDisbursementDate(),
-                transactionsToReprocess, loan.getCurrency(), installmentsToReprocess, loan.getActiveCharges()).getRight();
         BigDecimal payableInterest = BigDecimal.ZERO;
-        if (modelAfter != null && loan.getStatus().isActive()) {
-            LoanRepaymentScheduleInstallment actualInstallment = loan.getRelatedRepaymentScheduleInstallment(relatedRefundTransactionDate);
-            if (actualInstallment == null) {
-                actualInstallment = loan.getLastLoanRepaymentScheduleInstallment();
-            }
-            payableInterest = emiCalculator.getPayableDetails(modelAfter, actualInstallment.getDueDate(), relatedRefundTransactionDate)
-                    .getPayableInterest().getAmount();
+        if (loan.getLoanTransactions().stream().anyMatch(LoanTransaction::isDisbursement)) {
+            List<LoanTransaction> transactionsToReprocess = new ArrayList<>();
+            loan.getLoanTransactions().stream().filter(lt -> !lt.isReversed()) //
+                    .filter(lt -> !lt.isAccrual() && !lt.isAccrualActivity()) //
+                    .forEach(lt -> simulateRepaymentForDisbursements(lt, refundFinal, transactionsToReprocess)); //
+
+            List<LoanRepaymentScheduleInstallment> installmentsToReprocess = new ArrayList<>(
+                    loan.getRepaymentScheduleInstallments().stream().filter(i -> !i.isReAged() && !i.isAdditional()).toList());
+
+            ProgressiveLoanInterestScheduleModel modelAfter = processor.reprocessProgressiveLoanTransactions(loan.getDisbursementDate(),
+                    transactionsToReprocess, loan.getCurrency(), installmentsToReprocess, loan.getActiveCharges()).getRight();
+
+            payableInterest = installmentsToReprocess.stream() //
+                    .map(installment -> emiCalculator //
+                            .getPayableDetails(modelAfter, installment.getDueDate(), relatedRefundTransactionDate) //
+                            .getPayableInterest() //
+                            .getAmount()) //
+                    .reduce(BigDecimal.ZERO, BigDecimal::add); //
         }
-        BigDecimal paidInterest = installmentsToReprocess.stream().map(i -> i.getInterestPaid(loan.getCurrency())).filter(Objects::nonNull)
-                .map(Money::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
-        return payableInterest.add(paidInterest);
+        return payableInterest;
     }
 
     @Override
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
index 71dc80b44..3a7cd4ad9 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
@@ -295,7 +295,6 @@ public abstract class BaseLoanIntegrationTest {
                 .allowCompoundingOnEod(false)//
                 .canDefineInstallmentAmount(true)//
                 .repaymentStartDateType(1)//
-                .supportedInterestRefundTypes(List.of())//
                 .charges(List.of())//
                 .principalVariationsForBorrowerCycle(List.of())//
                 .interestRateVariationsForBorrowerCycle(List.of())//
@@ -1296,4 +1295,10 @@ public abstract class BaseLoanIntegrationTest {
 
         public static final String LAST_INSTALLMENT = "LAST_INSTALLMENT";
     }
+
+    public static class SupportedInterestRefundTypesItem {
+
+        public static final String MERCHANT_ISSUED_REFUND = "MERCHANT_ISSUED_REFUND";
+        public static final String PAYOUT_REFUND = "PAYOUT_REFUND";
+    }
 }
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanInterestRefundTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanInterestRefundTest.java
index 2cf9cc0d7..35ef80eef 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanInterestRefundTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanInterestRefundTest.java
@@ -26,7 +26,9 @@ import io.restassured.http.ContentType;
 import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
 import java.math.BigDecimal;
-import java.util.ArrayList;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
@@ -70,7 +72,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>()) //
+                            //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.9,
@@ -86,7 +88,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
                     transaction(1000.0, "Payout Refund", "22 January 2021"));
         });
@@ -99,7 +101,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>())//
+                            //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.9,
@@ -115,7 +117,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
                     transaction(1000.0, "Merchant Issued Refund", "22 January 2021"));
         });
@@ -128,7 +130,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
@@ -144,7 +146,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, //
                     transaction(1000.0, "Disbursement", "01 January 2021"), //
                     transaction(1000.0, "Payout Refund", "22 January 2021"), //
@@ -185,7 +187,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
@@ -201,7 +203,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
                     transaction(1000.0, "Merchant Issued Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
                     transaction(5.75, "Interest Refund", "22 January 2021"));
@@ -215,8 +217,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
-                            .addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
@@ -232,7 +234,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
                     transaction(1000.0, "Payout Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
                     transaction(5.75, "Interest Refund", "22 January 2021"));
@@ -246,8 +248,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
-                            .addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
@@ -263,7 +265,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
                     transaction(1000.0, "Payout Refund", "01 February 2021"), transaction(8.48, "Accrual", "01 February 2021"),
                     transaction(8.48, "Interest Refund", "01 February 2021"));
@@ -277,8 +279,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
-                            .addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
@@ -294,7 +296,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
                     transaction(87.89, "Repayment", "01 February 2021"));
         });
@@ -306,7 +308,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
                     transaction(1000.0, "Payout Refund", "09 February 2021"), transaction(87.89, "Repayment", "01 February 2021"),
                     transaction(10.50, "Interest Refund", "09 February 2021"));
@@ -320,11 +322,11 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>())//
+                            //
                             .disallowExpectedDisbursements(true)//
                             .multiDisburseLoan(true)//
-                            .maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
-                            .addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
+                            .maxTrancheCount(2).addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
@@ -341,7 +343,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(750.0, "Disbursement", "01 January 2021"),
                     transaction(250.0, "Disbursement", "01 January 2021"), transaction(1000.0, "Payout Refund", "22 January 2021"),
                     transaction(5.75, "Accrual", "22 January 2021"), transaction(5.75, "Interest Refund", "22 January 2021"));
@@ -355,9 +357,9 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>()).disallowExpectedDisbursements(true).multiDisburseLoan(true)
-                            .maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
-                            .addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
+                            .disallowExpectedDisbursements(true).multiDisburseLoan(true).maxTrancheCount(2)
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
@@ -377,7 +379,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(750.0, "Disbursement", "04 January 2021"),
                     transaction(250.0, "Disbursement", "01 January 2021"), transaction(1000.0, "Payout Refund", "22 January 2021"),
                     transaction(5.14, "Accrual", "22 January 2021"), transaction(5.14, "Interest Refund", "22 January 2021"));
@@ -391,9 +393,10 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             PostLoanProductsResponse loanProduct = loanProductHelper
                     .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
                             .daysInYearType(DaysInYearType.ACTUAL) //
-                            .supportedInterestRefundTypes(new ArrayList<>()).disallowExpectedDisbursements(true).multiDisburseLoan(true)
-                            .maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
-                            .addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
+                            .multiDisburseLoan(true) //
+                            .disallowExpectedDisbursements(true) //
+                            .maxTrancheCount(2).addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
                             .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
             );
             Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
@@ -413,7 +416,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(500.0, "Disbursement", "01 January 2021"),
                     transaction(500.0, "Disbursement", "07 January 2021"), transaction(87.82, "Repayment", "01 February 2021"));
         });
@@ -425,18 +428,248 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
             Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
 
-            logTransactions(loanId);
+            logLoanTransactions(loanId);
             verifyTransactions(loanId, transaction(500.0, "Disbursement", "01 January 2021"),
                     transaction(500.0, "Disbursement", "07 January 2021"), transaction(1000.0, "Payout Refund", "09 February 2021"),
                     transaction(87.82, "Repayment", "01 February 2021"), transaction(9.67, "Interest Refund", "09 February 2021"));
         });
     }
 
-    private void logTransactions(Long loanId) {
+    @Test
+    public void verifyUC06() {
+        AtomicReference<Long> loanIdRef = new AtomicReference<>();
+        runAt("1 December 2020", () -> {
+            PostLoanProductsResponse loanProduct = loanProductHelper
+                    .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
+                            .daysInYearType(DaysInYearType.ACTUAL) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
+                            .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
+            );
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 December 2020", 1000.0, 9.99,
+                    6, null);
+            Assertions.assertNotNull(loanId);
+            loanIdRef.set(loanId);
+            disburseLoan(loanId, BigDecimal.valueOf(1000), "1 December 2020");
+
+        });
+        runAt("14 December 2020", () -> {
+            Long loanId = loanIdRef.get();
+            PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
+                    .makeLoanRepayment("PayoutRefund", "14 December 2020", 500F, loanId.intValue());
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
+
+            logLoanTransactions(loanId);
+            verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 December 2020"), //
+                    transaction(500.0, "Payout Refund", "14 December 2020"), //
+                    transaction(1.78, "Interest Refund", "14 December 2020"));
+        });
+    }
+
+    @Test
+    public void verifyUC07() {
+        AtomicReference<Long> loanIdRef = new AtomicReference<>();
+        runAt("1 January 2021", () -> {
+            PostLoanProductsResponse loanProduct = loanProductHelper
+                    .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
+                            .daysInYearType(DaysInYearType.ACTUAL) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
+                            .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
+            );
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
+                    12, null);
+            Assertions.assertNotNull(loanId);
+            loanIdRef.set(loanId);
+            disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
+
+            GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
+            logInstallmentsOfLoanDetails(loanDetails);
+        });
+        runAt("1 February 2021", () -> {
+            Long loanId = loanIdRef.get();
+            PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment("Repayment",
+                    "1 February 2021", 87.89F, loanId.intValue());
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
+
+            logLoanTransactions(loanId);
+            verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"), //
+                    transaction(87.89, "Repayment", "01 February 2021"));
+        });
+        runAt("9 February 2021", () -> {
+            Long loanId = loanIdRef.get();
+            PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
+                    .makeLoanRepayment("PayoutRefund", "09 February 2021", 500F, loanId.intValue());
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
+
+            logLoanTransactions(loanId);
+            verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"), //
+                    transaction(87.89, "Repayment", "01 February 2021"), //
+                    transaction(500.0, "Payout Refund", "09 February 2021"), //
+                    transaction(5.35, "Interest Refund", "09 February 2021"));
+        });
+    }
+
+    @Test
+    public void verifyUC08() {
+        AtomicReference<Long> loanIdRef = new AtomicReference<>();
+        runAt("1 January 2021", () -> {
+            PostLoanProductsResponse loanProduct = loanProductHelper
+                    .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
+                            .daysInYearType(DaysInYearType.ACTUAL) //
+                            //
+                            .disallowExpectedDisbursements(true)//
+                            .multiDisburseLoan(true)//
+                            .maxTrancheCount(2).addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
+                            .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
+            );
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
+                    6, null);
+            Assertions.assertNotNull(loanId);
+            loanIdRef.set(loanId);
+            disburseLoan(loanId, BigDecimal.valueOf(250), "1 January 2021");
+            disburseLoan(loanId, BigDecimal.valueOf(750), "1 January 2021");
+        });
+        runAt("22 January 2021", () -> {
+            Long loanId = loanIdRef.get();
+            PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
+                    .makeLoanRepayment("PayoutRefund", "22 January 2021", 500F, loanId.intValue());
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
+
+            logLoanTransactions(loanId);
+            verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
+                    transaction(750.0, "Disbursement", "01 January 2021"), //
+                    transaction(500.0, "Payout Refund", "22 January 2021"), //
+                    transaction(2.88, "Interest Refund", "22 January 2021"));
+        });
+    }
+
+    @Test
+    public void verifyUC09() {
+        AtomicReference<Long> loanIdRef = new AtomicReference<>();
+        runAt("1 January 2021", () -> {
+            PostLoanProductsResponse loanProduct = loanProductHelper
+                    .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
+                            .daysInYearType(DaysInYearType.ACTUAL) //
+                            .disallowExpectedDisbursements(true).multiDisburseLoan(true).maxTrancheCount(2)
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
+                            .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
+            );
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
+                    6, null);
+            Assertions.assertNotNull(loanId);
+            loanIdRef.set(loanId);
+            disburseLoan(loanId, BigDecimal.valueOf(250), "1 January 2021");
+        });
+        runAt("7 January 2021", () -> {
+            Long loanId = loanIdRef.get();
+            disburseLoan(loanId, BigDecimal.valueOf(750), "7 January 2021");
+        });
+        runAt("22 January 2021", () -> {
+            Long loanId = loanIdRef.get();
+            PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
+                    .makeLoanRepayment("PayoutRefund", "22 January 2021", 500F, loanId.intValue());
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
+
+            logLoanTransactions(loanId);
+            verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
+                    transaction(750.0, "Disbursement", "07 January 2021"), //
+                    transaction(500.0, "Payout Refund", "22 January 2021"), //
+                    transaction(2.47, "Interest Refund", "22 January 2021"));
+        });
+    }
+
+    @Test
+    public void verifyUC10() {
+        AtomicReference<Long> loanIdRef = new AtomicReference<>();
+        runAt("1 January 2021", () -> {
+            PostLoanProductsResponse loanProduct = loanProductHelper
+                    .createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
+                            .daysInYearType(DaysInYearType.ACTUAL) //
+                            .disallowExpectedDisbursements(true).multiDisburseLoan(true).maxTrancheCount(2)
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
+                            .addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
+                            .recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
+            );
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
+                    6, null);
+            Assertions.assertNotNull(loanId);
+            loanIdRef.set(loanId);
+            disburseLoan(loanId, BigDecimal.valueOf(250), "1 January 2021");
+
+        });
+        runAt("7 January 2021", () -> {
+            Long loanId = loanIdRef.get();
+            disburseLoan(loanId, BigDecimal.valueOf(750), "7 January 2021");
+
+            GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
+            logInstallmentsOfLoanDetails(loanDetails);
+        });
+        runAt("1 July 2021", () -> {
+            Long loanId = loanIdRef.get();
+            loanTransactionHelper.makeLoanRepayment("Repayment", "1 February 2021", 171.29F, loanId.intValue());
+            loanTransactionHelper.makeLoanRepayment("Repayment", "1 March 2021", 171.29F, loanId.intValue());
+            loanTransactionHelper.makeLoanRepayment("Repayment", "1 April 2021", 171.29F, loanId.intValue());
+            loanTransactionHelper.makeLoanRepayment("Repayment", "1 May 2021", 171.29F, loanId.intValue());
+            loanTransactionHelper.makeLoanRepayment("Repayment", "1 June 2021", 171.29F, loanId.intValue());
+            loanTransactionHelper.makeLoanRepayment("Repayment", "1 July 2021", 171.32F, loanId.intValue());
+
+            logLoanTransactions(loanId);
+            verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
+                    transaction(750.0, "Disbursement", "07 January 2021"), //
+                    transaction(171.29, "Repayment", "01 February 2021"), //
+                    transaction(171.29, "Repayment", "01 March 2021"), //
+                    transaction(171.29, "Repayment", "01 April 2021"), //
+                    transaction(171.29, "Repayment", "01 May 2021"), //
+                    transaction(171.29, "Repayment", "01 June 2021"), //
+                    transaction(171.32, "Repayment", "01 July 2021") //
+            ); //
+        });
+        runAt("11 July 2021", () -> {
+            Long loanId = loanIdRef.get();
+            PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
+                    .makeLoanRepayment("PayoutRefund", "11 July 2021", 500.0F, loanId.intValue());
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
+            Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
+
+            logLoanTransactions(loanId);
+            verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
+                    transaction(750.0, "Disbursement", "07 January 2021"), //
+                    transaction(171.29, "Repayment", "01 February 2021"), //
+                    transaction(171.29, "Repayment", "01 March 2021"), //
+                    transaction(171.29, "Repayment", "01 April 2021"), //
+                    transaction(171.29, "Repayment", "01 May 2021"), //
+                    transaction(171.29, "Repayment", "01 June 2021"), //
+                    transaction(171.32, "Repayment", "01 July 2021"), //
+                    transaction(500.0, "Payout Refund", "11 July 2021"), //
+                    transaction(20.41, "Interest Refund", "11 July 2021")); //
+        });
+    }
+
+    private void logInstallmentsOfLoanDetails(GetLoansLoanIdResponse loanDetails) {
+        log.info("index, dueDate, principal, fee, penalty, interest");
+        if (loanDetails != null && loanDetails.getRepaymentSchedule() != null && loanDetails.getRepaymentSchedule().getPeriods() != null) {
+            loanDetails.getRepaymentSchedule().getPeriods()
+                    .forEach(period -> log.info("{}, \"{}\", {}, {}, {}, {}", period.getPeriod(),
+                            DateTimeFormatter.ofPattern(DATETIME_PATTERN, Locale.ENGLISH)
+                                    .format(Objects.requireNonNull(period.getDueDate())),
+                            period.getPrincipalDue(), period.getFeeChargesDue(), period.getPenaltyChargesDue(), period.getInterestDue()));
+        }
+    }
+
+    private void logLoanTransactions(Long loanId) {
         GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
-        assert loanDetails.getTransactions() != null;
-        loanDetails.getTransactions()
-                .forEach(tr -> log.info("Transaction {}  {}  {} ", tr.getType().getValue(), tr.getDate(), tr.getAmount()));
+        if (loanDetails.getTransactions() != null) {
+            loanDetails.getTransactions()
+                    .forEach(tr -> log.info("Transaction {}  {}  {} ", tr.getType().getValue(), tr.getDate(), tr.getAmount()));
+        }
     }
 
 }