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 f5d9a3a02 FINERACT-1981: Update Payable Interest Calculation For 
LoanSummaryData
f5d9a3a02 is described below

commit f5d9a3a025628eb8b3654a4676fc212a90629fb4
Author: Soma Sörös <[email protected]>
AuthorDate: Wed Nov 20 17:18:46 2024 +0100

    FINERACT-1981: Update Payable Interest Calculation For LoanSummaryData
---
 .../loanaccount/data/LoanSummaryData.java          | 174 --------------------
 .../loan/LoanBusinessEventSerializer.java          |  15 +-
 .../api/InternalLoanInformationApiResource.java    |  21 ---
 .../loanaccount/api/LoansApiResource.java          |  13 +-
 .../service/CommonLoanSummaryDataProvider.java     | 173 ++++++++++++++++++++
 .../service/CumulativeLoanSummaryDataProvider.java |  90 +++++++++++
 .../service/LoanSummaryDataProvider.java           |  47 ++++++
 .../service/LoanSummaryProviderDelegate.java       |  35 ++++
 .../ProgressiveLoanSummaryDataProvider.java        | 110 +++++++++++++
 ...PaymentAllocationLoanRepaymentScheduleTest.java |  22 +++
 .../integrationtests/LoanPrepayAmountTest.java     |  61 +++++++
 .../LoanRefundTransactionTest.java                 | 177 ---------------------
 12 files changed, 558 insertions(+), 380 deletions(-)

diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanSummaryData.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanSummaryData.java
index de2f68cb0..b1e147a5d 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanSummaryData.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanSummaryData.java
@@ -20,19 +20,10 @@ package org.apache.fineract.portfolio.loanaccount.data;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
-import java.util.Collection;
-import java.util.Optional;
 import lombok.Builder;
 import lombok.Data;
 import lombok.experimental.Accessors;
-import org.apache.fineract.infrastructure.core.service.DateUtils;
-import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
-import org.apache.fineract.organisation.monetary.domain.Money;
-import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
-import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
-import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
 
 /**
  * Immutable data object representing loan summary information.
@@ -105,169 +96,4 @@ public class LoanSummaryData {
     private BigDecimal totalUnpaidPayableDueInterest;
     private BigDecimal totalUnpaidPayableNotDueInterest;
 
-    public static LoanSummaryData withTransactionAmountsSummary(final 
LoanSummaryData defaultSummaryData,
-            final LoanScheduleData repaymentSchedule, final 
Collection<LoanTransactionBalance> loanTransactionBalances) {
-        final LocalDate businessDate = DateUtils.getBusinessLocalDate();
-
-        BigDecimal totalMerchantRefund = BigDecimal.ZERO;
-        BigDecimal totalMerchantRefundReversed = BigDecimal.ZERO;
-        BigDecimal totalPayoutRefund = BigDecimal.ZERO;
-        BigDecimal totalPayoutRefundReversed = BigDecimal.ZERO;
-        BigDecimal totalGoodwillCredit = BigDecimal.ZERO;
-        BigDecimal totalGoodwillCreditReversed = BigDecimal.ZERO;
-        BigDecimal totalChargeAdjustment = BigDecimal.ZERO;
-        BigDecimal totalChargeAdjustmentReversed = BigDecimal.ZERO;
-        BigDecimal totalChargeback = BigDecimal.ZERO;
-        BigDecimal totalCreditBalanceRefund = BigDecimal.ZERO;
-        BigDecimal totalCreditBalanceRefundReversed = BigDecimal.ZERO;
-        BigDecimal totalRepaymentTransaction = BigDecimal.ZERO;
-        BigDecimal totalRepaymentTransactionReversed = BigDecimal.ZERO;
-        BigDecimal totalInterestPaymentWaiver = BigDecimal.ZERO;
-        BigDecimal totalInterestRefund = BigDecimal.ZERO;
-        BigDecimal totalUnpaidPayableDueInterest = BigDecimal.ZERO;
-        BigDecimal totalUnpaidPayableNotDueInterest = BigDecimal.ZERO;
-
-        totalChargeAdjustment = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
-                LoanTransactionType.CHARGE_ADJUSTMENT.getValue());
-        totalChargeAdjustmentReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
-                LoanTransactionType.CHARGE_ADJUSTMENT.getValue());
-
-        totalChargeback = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.CHARGEBACK.getValue());
-
-        totalCreditBalanceRefund = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
-                LoanTransactionType.CREDIT_BALANCE_REFUND.getValue());
-        totalCreditBalanceRefundReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
-                LoanTransactionType.CREDIT_BALANCE_REFUND.getValue());
-
-        totalGoodwillCredit = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.GOODWILL_CREDIT.getValue());
-        totalGoodwillCreditReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
-                LoanTransactionType.GOODWILL_CREDIT.getValue());
-
-        totalInterestRefund = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.INTEREST_REFUND.getValue());
-
-        totalInterestPaymentWaiver = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
-                LoanTransactionType.INTEREST_PAYMENT_WAIVER.getValue());
-
-        totalMerchantRefund = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
-                LoanTransactionType.MERCHANT_ISSUED_REFUND.getValue());
-        totalMerchantRefundReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
-                LoanTransactionType.MERCHANT_ISSUED_REFUND.getValue());
-
-        totalPayoutRefund = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.PAYOUT_REFUND.getValue());
-        totalPayoutRefundReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
-                LoanTransactionType.PAYOUT_REFUND.getValue());
-
-        totalRepaymentTransaction = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.REPAYMENT.getValue())
-                
.add(fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.DOWN_PAYMENT.getValue()));
-        totalRepaymentTransactionReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
-                LoanTransactionType.REPAYMENT.getValue());
-
-        if (repaymentSchedule != null) {
-            // Outstanding Interest on Past due installments
-            totalUnpaidPayableDueInterest = 
computeTotalUnpaidPayableDueInterestAmount(repaymentSchedule.getPeriods(), 
businessDate);
-
-            // Accumulated daily interest of the current Installment period
-            totalUnpaidPayableNotDueInterest = 
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(repaymentSchedule.getPeriods(),
-                    businessDate, defaultSummaryData.currency);
-        }
-
-        return 
LoanSummaryData.builder().currency(defaultSummaryData.currency).principalDisbursed(defaultSummaryData.principalDisbursed)
-                
.principalAdjustments(defaultSummaryData.principalAdjustments).principalPaid(defaultSummaryData.principalPaid)
-                
.principalWrittenOff(defaultSummaryData.principalWrittenOff).principalOutstanding(defaultSummaryData.principalOutstanding)
-                
.principalOverdue(defaultSummaryData.principalOverdue).interestCharged(defaultSummaryData.interestCharged)
-                
.interestPaid(defaultSummaryData.interestPaid).interestWaived(defaultSummaryData.interestWaived)
-                
.interestWrittenOff(defaultSummaryData.interestWrittenOff).interestOutstanding(defaultSummaryData.interestOutstanding)
-                
.interestOverdue(defaultSummaryData.interestOverdue).feeChargesCharged(defaultSummaryData.feeChargesCharged)
-                .feeAdjustments(defaultSummaryData.feeAdjustments)
-                
.feeChargesDueAtDisbursementCharged(defaultSummaryData.feeChargesDueAtDisbursementCharged)
-                
.feeChargesPaid(defaultSummaryData.feeChargesPaid).feeChargesWaived(defaultSummaryData.feeChargesWaived)
-                .feeChargesWrittenOff(defaultSummaryData.feeChargesWrittenOff)
-                
.feeChargesOutstanding(defaultSummaryData.feeChargesOutstanding).feeChargesOverdue(defaultSummaryData.feeChargesOverdue)
-                
.penaltyChargesCharged(defaultSummaryData.penaltyChargesCharged).penaltyAdjustments(defaultSummaryData.penaltyAdjustments)
-                
.penaltyChargesPaid(defaultSummaryData.penaltyChargesPaid).penaltyChargesWaived(defaultSummaryData.penaltyChargesWaived)
-                
.penaltyChargesWrittenOff(defaultSummaryData.penaltyChargesWrittenOff)
-                
.penaltyChargesOutstanding(defaultSummaryData.penaltyChargesOutstanding)
-                
.penaltyChargesOverdue(defaultSummaryData.penaltyChargesOverdue)
-                
.totalExpectedRepayment(defaultSummaryData.totalExpectedRepayment).totalRepayment(defaultSummaryData.totalRepayment)
-                
.totalExpectedCostOfLoan(defaultSummaryData.totalExpectedCostOfLoan).totalCostOfLoan(defaultSummaryData.totalCostOfLoan)
-                
.totalWaived(defaultSummaryData.totalWaived).totalWrittenOff(defaultSummaryData.totalWrittenOff)
-                
.totalOutstanding(defaultSummaryData.totalOutstanding).totalOverdue(defaultSummaryData.totalOverdue)
-                
.overdueSinceDate(defaultSummaryData.overdueSinceDate).writeoffReasonId(defaultSummaryData.writeoffReasonId)
-                
.writeoffReason(defaultSummaryData.writeoffReason).totalRecovered(defaultSummaryData.totalRecovered)
-                
.chargeOffReasonId(defaultSummaryData.chargeOffReasonId).chargeOffReason(defaultSummaryData.chargeOffReason)
-                
.totalMerchantRefund(totalMerchantRefund).totalMerchantRefundReversed(totalMerchantRefundReversed)
-                
.totalPayoutRefund(totalPayoutRefund).totalPayoutRefundReversed(totalPayoutRefundReversed)
-                
.totalGoodwillCredit(totalGoodwillCredit).totalGoodwillCreditReversed(totalGoodwillCreditReversed)
-                
.totalChargeAdjustment(totalChargeAdjustment).totalChargeAdjustmentReversed(totalChargeAdjustmentReversed)
-                
.totalChargeback(totalChargeback).totalCreditBalanceRefund(totalCreditBalanceRefund)
-                
.totalCreditBalanceRefundReversed(totalCreditBalanceRefundReversed).totalRepaymentTransaction(totalRepaymentTransaction)
-                
.totalRepaymentTransactionReversed(totalRepaymentTransactionReversed).totalInterestPaymentWaiver(totalInterestPaymentWaiver)
-                .totalUnpaidPayableDueInterest(totalUnpaidPayableDueInterest)
-                
.totalUnpaidPayableNotDueInterest(totalUnpaidPayableNotDueInterest).totalInterestRefund(totalInterestRefund).build();
-    }
-
-    private static BigDecimal fetchLoanTransactionBalanceByType(final 
Collection<LoanTransactionBalance> loanTransactionBalances,
-            final Integer transactionType) {
-        final Optional<LoanTransactionBalance> optLoanTransactionBalance = 
loanTransactionBalances.stream()
-                .filter(balance -> 
balance.getTransactionType().equals(transactionType) && 
!balance.isReversed()).findFirst();
-        return optLoanTransactionBalance.isPresent() ? 
optLoanTransactionBalance.get().getAmount() : BigDecimal.ZERO;
-    }
-
-    private static BigDecimal fetchLoanTransactionBalanceReversedByType(final 
Collection<LoanTransactionBalance> loanTransactionBalances,
-            final Integer transactionType) {
-        final Optional<LoanTransactionBalance> optLoanTransactionBalance = 
loanTransactionBalances.stream()
-                .filter(balance -> 
balance.getTransactionType().equals(transactionType) && balance.isReversed()
-                        && balance.isManuallyAdjustedOrReversed())
-                .findFirst();
-        return optLoanTransactionBalance.isPresent() ? 
optLoanTransactionBalance.get().getAmount() : BigDecimal.ZERO;
-    }
-
-    public static LoanSummaryData withOnlyCurrencyData(CurrencyData 
currencyData) {
-        return LoanSummaryData.builder().currency(currencyData).build();
-    }
-
-    private static BigDecimal 
computeTotalUnpaidPayableDueInterestAmount(Collection<LoanSchedulePeriodData> 
periods,
-            final LocalDate businessDate) {
-        return periods.stream().filter(period -> 
!period.getDownPaymentPeriod() && businessDate.compareTo(period.getDueDate()) 
>= 0)
-                .map(period -> 
period.getInterestOutstanding()).reduce(BigDecimal.ZERO, BigDecimal::add);
-    }
-
-    private static BigDecimal 
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(final 
Collection<LoanSchedulePeriodData> periods,
-            final LocalDate businessDate, final CurrencyData currency) {
-        // Find the current Period (If exists one) based on the Business date
-        final Optional<LoanSchedulePeriodData> optCurrentPeriod = 
periods.stream()
-                .filter(period -> !period.getDownPaymentPeriod() && 
period.isActualPeriodForNotDuePayableCalculation(businessDate))
-                .findFirst();
-
-        if (optCurrentPeriod.isPresent()) {
-            final LoanSchedulePeriodData currentPeriod = 
optCurrentPeriod.get();
-            final long remainingDays = currentPeriod.getDaysInPeriod()
-                    - 
DateUtils.getDifferenceInDays(currentPeriod.getFromDate(), businessDate);
-
-            return computeAccruedInterestTillDay(currentPeriod, remainingDays, 
currency);
-        }
-        // Default value equal to Zero
-        return BigDecimal.ZERO;
-    }
-
-    public static BigDecimal computeAccruedInterestTillDay(final 
LoanSchedulePeriodData period, final long untilDay,
-            final CurrencyData currency) {
-        Integer remainingDays = period.getDaysInPeriod();
-        BigDecimal totalAccruedInterest = BigDecimal.ZERO;
-        while (remainingDays > untilDay) {
-            final BigDecimal accruedInterest = 
period.getInterestDue().subtract(totalAccruedInterest)
-                    .divide(BigDecimal.valueOf(remainingDays), 
MoneyHelper.getMathContext());
-            totalAccruedInterest = totalAccruedInterest.add(accruedInterest);
-            remainingDays--;
-        }
-
-        totalAccruedInterest = 
totalAccruedInterest.subtract(period.getInterestPaid()).subtract(period.getInterestWaived());
-        if (MathUtil.isLessThanZero(totalAccruedInterest)) {
-            // Set Zero If the Interest Paid + Waived is greather than 
Interest Accrued
-            totalAccruedInterest = BigDecimal.ZERO;
-        }
-
-        return Money.of(currency, totalAccruedInterest).getAmount();
-    }
-
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java
index 36cfe8637..ef8588c6c 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java
@@ -35,11 +35,13 @@ import 
org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
 import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
-import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryBalancesRepository;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
 import 
org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
 import 
org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
+import 
org.apache.fineract.portfolio.loanaccount.service.LoanSummaryDataProvider;
+import 
org.apache.fineract.portfolio.loanaccount.service.LoanSummaryProviderDelegate;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
 @Component
@@ -52,6 +54,8 @@ public class LoanBusinessEventSerializer implements 
BusinessEventSerializer {
     private final DelinquencyReadPlatformService 
delinquencyReadPlatformService;
     private final LoanInstallmentLevelDelinquencyEventProducer 
installmentLevelDelinquencyEventProducer;
     private final LoanSummaryBalancesRepository loanSummaryBalancesRepository;
+    @Lazy
+    private final LoanSummaryProviderDelegate loanSummaryProviderDelegate;
 
     @Override
     public <T> boolean canSerialize(BusinessEvent<T> event) {
@@ -74,12 +78,15 @@ public class LoanBusinessEventSerializer implements 
BusinessEventSerializer {
         CollectionData delinquentData = 
delinquencyReadPlatformService.calculateLoanCollectionData(loanId);
         data.setDelinquent(delinquentData);
 
+        LoanSummaryDataProvider loanSummaryDataProvider = 
loanSummaryProviderDelegate
+                
.resolveLoanSummaryDataProvider(data.getTransactionProcessingStrategyCode());
+
         if (data.getSummary() != null) {
-            
data.setSummary(LoanSummaryData.withTransactionAmountsSummary(data.getSummary(),
 data.getRepaymentSchedule(),
-                    
loanSummaryBalancesRepository.retrieveLoanSummaryBalancesByTransactionType(loanId,
+            
data.setSummary(loanSummaryDataProvider.withTransactionAmountsSummary(event.get(),
 data.getSummary(),
+                    data.getRepaymentSchedule(), 
loanSummaryBalancesRepository.retrieveLoanSummaryBalancesByTransactionType(loanId,
                             LoanApiConstants.LOAN_SUMMARY_TRANSACTION_TYPES)));
         } else {
-            
data.setSummary(LoanSummaryData.withOnlyCurrencyData(data.getCurrency()));
+            
data.setSummary(loanSummaryDataProvider.withOnlyCurrencyData(data.getCurrency()));
         }
 
         List<LoanInstallmentDelinquencyBucketDataV1> 
installmentsDelinquencyData = installmentLevelDelinquencyEventProducer
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java
index 84785072d..ee37e4972 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java
@@ -27,7 +27,6 @@ import com.google.gson.Gson;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
@@ -43,7 +42,6 @@ import 
org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
 import org.apache.fineract.infrastructure.core.boot.FineractProfiles;
 import 
org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
 import 
org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
-import org.apache.fineract.portfolio.loanaccount.data.LoanRefundRequestData;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
@@ -158,23 +156,4 @@ public class InternalLoanInformationApiResource implements 
InitializingBean {
         final Loan loan = 
loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
         return 
advancedPaymentDataMapper.mapLoanPaymentAllocationRule(loan.getPaymentAllocationRules());
     }
-
-    @POST
-    @Path("{loanId}/apply-interest-refund")
-    @Consumes({ MediaType.APPLICATION_JSON })
-    @Produces({ MediaType.APPLICATION_JSON })
-    @SuppressFBWarnings("SLF4J_SIGN_ONLY_FORMAT")
-    public Long applyInterestRefundToLoan(@Context final UriInfo uriInfo, 
@PathParam("loanId") Long loanId,
-            final String apiRequestBodyAsJson) {
-        
log.warn("------------------------------------------------------------");
-        log.warn("                                                            
");
-        log.warn("    Apply Loan Transaction to Interest Refund loanId {} ", 
loanId);
-        log.warn("                                                            
");
-        
log.warn("------------------------------------------------------------");
-        LoanRefundRequestData loanRefundRequestData = 
gson.fromJson(apiRequestBodyAsJson, LoanRefundRequestData.class);
-        final Loan loan = 
loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
-        final LoanTransaction loanTransaction = 
loanAccountDomainService.applyInterestRefund(loan, loanRefundRequestData);
-        return loanTransaction.getId();
-    }
-
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
index c4d494910..9e909840d 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
@@ -127,7 +127,6 @@ import 
org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanApprovalData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
 import 
org.apache.fineract.portfolio.loanaccount.data.LoanCollateralManagementData;
-import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
 import org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData;
@@ -150,6 +149,8 @@ import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanTermV
 import 
org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoReadPlatformService;
 import 
org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
 import 
org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
+import 
org.apache.fineract.portfolio.loanaccount.service.LoanSummaryDataProvider;
+import 
org.apache.fineract.portfolio.loanaccount.service.LoanSummaryProviderDelegate;
 import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
 import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
 import 
org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData;
@@ -289,6 +290,7 @@ public class LoansApiResource {
     private final LoanSummaryBalancesRepository loanSummaryBalancesRepository;
     private final ClientReadPlatformService clientReadPlatformService;
     private final LoanTermVariationsRepository loanTermVariationsRepository;
+    private final LoanSummaryProviderDelegate loanSummaryProviderDelegate;
 
     /*
      * This template API is used for loan approval, ideally this should be 
invoked on loan that are pending for
@@ -1115,9 +1117,12 @@ public class LoansApiResource {
 
         // updating summary with transaction amounts summary
         if (loanBasicDetails.getSummary() != null) {
-            
loanBasicDetails.setSummary(LoanSummaryData.withTransactionAmountsSummary(loanBasicDetails.getSummary(),
 repaymentSchedule,
-                    
loanSummaryBalancesRepository.retrieveLoanSummaryBalancesByTransactionType(loanBasicDetails.getId(),
-                            LoanApiConstants.LOAN_SUMMARY_TRANSACTION_TYPES)));
+            LoanSummaryDataProvider loanSummaryDataProvider = 
loanSummaryProviderDelegate
+                    
.resolveLoanSummaryDataProvider(loanBasicDetails.getTransactionProcessingStrategyCode());
+            loanBasicDetails.setSummary(
+                    
loanSummaryDataProvider.withTransactionAmountsSummary(loanBasicDetails.getId(), 
loanBasicDetails.getSummary(),
+                            repaymentSchedule, 
loanSummaryBalancesRepository.retrieveLoanSummaryBalancesByTransactionType(
+                                    loanBasicDetails.getId(), 
LoanApiConstants.LOAN_SUMMARY_TRANSACTION_TYPES)));
         }
 
         final LoanAccountData loanAccount = 
loanBasicDetails.associationsAndTemplate(repaymentSchedule, loanRepayments, 
charges,
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CommonLoanSummaryDataProvider.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CommonLoanSummaryDataProvider.java
new file mode 100644
index 000000000..6e1ce2dab
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CommonLoanSummaryDataProvider.java
@@ -0,0 +1,173 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Collection;
+import java.util.Optional;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionBalance;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
+
+public abstract class CommonLoanSummaryDataProvider implements 
LoanSummaryDataProvider {
+
+    @Override
+    public LoanSummaryData withTransactionAmountsSummary(Loan loan, 
LoanSummaryData defaultSummaryData, LoanScheduleData repaymentSchedule,
+            Collection<LoanTransactionBalance> loanTransactionBalances) {
+        final LocalDate businessDate = DateUtils.getBusinessLocalDate();
+
+        BigDecimal totalMerchantRefund = BigDecimal.ZERO;
+        BigDecimal totalMerchantRefundReversed = BigDecimal.ZERO;
+        BigDecimal totalPayoutRefund = BigDecimal.ZERO;
+        BigDecimal totalPayoutRefundReversed = BigDecimal.ZERO;
+        BigDecimal totalGoodwillCredit = BigDecimal.ZERO;
+        BigDecimal totalGoodwillCreditReversed = BigDecimal.ZERO;
+        BigDecimal totalChargeAdjustment = BigDecimal.ZERO;
+        BigDecimal totalChargeAdjustmentReversed = BigDecimal.ZERO;
+        BigDecimal totalChargeback = BigDecimal.ZERO;
+        BigDecimal totalCreditBalanceRefund = BigDecimal.ZERO;
+        BigDecimal totalCreditBalanceRefundReversed = BigDecimal.ZERO;
+        BigDecimal totalRepaymentTransaction = BigDecimal.ZERO;
+        BigDecimal totalRepaymentTransactionReversed = BigDecimal.ZERO;
+        BigDecimal totalInterestPaymentWaiver = BigDecimal.ZERO;
+        BigDecimal totalInterestRefund = BigDecimal.ZERO;
+        BigDecimal totalUnpaidPayableDueInterest = BigDecimal.ZERO;
+        BigDecimal totalUnpaidPayableNotDueInterest = BigDecimal.ZERO;
+
+        totalChargeAdjustment = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
+                LoanTransactionType.CHARGE_ADJUSTMENT.getValue());
+        totalChargeAdjustmentReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
+                LoanTransactionType.CHARGE_ADJUSTMENT.getValue());
+
+        totalChargeback = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.CHARGEBACK.getValue());
+
+        totalCreditBalanceRefund = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
+                LoanTransactionType.CREDIT_BALANCE_REFUND.getValue());
+        totalCreditBalanceRefundReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
+                LoanTransactionType.CREDIT_BALANCE_REFUND.getValue());
+
+        totalGoodwillCredit = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.GOODWILL_CREDIT.getValue());
+        totalGoodwillCreditReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
+                LoanTransactionType.GOODWILL_CREDIT.getValue());
+
+        totalInterestRefund = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.INTEREST_REFUND.getValue());
+
+        totalInterestPaymentWaiver = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
+                LoanTransactionType.INTEREST_PAYMENT_WAIVER.getValue());
+
+        totalMerchantRefund = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
+                LoanTransactionType.MERCHANT_ISSUED_REFUND.getValue());
+        totalMerchantRefundReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
+                LoanTransactionType.MERCHANT_ISSUED_REFUND.getValue());
+
+        totalPayoutRefund = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.PAYOUT_REFUND.getValue());
+        totalPayoutRefundReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
+                LoanTransactionType.PAYOUT_REFUND.getValue());
+
+        totalRepaymentTransaction = 
fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.REPAYMENT.getValue())
+                
.add(fetchLoanTransactionBalanceByType(loanTransactionBalances, 
LoanTransactionType.DOWN_PAYMENT.getValue()));
+        totalRepaymentTransactionReversed = 
fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
+                LoanTransactionType.REPAYMENT.getValue());
+
+        if (repaymentSchedule != null) {
+            // Outstanding Interest on Past due installments
+            totalUnpaidPayableDueInterest = 
computeTotalUnpaidPayableDueInterestAmount(repaymentSchedule.getPeriods(), 
businessDate);
+
+            // Accumulated daily interest of the current Installment period
+            totalUnpaidPayableNotDueInterest = 
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(loan,
+                    repaymentSchedule.getPeriods(), businessDate, 
defaultSummaryData.getCurrency());
+        }
+
+        return 
LoanSummaryData.builder().currency(defaultSummaryData.getCurrency())
+                .principalDisbursed(defaultSummaryData.getPrincipalDisbursed())
+                
.principalAdjustments(defaultSummaryData.getPrincipalAdjustments()).principalPaid(defaultSummaryData.getPrincipalPaid())
+                
.principalWrittenOff(defaultSummaryData.getPrincipalWrittenOff())
+                
.principalOutstanding(defaultSummaryData.getPrincipalOutstanding())
+                
.principalOverdue(defaultSummaryData.getPrincipalOverdue()).interestCharged(defaultSummaryData.getInterestCharged())
+                
.interestPaid(defaultSummaryData.getInterestPaid()).interestWaived(defaultSummaryData.getInterestWaived())
+                .interestWrittenOff(defaultSummaryData.getInterestWrittenOff())
+                
.interestOutstanding(defaultSummaryData.getInterestOutstanding()).interestOverdue(defaultSummaryData.getInterestOverdue())
+                
.feeChargesCharged(defaultSummaryData.getFeeChargesCharged()).feeAdjustments(defaultSummaryData.getFeeAdjustments())
+                
.feeChargesDueAtDisbursementCharged(defaultSummaryData.getFeeChargesDueAtDisbursementCharged())
+                
.feeChargesPaid(defaultSummaryData.getFeeChargesPaid()).feeChargesWaived(defaultSummaryData.getFeeChargesWaived())
+                
.feeChargesWrittenOff(defaultSummaryData.getFeeChargesWrittenOff())
+                
.feeChargesOutstanding(defaultSummaryData.getFeeChargesOutstanding())
+                .feeChargesOverdue(defaultSummaryData.getFeeChargesOverdue())
+                
.penaltyChargesCharged(defaultSummaryData.getPenaltyChargesCharged())
+                .penaltyAdjustments(defaultSummaryData.getPenaltyAdjustments())
+                .penaltyChargesPaid(defaultSummaryData.getPenaltyChargesPaid())
+                
.penaltyChargesWaived(defaultSummaryData.getPenaltyChargesWaived())
+                
.penaltyChargesWrittenOff(defaultSummaryData.getPenaltyChargesWrittenOff())
+                
.penaltyChargesOutstanding(defaultSummaryData.getPenaltyChargesOutstanding())
+                
.penaltyChargesOverdue(defaultSummaryData.getPenaltyChargesOverdue())
+                
.totalExpectedRepayment(defaultSummaryData.getTotalExpectedRepayment())
+                .totalRepayment(defaultSummaryData.getTotalRepayment())
+                
.totalExpectedCostOfLoan(defaultSummaryData.getTotalExpectedCostOfLoan())
+                
.totalCostOfLoan(defaultSummaryData.getTotalCostOfLoan()).totalWaived(defaultSummaryData.getTotalWaived())
+                
.totalWrittenOff(defaultSummaryData.getTotalWrittenOff()).totalOutstanding(defaultSummaryData.getTotalOutstanding())
+                
.totalOverdue(defaultSummaryData.getTotalOverdue()).overdueSinceDate(defaultSummaryData.getOverdueSinceDate())
+                
.writeoffReasonId(defaultSummaryData.getWriteoffReasonId()).writeoffReason(defaultSummaryData.getWriteoffReason())
+                
.totalRecovered(defaultSummaryData.getTotalRecovered()).chargeOffReasonId(defaultSummaryData.getChargeOffReasonId())
+                
.chargeOffReason(defaultSummaryData.getChargeOffReason()).totalMerchantRefund(totalMerchantRefund)
+                
.totalMerchantRefundReversed(totalMerchantRefundReversed).totalPayoutRefund(totalPayoutRefund)
+                
.totalPayoutRefundReversed(totalPayoutRefundReversed).totalGoodwillCredit(totalGoodwillCredit)
+                
.totalGoodwillCreditReversed(totalGoodwillCreditReversed).totalChargeAdjustment(totalChargeAdjustment)
+                
.totalChargeAdjustmentReversed(totalChargeAdjustmentReversed).totalChargeback(totalChargeback)
+                
.totalCreditBalanceRefund(totalCreditBalanceRefund).totalCreditBalanceRefundReversed(totalCreditBalanceRefundReversed)
+                
.totalRepaymentTransaction(totalRepaymentTransaction).totalRepaymentTransactionReversed(totalRepaymentTransactionReversed)
+                
.totalInterestPaymentWaiver(totalInterestPaymentWaiver).totalUnpaidPayableDueInterest(totalUnpaidPayableDueInterest)
+                
.totalUnpaidPayableNotDueInterest(totalUnpaidPayableNotDueInterest).totalInterestRefund(totalInterestRefund).build();
+    }
+
+    private static BigDecimal fetchLoanTransactionBalanceByType(final 
Collection<LoanTransactionBalance> loanTransactionBalances,
+            final Integer transactionType) {
+        final Optional<LoanTransactionBalance> optLoanTransactionBalance = 
loanTransactionBalances.stream()
+                .filter(balance -> 
balance.getTransactionType().equals(transactionType) && 
!balance.isReversed()).findFirst();
+        return optLoanTransactionBalance.isPresent() ? 
optLoanTransactionBalance.get().getAmount() : BigDecimal.ZERO;
+    }
+
+    private static BigDecimal fetchLoanTransactionBalanceReversedByType(final 
Collection<LoanTransactionBalance> loanTransactionBalances,
+            final Integer transactionType) {
+        final Optional<LoanTransactionBalance> optLoanTransactionBalance = 
loanTransactionBalances.stream()
+                .filter(balance -> 
balance.getTransactionType().equals(transactionType) && balance.isReversed()
+                        && balance.isManuallyAdjustedOrReversed())
+                .findFirst();
+        return optLoanTransactionBalance.isPresent() ? 
optLoanTransactionBalance.get().getAmount() : BigDecimal.ZERO;
+    }
+
+    @Override
+    public BigDecimal 
computeTotalUnpaidPayableDueInterestAmount(Collection<LoanSchedulePeriodData> 
periods, final LocalDate businessDate) {
+        return periods.stream().filter(period -> 
!period.getDownPaymentPeriod() && businessDate.compareTo(period.getDueDate()) 
>= 0)
+                
.map(LoanSchedulePeriodData::getInterestOutstanding).reduce(BigDecimal.ZERO, 
BigDecimal::add);
+    }
+
+    @Override
+    public LoanSummaryData withOnlyCurrencyData(CurrencyData currencyData) {
+        {
+            return LoanSummaryData.builder().currency(currencyData).build();
+        }
+    }
+
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CumulativeLoanSummaryDataProvider.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CumulativeLoanSummaryDataProvider.java
new file mode 100644
index 000000000..2d4e06d9d
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CumulativeLoanSummaryDataProvider.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Collection;
+import java.util.Optional;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
+import org.apache.fineract.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
+import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionBalance;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CumulativeLoanSummaryDataProvider extends 
CommonLoanSummaryDataProvider {
+
+    @Override
+    public boolean accept(String loanProcessingStrategyCode) {
+        return 
!loanProcessingStrategyCode.equalsIgnoreCase("advanced-payment-allocation-strategy");
+    }
+
+    @Override
+    public BigDecimal 
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(final Loan loan,
+            final Collection<LoanSchedulePeriodData> periods, final LocalDate 
businessDate, final CurrencyData currency) {
+        // Find the current Period (If exists one) based on the Business date
+        final Optional<LoanSchedulePeriodData> optCurrentPeriod = 
periods.stream()
+                .filter(period -> !period.getDownPaymentPeriod() && 
period.isActualPeriodForNotDuePayableCalculation(businessDate))
+                .findFirst();
+
+        if (optCurrentPeriod.isPresent()) {
+            final LoanSchedulePeriodData currentPeriod = 
optCurrentPeriod.get();
+            final long remainingDays = currentPeriod.getDaysInPeriod()
+                    - 
DateUtils.getDifferenceInDays(currentPeriod.getFromDate(), businessDate);
+
+            return computeAccruedInterestTillDay(currentPeriod, remainingDays, 
currency);
+        }
+        // Default value equal to Zero
+        return BigDecimal.ZERO;
+    }
+
+    @Override
+    public LoanSummaryData withTransactionAmountsSummary(Long loanId, 
LoanSummaryData defaultSummaryData,
+            LoanScheduleData repaymentSchedule, 
Collection<LoanTransactionBalance> loanTransactionBalances) {
+        Loan loan = null;
+        return super.withTransactionAmountsSummary(loan, defaultSummaryData, 
repaymentSchedule, loanTransactionBalances);
+    }
+
+    private static BigDecimal computeAccruedInterestTillDay(final 
LoanSchedulePeriodData period, final long untilDay,
+            final CurrencyData currency) {
+        Integer remainingDays = period.getDaysInPeriod();
+        BigDecimal totalAccruedInterest = BigDecimal.ZERO;
+        while (remainingDays > untilDay) {
+            final BigDecimal accruedInterest = 
period.getInterestDue().subtract(totalAccruedInterest)
+                    .divide(BigDecimal.valueOf(remainingDays), 
MoneyHelper.getMathContext());
+            totalAccruedInterest = totalAccruedInterest.add(accruedInterest);
+            remainingDays--;
+        }
+
+        totalAccruedInterest = 
totalAccruedInterest.subtract(period.getInterestPaid()).subtract(period.getInterestWaived());
+        if (MathUtil.isLessThanZero(totalAccruedInterest)) {
+            // Set Zero If the Interest Paid + Waived is greather than 
Interest Accrued
+            totalAccruedInterest = BigDecimal.ZERO;
+        }
+
+        return Money.of(currency, totalAccruedInterest).getAmount();
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryDataProvider.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryDataProvider.java
new file mode 100644
index 000000000..b10f86f74
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryDataProvider.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Collection;
+import org.apache.fineract.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionBalance;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
+
+public interface LoanSummaryDataProvider {
+
+    BigDecimal 
computeTotalUnpaidPayableDueInterestAmount(Collection<LoanSchedulePeriodData> 
periods, LocalDate businessDate);
+
+    BigDecimal 
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(Loan loan, 
Collection<LoanSchedulePeriodData> periods,
+            LocalDate businessDate, CurrencyData currency);
+
+    LoanSummaryData withOnlyCurrencyData(CurrencyData currencyData);
+
+    LoanSummaryData withTransactionAmountsSummary(Long loanId, LoanSummaryData 
defaultSummaryData, LoanScheduleData repaymentSchedule,
+            Collection<LoanTransactionBalance> loanTransactionBalances);
+
+    LoanSummaryData withTransactionAmountsSummary(Loan loan, LoanSummaryData 
defaultSummaryData, LoanScheduleData repaymentSchedule,
+            Collection<LoanTransactionBalance> loanTransactionBalances);
+
+    boolean accept(String loanProcessingStrategyCode);
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
new file mode 100644
index 000000000..20f9663fc
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.service;
+
+import java.util.List;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@Component
+@AllArgsConstructor
+public class LoanSummaryProviderDelegate {
+
+    private final List<LoanSummaryDataProvider> loanSummaryDataProviders;
+
+    public LoanSummaryDataProvider resolveLoanSummaryDataProvider(String 
loanProcessingStrategyCode) {
+        return loanSummaryDataProviders.stream().filter(provider -> 
provider.accept(loanProcessingStrategyCode)).findAny()
+                .orElseThrow(() -> new IllegalArgumentException("No provider 
found for :" + loanProcessingStrategyCode));
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
new file mode 100644
index 000000000..6bddb5e95
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Collection;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.fineract.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionBalance;
+import 
org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.PeriodDueDetails;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel;
+import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
+import org.springframework.stereotype.Component;
+
+@Component
+@AllArgsConstructor
+public class ProgressiveLoanSummaryDataProvider extends 
CommonLoanSummaryDataProvider {
+
+    private final AdvancedPaymentScheduleTransactionProcessor 
advancedPaymentScheduleTransactionProcessor;
+    private final EMICalculator emiCalculator;
+    private final LoanRepositoryWrapper loanRepository;
+
+    @Override
+    public boolean accept(String loanProcessingStrategyCode) {
+        return 
loanProcessingStrategyCode.equalsIgnoreCase("advanced-payment-allocation-strategy");
+    }
+
+    @Override
+    public LoanSummaryData withTransactionAmountsSummary(Long loanId, 
LoanSummaryData defaultSummaryData,
+            LoanScheduleData repaymentSchedule, 
Collection<LoanTransactionBalance> loanTransactionBalances) {
+        final Loan loan = loanRepository.findOneWithNotFoundDetection(loanId, 
true);
+        return super.withTransactionAmountsSummary(loan, defaultSummaryData, 
repaymentSchedule, loanTransactionBalances);
+    }
+
+    @Override
+    public LoanSummaryData withTransactionAmountsSummary(Loan loan, 
LoanSummaryData defaultSummaryData, LoanScheduleData repaymentSchedule,
+            Collection<LoanTransactionBalance> loanTransactionBalances) {
+        return super.withTransactionAmountsSummary(loan, defaultSummaryData, 
repaymentSchedule, loanTransactionBalances);
+    }
+
+    private LoanRepaymentScheduleInstallment 
getRelatedRepaymentScheduleInstallment(Loan loan, LocalDate businessDate) {
+        return loan.getRepaymentScheduleInstallments().stream().filter(i -> 
!i.isDownPayment() && !i.isAdditional()
+                && !businessDate.isBefore(i.getFromDate()) && 
businessDate.isBefore(i.getDueDate())).findFirst().orElseGet(() -> {
+                    List<LoanRepaymentScheduleInstallment> list = 
loan.getRepaymentScheduleInstallments().stream()
+                            .filter(i -> !i.isDownPayment() && 
!i.isAdditional()).toList();
+                    return !list.isEmpty() ? list.get(list.size() - 1) : null;
+                });
+    }
+
+    @Override
+    public BigDecimal 
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(final Loan loan,
+            final Collection<LoanSchedulePeriodData> periods, final LocalDate 
businessDate, final CurrencyData currency) {
+
+        LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = 
getRelatedRepaymentScheduleInstallment(loan, businessDate);
+        if (loan.isInterestBearing() && loanRepaymentScheduleInstallment != 
null) {
+            List<LoanTransaction> transactionsToReprocess = 
loan.retrieveListOfTransactionsForReprocessing().stream()
+                    .filter(t -> !t.isAccrualActivity()).toList();
+            Pair<ChangedTransactionDetail, 
ProgressiveLoanInterestScheduleModel> 
changedTransactionDetailProgressiveLoanInterestScheduleModelPair = 
advancedPaymentScheduleTransactionProcessor
+                    
.reprocessProgressiveLoanTransactions(loan.getDisbursementDate(), businessDate, 
transactionsToReprocess,
+                            loan.getCurrency(), 
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges());
+            ProgressiveLoanInterestScheduleModel model = 
changedTransactionDetailProgressiveLoanInterestScheduleModelPair.getRight();
+            if 
(!changedTransactionDetailProgressiveLoanInterestScheduleModelPair.getLeft().getCurrentTransactionToOldId().isEmpty()
+                    || 
!changedTransactionDetailProgressiveLoanInterestScheduleModelPair.getLeft().getNewTransactionMappings().isEmpty())
 {
+                throw new RuntimeException("Transactions should not be reverse 
replayed!");
+            }
+            if (model != null) {
+                PeriodDueDetails dueAmounts = 
emiCalculator.getDueAmounts(model, 
loanRepaymentScheduleInstallment.getDueDate(),
+                        businessDate);
+                if (dueAmounts != null) {
+                    BigDecimal interestPaid = 
loanRepaymentScheduleInstallment.getInterestPaid();
+                    BigDecimal dueInterest = 
dueAmounts.getDueInterest().getAmount();
+                    if (interestPaid == null) {
+                        return dueInterest;
+                    }
+                    return dueInterest.subtract(interestPaid);
+                }
+            }
+        }
+
+        return BigDecimal.ZERO;
+    }
+}
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
index 07bf0a4c7..bfe96eb77 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
@@ -4674,6 +4674,28 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             assertEquals(new BigDecimal("0.05"), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
         });
 
+        runAt("31 January 2024", () -> {
+            // Generate the Accruals
+            final PeriodicAccrualAccountingHelper 
periodicAccrualAccountingHelper = new 
PeriodicAccrualAccountingHelper(requestSpec,
+                    responseSpec);
+            periodicAccrualAccountingHelper.runPeriodicAccrualAccounting("31 
January 2024");
+
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(new BigDecimal("0.09"), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        runAt("1 February 2024", () -> {
+            // Generate the Accruals
+            final PeriodicAccrualAccountingHelper 
periodicAccrualAccountingHelper = new 
PeriodicAccrualAccountingHelper(requestSpec,
+                    responseSpec);
+            periodicAccrualAccountingHelper.runPeriodicAccrualAccounting("1 
February 2024");
+
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(new BigDecimal("0.12"), 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
         // Not Due and Due Interest
         runAt("20 February 2024", () -> {
             final PeriodicAccrualAccountingHelper 
periodicAccrualAccountingHelper = new 
PeriodicAccrualAccountingHelper(requestSpec,
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanPrepayAmountTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanPrepayAmountTest.java
new file mode 100644
index 000000000..bde69d064
--- /dev/null
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanPrepayAmountTest.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.integrationtests;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.PostLoanProductsResponse;
+import org.apache.fineract.client.models.PostLoansResponse;
+import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+
+@Slf4j
+public class LoanPrepayAmountTest extends BaseLoanIntegrationTest {
+
+    Long clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
+    Long loanId;
+
+    @Test
+    public void testLoanPrepayAmountProgressive() {
+        runAt("1 January 2024", () -> {
+            final PostLoanProductsResponse loanProductsResponse = 
loanProductHelper.createLoanProduct(create4IProgressive());
+            PostLoansResponse postLoansResponse = 
loanTransactionHelper.applyLoan(applyLP2ProgressiveLoanRequest(clientId,
+                    loanProductsResponse.getResourceId(), "01 January 2024", 
1000.0, 9.99, 6, null));
+            loanId = postLoansResponse.getLoanId();
+            loanTransactionHelper.approveLoan(loanId, 
approveLoanRequest(1000.0, "01 January 2024"));
+            disburseLoan(loanId, BigDecimal.valueOf(250.0), "01 January 2024");
+        });
+        runAt("7 january 2024", () -> {
+            disburseLoan(loanId, BigDecimal.valueOf(350.0), "04 January 2024");
+            disburseLoan(loanId, BigDecimal.valueOf(400.0), "05 January 2024");
+        });
+        for (int i = 7; i <= 31; i++) {
+            runAt(i + " January 2024", () -> {
+                GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId);
+                HashMap prepayAmount = 
loanTransactionHelper.getPrepayAmount(requestSpec, responseSpec, 
loanId.intValue());
+                Assertions.assertEquals((float) 
prepayAmount.get("interestPortion"),
+                        
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().floatValue());
+            });
+        }
+    }
+
+}
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRefundTransactionTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRefundTransactionTest.java
index cc9b93e6a..b40068e3b 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRefundTransactionTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRefundTransactionTest.java
@@ -18,11 +18,6 @@
  */
 package org.apache.fineract.integrationtests;
 
-import static 
org.apache.fineract.integrationtests.BaseLoanIntegrationTest.InterestRateFrequencyType.YEARS;
-import static 
org.apache.fineract.integrationtests.BaseLoanIntegrationTest.RepaymentFrequencyType.DAYS;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import com.google.gson.Gson;
 import io.restassured.builder.RequestSpecBuilder;
 import io.restassured.builder.ResponseSpecBuilder;
 import io.restassured.http.ContentType;
@@ -30,22 +25,16 @@ import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
 import java.math.BigDecimal;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.concurrent.atomic.AtomicLong;
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
-import org.apache.fineract.client.models.PostLoanProductsRequest;
 import org.apache.fineract.client.models.PostLoanProductsResponse;
-import org.apache.fineract.client.models.PostLoansLoanIdRequest;
 import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
 import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
-import org.apache.fineract.client.models.PostLoansRequest;
 import org.apache.fineract.client.models.PostLoansResponse;
 import org.apache.fineract.integrationtests.common.BusinessDateHelper;
 import org.apache.fineract.integrationtests.common.ClientHelper;
 import org.apache.fineract.integrationtests.common.LoanRescheduleRequestHelper;
 import org.apache.fineract.integrationtests.common.Utils;
 import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
-import 
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
 import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -78,158 +67,6 @@ public class LoanRefundTransactionTest extends 
BaseLoanIntegrationTest {
         loanRescheduleRequestHelper = new 
LoanRescheduleRequestHelper(requestSpec, responseSpec);
     }
 
-    // UC1: (Internal case) Generate a totalInterestRefund using Advanced 
payment allocation with Interest Refund
-    // options and Apply
-    // Interest Refund transaction
-    // 1. Create a Loan product with Adv. Pment. Alloc. and with Accrual and 
Interest Refund
-    // 2. Submit, Approve and Disburse a Loan account
-    // 3. Apply the INTEREST_REFUND transaction to validate the Journal 
Entries generated
-    @Test
-    public void uc1() {
-        final String operationDate = "1 January 2024";
-        AtomicLong createdLoanId = new AtomicLong();
-        runAt(operationDate, () -> {
-            Long clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
-            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
-                    
.interestRatePerPeriod(108.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS)
-                    
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL).daysInYearType(DaysInYearType.DAYS_360)
-                    .numberOfRepayments(4)//
-                    .maxInterestRatePerPeriod((double) 110)//
-                    .repaymentEvery(1)//
-                    .repaymentFrequencyType(1L)//
-                    .allowPartialPeriodInterestCalcualtion(false)//
-                    .multiDisburseLoan(false)//
-                    .disallowExpectedDisbursements(null)//
-                    .allowApprovedDisbursedAmountsOverApplied(null)//
-                    .overAppliedCalculationType(null)//
-                    .overAppliedNumber(null)//
-                    .installmentAmountInMultiplesOf(null)//
-            ;//
-            PostLoanProductsResponse loanProductResponse = 
loanProductHelper.createLoanProduct(product);
-            PostLoansRequest applicationRequest = applyLoanRequest(clientId, 
loanProductResponse.getResourceId(), operationDate, 1000.0, 4)
-                    .interestRatePerPeriod(BigDecimal.valueOf(108.0));
-
-            applicationRequest = 
applicationRequest.interestCalculationPeriodType(DAYS)
-                    
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY);
-
-            PostLoansResponse loanResponse = 
loanTransactionHelper.applyLoan(applicationRequest);
-            createdLoanId.set(loanResponse.getLoanId());
-
-            loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
-                    new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000.0)).dateFormat(DATETIME_PATTERN)
-                            .approvedOnDate("1 January 2024").locale("en"));
-
-            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
-                    new PostLoansLoanIdRequest().actualDisbursementDate("1 
January 2024").dateFormat(DATETIME_PATTERN)
-                            
.transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
-
-            // After Disbursement we are expecting zero interest refund
-            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-        });
-
-        runAt("10 February 2024", () -> {
-            // After Interest refund transaction we are expecting non zero 
interest refund
-            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            LOG.info("value {}", 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-
-            final BigDecimal inteterestRefund = BigDecimal.valueOf(11);
-            final Long loanTransactionId = 
loanTransactionHelper.applyInterestRefundLoanTransaction(requestSpec, 
responseSpec,
-                    createdLoanId.get(), 
buildJsonBody(BigDecimal.valueOf(5.0), BigDecimal.valueOf(3.0), 
BigDecimal.valueOf(2.0),
-                            BigDecimal.valueOf(1.0), null));
-
-            loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            assertEquals(inteterestRefund, 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-
-            verifyTRJournalEntries(loanTransactionId, journalEntry(5.0, 
loansReceivableAccount, "CREDIT"),
-                    journalEntry(3.0, interestReceivableAccount, "CREDIT"), 
journalEntry(2.0, feeReceivableAccount, "CREDIT"),
-                    journalEntry(1.0, penaltyReceivableAccount, "CREDIT"), 
journalEntry(11.0, overpaymentAccount, "CREDIT"),
-                    journalEntry(22.0, interestIncomeAccount, "DEBIT"));
-        });
-    }
-
-    // UC2: (Internal case) Generate a totalInterestRefund using Advanced 
payment allocation with Interest Refund
-    // options and Apply
-    // Interest Refund transaction when the Loan Account is ChargeBack
-    // 1. Create a Loan product with Adv. Pment. Alloc. and with Accrual and 
Interest Refund
-    // 2. Submit, Approve and Disburse a Loan account
-    // 3. Apply the MERCHANT_ISSUED_REFUND transaction to validate 
totalInterestRefund different than Zero
-    // 4- Apply the INTEREST_REFUND transaction to validate the Journal 
Entries generated
-    @Test
-    public void uc2() {
-        final String operationDate = "1 January 2024";
-        AtomicLong createdLoanId = new AtomicLong();
-        runAt(operationDate, () -> {
-            Long clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
-            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
-                    
.interestRatePerPeriod(108.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS)
-                    
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL).daysInYearType(DaysInYearType.DAYS_360)
-                    .numberOfRepayments(4)//
-                    .maxInterestRatePerPeriod((double) 110)//
-                    .repaymentEvery(1)//
-                    .repaymentFrequencyType(1L)//
-                    .allowPartialPeriodInterestCalcualtion(false)//
-                    .multiDisburseLoan(false)//
-                    .disallowExpectedDisbursements(null)//
-                    .allowApprovedDisbursedAmountsOverApplied(null)//
-                    .overAppliedCalculationType(null)//
-                    .overAppliedNumber(null)//
-                    .installmentAmountInMultiplesOf(null)//
-            ;//
-            PostLoanProductsResponse loanProductResponse = 
loanProductHelper.createLoanProduct(product);
-            PostLoansRequest applicationRequest = applyLoanRequest(clientId, 
loanProductResponse.getResourceId(), operationDate, 1000.0, 4)
-                    .interestRatePerPeriod(BigDecimal.valueOf(108.0));
-
-            applicationRequest = 
applicationRequest.interestCalculationPeriodType(DAYS)
-                    
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY);
-
-            PostLoansResponse loanResponse = 
loanTransactionHelper.applyLoan(applicationRequest);
-            createdLoanId.set(loanResponse.getLoanId());
-
-            loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
-                    new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000.0)).dateFormat(DATETIME_PATTERN)
-                            .approvedOnDate("1 January 2024").locale("en"));
-
-            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
-                    new PostLoansLoanIdRequest().actualDisbursementDate("1 
January 2024").dateFormat(DATETIME_PATTERN)
-                            
.transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
-
-            // After Disbursement we are expecting zero interest refund
-            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-        });
-
-        runAt("1 February 2024", () -> {
-            // After Interest refund transaction we are expecting non zero 
interest refund
-            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            LOG.info("value {}", 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-
-            Long repayment1TransactionId = 
addRepaymentForLoan(createdLoanId.get(), 250.0, "1 February 2024");
-            chargeOffLoan(createdLoanId.get(), "1 February 2024");
-        });
-
-        runAt("10 February 2024", () -> {
-            // After Interest refund transaction we are expecting non zero 
interest refund
-            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            LOG.info("value {}", 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-            LOG.info("chargedOffOnDate {}", 
loanDetails.getTimeline().getChargedOffOnDate());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-
-            final BigDecimal inteterestRefund = BigDecimal.valueOf(11);
-            final Long loanTransactionId = 
loanTransactionHelper.applyInterestRefundLoanTransaction(requestSpec, 
responseSpec,
-                    createdLoanId.get(), 
buildJsonBody(BigDecimal.valueOf(5.0), BigDecimal.valueOf(3.0), 
BigDecimal.valueOf(2.0),
-                            BigDecimal.valueOf(1.0), null));
-
-            loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            assertEquals(inteterestRefund, 
loanDetails.getSummary().getTotalInterestRefund().stripTrailingZeros());
-
-            verifyTRJournalEntries(loanTransactionId, journalEntry(11.0, 
interestIncomeChargeOffAccount, "CREDIT"),
-                    journalEntry(11.0, overpaymentAccount, "CREDIT"), 
journalEntry(22.0, interestIncomeAccount, "DEBIT"));
-        });
-    }
-
     @Test
     public void testMerchantIssuedRefundCreatesAndReversesInterestRefund() {
         runAt("01 July 2024", () -> {
@@ -292,20 +129,6 @@ public class LoanRefundTransactionTest extends 
BaseLoanIntegrationTest {
         });
     }
 
-    private String buildJsonBody(final BigDecimal principal, final BigDecimal 
interest, final BigDecimal feeCharges,
-            final BigDecimal penaltyCharges, final BigDecimal overpayment) {
-        final HashMap<String, BigDecimal> map = new HashMap<>();
-        map.put("principal", principal);
-        map.put("interest", interest);
-        map.put("feeCharges", feeCharges);
-        map.put("penaltyCharges", penaltyCharges);
-        if (overpayment != null) {
-            map.put("overpayment", overpayment);
-        }
-
-        return new Gson().toJson(map);
-    }
-
     private Long createLoanForMerchantIssuedRefundWithInterestRefund(Long 
clientId) {
         return createLoanForRefundWithInterestRefund(clientId, 
"MERCHANT_ISSUED_REFUND");
     }

Reply via email to