FINERACT-1981: Order disbursements and repayment periods properly
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/DisbursementData.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/DisbursementData.java
index 243426d..53e318f 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/DisbursementData.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/DisbursementData.java
@@ -23,6 +23,7 @@
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
 
 /**
  * Immutable data object representing disbursement information.
@@ -89,9 +90,12 @@
         return DateUtils.compare(obj.expectedDisbursementDate, this.expectedDisbursementDate);
     }
 
-    public boolean isDueForDisbursement(final LocalDate fromNotInclusive, final LocalDate upToAndInclusive) {
+    public boolean isDueForDisbursement(LoanScheduleType loanScheduleType, final LocalDate fromDate, final LocalDate toDate) {
         final LocalDate dueDate = disbursementDate();
-        return occursOnDayFromAndUpToAndIncluding(fromNotInclusive, upToAndInclusive, dueDate);
+        return switch (loanScheduleType) {
+            case CUMULATIVE -> occursOnDayFromAndUpToAndIncluding(fromDate, toDate, dueDate);
+            case PROGRESSIVE -> occursOnDayFromAndIncludingAndUpTo(fromDate, toDate, dueDate);
+        };
     }
 
     private boolean occursOnDayFromAndUpToAndIncluding(final LocalDate fromNotInclusive, final LocalDate upToAndInclusive,
@@ -99,6 +103,12 @@
         return DateUtils.isAfter(target, fromNotInclusive) && !DateUtils.isAfter(target, upToAndInclusive);
     }
 
+    private boolean occursOnDayFromAndIncludingAndUpTo(final LocalDate fromInclusive, final LocalDate upToNotInclusive,
+            final LocalDate target) {
+        return (DateUtils.isEqual(target, fromInclusive) || DateUtils.isAfter(target, fromInclusive))
+                && DateUtils.isBefore(target, upToNotInclusive);
+    }
+
     public BigDecimal getWaivedChargeAmount() {
         return this.waivedChargeAmount == null ? BigDecimal.ZERO : this.waivedChargeAmount;
     }
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index 9994201..fefbd02 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -282,7 +282,7 @@
             List<LoanRepaymentScheduleInstallment> installments) {
         final MathContext mc = MoneyHelper.getMathContext();
         List<LoanRepaymentScheduleInstallment> candidateRepaymentInstallments = installments.stream().filter(
-                i -> !i.getDueDate().isBefore(disbursementTransaction.getTransactionDate()) && !i.isDownPayment() && !i.isAdditional())
+                i -> i.getDueDate().isAfter(disbursementTransaction.getTransactionDate()) && !i.isDownPayment() && !i.isAdditional())
                 .toList();
         int noCandidateRepaymentInstallments = candidateRepaymentInstallments.size();
         LoanProductRelatedDetail loanProductRelatedDetail = disbursementTransaction.getLoan().getLoanRepaymentScheduleDetail();
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleType.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleType.java
index f561733..d9a7046 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleType.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleType.java
@@ -39,4 +39,11 @@
     public EnumOptionData asEnumOptionData() {
         return new EnumOptionData((long) this.ordinal(), this.name(), this.humanReadableName);
     }
+
+    public static LoanScheduleType fromEnumOptionData(EnumOptionData enumOptionData) {
+        if (enumOptionData == null) {
+            return null;
+        }
+        return valueOf(enumOptionData.getCode());
+    }
 }
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 e379e84..7f6da6f 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
@@ -47,7 +47,6 @@
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.UriInfo;
 import java.io.InputStream;
-import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -953,7 +952,7 @@
                                 loanBasicDetails.getFeeChargesAtDisbursementCharged());
                 repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(resolvedLoanId, repaymentScheduleRelatedData,
                         disbursementData, loanBasicDetails.isInterestRecalculationEnabled(),
-                        loanBasicDetails.getSummary() != null ? loanBasicDetails.getSummary().getFeeChargesPaid() : BigDecimal.ZERO);
+                        LoanScheduleType.fromEnumOptionData(loanBasicDetails.getLoanScheduleType()));
 
                 if (associationParameters.contains(DataTableApiConstant.futureScheduleAssociateParamName)
                         && loanBasicDetails.isInterestRecalculationEnabled()) {
@@ -965,8 +964,9 @@
                         && loanBasicDetails.isInterestRecalculationEnabled()
                         && LoanStatus.fromInt(loanBasicDetails.getStatus().getId().intValue()).isActive()) {
                     mandatoryResponseParameters.add(DataTableApiConstant.originalScheduleAssociateParamName);
-                    LoanScheduleData loanScheduleData = this.loanScheduleHistoryReadPlatformService
-                            .retrieveRepaymentArchiveSchedule(resolvedLoanId, repaymentScheduleRelatedData, disbursementData);
+                    LoanScheduleData loanScheduleData = this.loanScheduleHistoryReadPlatformService.retrieveRepaymentArchiveSchedule(
+                            resolvedLoanId, repaymentScheduleRelatedData, disbursementData,
+                            LoanScheduleType.fromEnumOptionData(loanBasicDetails.getLoanScheduleType()));
                     loanBasicDetails = LoanAccountData.withOriginalSchedule(loanBasicDetails, loanScheduleData);
                 }
             }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
index d0c1ba0..2399093 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
@@ -28,7 +28,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeMap;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
@@ -85,26 +84,6 @@
 
         boolean isFirstRepayment = true;
 
-        if (loanApplicationTerms.isMultiDisburseLoan()) {
-            /* fetches the first tranche amount and also updates other tranche details to map */
-            Money disburseAmt = Money.of(currency, getDisbursementAmount(loanApplicationTerms, scheduleParams.getPeriodStartDate(),
-                    scheduleParams.getDisburseDetailMap(), scheduleParams.applyInterestRecalculation()));
-            Money downPaymentAmt = Money.zero(currency);
-            if (loanApplicationTerms.isDownPaymentEnabled()) {
-                downPaymentAmt = Money.of(currency, MathUtil.percentageOf(disburseAmt.getAmount(),
-                        loanApplicationTerms.getDisbursedAmountPercentageForDownPayment(), 19));
-                if (loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null) {
-                    downPaymentAmt = Money.roundToMultiplesOf(downPaymentAmt, loanApplicationTerms.getInstallmentAmountInMultiplesOf());
-                }
-            }
-            Money remainingPrincipalAmt = disburseAmt.minus(downPaymentAmt);
-            scheduleParams.setPrincipalToBeScheduled(remainingPrincipalAmt);
-            loanApplicationTerms.setPrincipal(remainingPrincipalAmt);
-            scheduleParams.setOutstandingBalance(remainingPrincipalAmt);
-            scheduleParams.setOutstandingBalanceAsPerRest(remainingPrincipalAmt);
-            loanApplicationTerms.resetFixedEmiAmount();
-        }
-
         // charges which depends on total loan interest will be added to this
         // set and handled separately after all installments generated
         final Set<LoanCharge> nonCompoundingCharges = separateTotalCompoundingPercentageCharges(loanCharges);
@@ -134,13 +113,8 @@
             }
 
             // 5 determine principal,interest of repayment period
-            PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
-                    getPaymentPeriodsInOneYearCalculator(), currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(),
-                    scheduleParams.getTotalCumulativePrincipal().minus(scheduleParams.getReducePrincipal()),
-                    scheduleParams.getTotalCumulativeInterest(), loanApplicationTerms.getTotalInterestDue(),
-                    scheduleParams.getTotalOutstandingInterestPaymentDueToGrace(), scheduleParams.getOutstandingBalanceAsPerRest(),
-                    loanApplicationTerms, scheduleParams.getPeriodNumber(), mc, null, scheduleParams.getCompoundingMap(), null,
-                    scheduledDueDate, null);
+            PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(loanApplicationTerms,
+                    scheduleParams, mc);
 
             // update cumulative fields for principal
             currentPeriodParams.setPrincipalForThisPeriod(principalInterestForThisPeriod.principal());
@@ -241,12 +215,8 @@
 
     public abstract PaymentPeriodsInOneYearCalculator getPaymentPeriodsInOneYearCalculator();
 
-    public abstract PrincipalInterest calculatePrincipalInterestComponentsForPeriod(PaymentPeriodsInOneYearCalculator calculator,
-            BigDecimal interestCalculationGraceOnRepaymentPeriodFraction, Money totalCumulativePrincipal, Money totalCumulativeInterest,
-            Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, Money outstandingBalance,
-            LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc, TreeMap<LocalDate, Money> principalVariation,
-            Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate,
-            Collection<LoanTermVariationsData> termVariations);
+    public abstract PrincipalInterest calculatePrincipalInterestComponentsForPeriod(LoanApplicationTerms loanApplicationTerms,
+            LoanScheduleParams loanScheduleParams, MathContext mc);
 
     // Private, internal methods
     private BigDecimal deriveTotalChargesDueAtTimeOfDisbursement(final Set<LoanCharge> loanCharges) {
@@ -266,7 +236,8 @@
         Money principalToBeScheduled;
         if (loanApplicationTerms.isMultiDisburseLoan()) {
             if (loanApplicationTerms.getTotalDisbursedAmount().isGreaterThanZero()) {
-                principalToBeScheduled = loanApplicationTerms.getTotalMultiDisbursedAmount();
+                principalToBeScheduled = Money.of(loanApplicationTerms.getCurrency(),
+                        loanApplicationTerms.getDisbursementDatas().get(0).getPrincipal());
             } else if (loanApplicationTerms.getApprovedPrincipal().isGreaterThanZero()) {
                 principalToBeScheduled = loanApplicationTerms.getApprovedPrincipal();
             } else {
@@ -300,6 +271,9 @@
                             loanScheduleParams, loanApplicationTerms.getExpectedDisbursementDate(), disbursementData.getPrincipal());
                     periods.add(downPaymentPeriod);
                 }
+            } else {
+                loanScheduleParams.getDisburseDetailMap().put(disbursementData.disbursementDate(),
+                        Money.of(loanApplicationTerms.getCurrency(), disbursementData.getPrincipal()));
             }
         }
 
@@ -313,14 +287,19 @@
         if (loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null) {
             downPaymentAmount = Money.roundToMultiplesOf(downPaymentAmount, loanApplicationTerms.getInstallmentAmountInMultiplesOf());
         }
-        LoanScheduleModelDownPaymentPeriod installment = LoanScheduleModelDownPaymentPeriod
-                .downPayment(scheduleParams.getInstalmentNumber(), date, downPaymentAmount, scheduleParams.getOutstandingBalance());
+        LoanScheduleModelDownPaymentPeriod installment = LoanScheduleModelDownPaymentPeriod.downPayment(
+                scheduleParams.getInstalmentNumber(), date, downPaymentAmount,
+                scheduleParams.getOutstandingBalance().minus(downPaymentAmount));
 
         addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
 
         scheduleParams.incrementInstalmentNumber();
         scheduleParams.addTotalRepaymentExpected(downPaymentAmount);
-
+        scheduleParams.reduceOutstandingBalance(downPaymentAmount);
+        scheduleParams.reduceOutstandingBalanceAsPerRest(downPaymentAmount);
+        scheduleParams.setPrincipalToBeScheduled(scheduleParams.getPrincipalToBeScheduled().minus(downPaymentAmount));
+        loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().minus(downPaymentAmount));
+        loanApplicationTerms.resetFixedEmiAmount();
         return installment;
     }
 
@@ -345,8 +324,9 @@
     private void processDisbursements(final LoanApplicationTerms loanApplicationTerms, final BigDecimal chargesDueAtTimeOfDisbursement,
             LoanScheduleParams scheduleParams, final Collection<LoanScheduleModelPeriod> periods, final LocalDate scheduledDueDate) {
         for (Map.Entry<LocalDate, Money> disburseDetail : scheduleParams.getDisburseDetailMap().entrySet()) {
-            if (disburseDetail.getKey().isAfter(scheduleParams.getPeriodStartDate())
-                    && !disburseDetail.getKey().isAfter(scheduledDueDate)) {
+            if ((disburseDetail.getKey().isEqual(scheduleParams.getPeriodStartDate())
+                    || disburseDetail.getKey().isAfter(scheduleParams.getPeriodStartDate()))
+                    && disburseDetail.getKey().isBefore(scheduledDueDate)) {
                 // validation check for amount not exceeds specified max
                 // amount as per the configuration
                 loanApplicationTerms.getMaxOutstandingBalance();
@@ -378,11 +358,10 @@
                 }
                 // updates actual outstanding balance with new
                 // disbursement detail
-                Money remainingPrincipal = disburseDetail.getValue().minus(downPaymentAmt);
-                scheduleParams.addOutstandingBalance(remainingPrincipal);
-                scheduleParams.addOutstandingBalanceAsPerRest(remainingPrincipal);
-                scheduleParams.addPrincipalToBeScheduled(remainingPrincipal);
-                loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().plus(remainingPrincipal));
+                scheduleParams.addOutstandingBalance(disburseDetail.getValue());
+                scheduleParams.addOutstandingBalanceAsPerRest(disburseDetail.getValue());
+                scheduleParams.addPrincipalToBeScheduled(disburseDetail.getValue());
+                loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().plus(disburseDetail.getValue()));
                 loanApplicationTerms.resetFixedEmiAmount();
             }
         }
@@ -585,43 +564,6 @@
         return interestCharges;
     }
 
-    private BigDecimal getDisbursementAmount(final LoanApplicationTerms loanApplicationTerms, LocalDate disbursementDate,
-            final Map<LocalDate, Money> disburseDetails, final boolean excludePastUnDisbursed) {
-
-        // this method relates to multi-disbursement loans
-        BigDecimal principal = BigDecimal.ZERO;
-        if (loanApplicationTerms.getDisbursementDatas().size() == 0) {
-            // non tranche loans have no disbursement data entries in submitted and approved status
-            // the appropriate approved amount or applied for amount is used to show a proposed schedule
-            if (loanApplicationTerms.getApprovedPrincipal().getAmount().compareTo(BigDecimal.ZERO) > 0) {
-                principal = loanApplicationTerms.getApprovedPrincipal().getAmount();
-            } else {
-                principal = loanApplicationTerms.getPrincipal().getAmount();
-            }
-        } else {
-            MonetaryCurrency currency = loanApplicationTerms.getPrincipal().getCurrency();
-            for (DisbursementData disbursementData : loanApplicationTerms.getDisbursementDatas()) {
-                if (disbursementData.disbursementDate().equals(disbursementDate)) {
-                    principal = principal.add(disbursementData.getPrincipal());
-                } else if (!excludePastUnDisbursed || disbursementData.isDisbursed()
-                        || !disbursementData.disbursementDate().isBefore(DateUtils.getBusinessLocalDate())) {
-                    /*
-                     * JW: sums up amounts by disbursal date in case of side-effect issues. Original assumed that there
-                     * were no duplicate disbursal dates and 'put' each amount into the map keyed by date
-                     */
-                    Money previousSum = disburseDetails.get(disbursementData.disbursementDate());
-                    BigDecimal sumToNow = BigDecimal.ZERO;
-                    if (previousSum != null) {
-                        sumToNow = previousSum.getAmount();
-                    }
-                    sumToNow = sumToNow.add(disbursementData.getPrincipal());
-                    disburseDetails.put(disbursementData.disbursementDate(), Money.of(currency, sumToNow));
-                }
-            }
-        }
-        return principal;
-    }
-
     private void updateOutstandingBalance(LoanScheduleParams scheduleParams, ScheduleCurrentPeriodParams currentPeriodParams) {
         // update outstandingLoanBlance using current period
         // 'principalDue'
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
index 99a106e..f05675e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
@@ -20,13 +20,9 @@
 
 import java.math.BigDecimal;
 import java.math.MathContext;
-import java.time.LocalDate;
-import java.util.Collection;
-import java.util.Map;
-import java.util.TreeMap;
 import lombok.RequiredArgsConstructor;
 import org.apache.fineract.organisation.monetary.domain.Money;
-import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleParams;
 import org.springframework.stereotype.Component;
 
 @Component
@@ -47,21 +43,30 @@
     }
 
     @Override
-    public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(PaymentPeriodsInOneYearCalculator calculator,
-            BigDecimal interestCalculationGraceOnRepaymentPeriodFraction, Money totalCumulativePrincipal, Money totalCumulativeInterest,
-            Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, Money outstandingBalance,
-            LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc, TreeMap<LocalDate, Money> principalVariation,
-            Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate,
-            Collection<LoanTermVariationsData> termVariations) {
+    public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(LoanApplicationTerms loanApplicationTerms,
+            LoanScheduleParams loanScheduleParams, MathContext mc) {
         // TODO: handle interest calculation
-        Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, outstandingBalance,
-                periodNumber, mc, Money.zero(loanApplicationTerms.getCurrency()));
-        final Money totalCumulativePrincipalToDate = totalCumulativePrincipal.plus(principalForThisInstallment);
+        int periodNumber = loanScheduleParams.getPeriodNumber();
+        BigDecimal fixedEMIAmount = loanApplicationTerms.getFixedEmiAmount();
+        Money calculatedPrincipal;
+        if (fixedEMIAmount == null) {
+            int noRemainingPeriod = loanApplicationTerms.getActualNoOfRepaymnets() - periodNumber + 1;
+            calculatedPrincipal = loanScheduleParams.getOutstandingBalance().dividedBy(noRemainingPeriod, mc.getRoundingMode());
+            if (loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null) {
+                calculatedPrincipal = Money.roundToMultiplesOf(calculatedPrincipal,
+                        loanApplicationTerms.getInstallmentAmountInMultiplesOf());
+            }
+            loanApplicationTerms.setFixedEmiAmount(calculatedPrincipal.getAmount());
+        } else {
+            calculatedPrincipal = Money.of(loanApplicationTerms.getCurrency(), fixedEMIAmount);
+        }
         // adjust if needed
-        principalForThisInstallment = loanApplicationTerms.adjustPrincipalIfLastRepaymentPeriod(principalForThisInstallment,
-                totalCumulativePrincipalToDate, periodNumber);
+        if (periodNumber == loanApplicationTerms.getActualNoOfRepaymnets()) {
+            Money remainingAmount = loanScheduleParams.getOutstandingBalance().minus(calculatedPrincipal);
+            calculatedPrincipal = calculatedPrincipal.plus(remainingAmount);
+        }
 
-        return new PrincipalInterest(principalForThisInstallment, Money.zero(loanApplicationTerms.getCurrency()),
+        return new PrincipalInterest(calculatedPrincipal, Money.zero(loanApplicationTerms.getCurrency()),
                 Money.zero(loanApplicationTerms.getCurrency()));
     }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformService.java
index 22270a1..3b25c50 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformService.java
@@ -23,13 +23,14 @@
 import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
 import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
 
 public interface LoanScheduleHistoryReadPlatformService {
 
     Integer fetchCurrentVersionNumber(Long loanId);
 
     LoanScheduleData retrieveRepaymentArchiveSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
-            Collection<DisbursementData> disbursementData);
+            Collection<DisbursementData> disbursementData, LoanScheduleType loanScheduleType);
 
     Map<String, Object> fetchOldAuditDates(Long id);
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformServiceImpl.java
index d098c63..8b35fef 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformServiceImpl.java
@@ -37,6 +37,7 @@
 import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
 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.domain.LoanScheduleType;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.DataAccessException;
 import org.springframework.dao.EmptyResultDataAccessException;
@@ -68,7 +69,8 @@
 
     @Override
     public LoanScheduleData retrieveRepaymentArchiveSchedule(final Long loanId,
-            final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData) {
+            final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData,
+            LoanScheduleType loanScheduleType) {
 
         try {
             this.context.authenticatedUser();
@@ -77,7 +79,7 @@
                 return null;
             }
             final LoanScheduleArchiveResultSetExtractor fullResultsetExtractor = new LoanScheduleArchiveResultSetExtractor(
-                    repaymentScheduleRelatedLoanData, disbursementData);
+                    repaymentScheduleRelatedLoanData, disbursementData, loanScheduleType);
             final String sql = "select " + fullResultsetExtractor.schema()
                     + " where ls.loan_id = ? and ls.version = ? order by ls.loan_id, ls.installment";
 
@@ -99,17 +101,19 @@
         private final DisbursementData disbursement;
         private final BigDecimal totalFeeChargesDueAtDisbursement;
         private final Collection<DisbursementData> disbursementData;
+        private final LoanScheduleType loanScheduleType;
         private LocalDate lastDueDate;
         private BigDecimal outstandingLoanPrincipalBalance;
 
         LoanScheduleArchiveResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
-                Collection<DisbursementData> disbursementData) {
+                Collection<DisbursementData> disbursementData, LoanScheduleType loanScheduleType) {
             this.currency = repaymentScheduleRelatedLoanData.getCurrency();
             this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
             this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
             this.lastDueDate = this.disbursement.disbursementDate();
             this.outstandingLoanPrincipalBalance = this.disbursement.getPrincipal();
             this.disbursementData = disbursementData;
+            this.loanScheduleType = loanScheduleType;
         }
 
         public String schema() {
@@ -163,7 +167,7 @@
                                     data.getPrincipal(), this.totalFeeChargesDueAtDisbursement, data.isDisbursed());
                             periods.add(periodData);
                             this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.getPrincipal());
-                        } else if (data.isDueForDisbursement(fromDate, dueDate)
+                        } else if (data.isDueForDisbursement(loanScheduleType, fromDate, dueDate)
                                 && this.outstandingLoanPrincipalBalance.compareTo(BigDecimal.ZERO) > 0) {
                             principal = principal.add(data.getPrincipal());
                             final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(),
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
index 235b6b8..1b0c64e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
@@ -18,7 +18,6 @@
  */
 package org.apache.fineract.portfolio.loanaccount.service;
 
-import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.util.Collection;
 import java.util.List;
@@ -43,6 +42,7 @@
 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.OverdueLoanScheduleData;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
 
 public interface LoanReadPlatformService {
 
@@ -51,7 +51,7 @@
     LoanAccountData fetchRepaymentScheduleData(LoanAccountData accountData);
 
     LoanScheduleData retrieveRepaymentSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData,
-            Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled, BigDecimal totalPaidFeeCharges);
+            Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled, LoanScheduleType loanScheduleType);
 
     Collection<LoanTransactionData> retrieveLoanTransactions(Long loanId);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index f0d0240..6adaa99 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -245,7 +245,7 @@
         final Collection<DisbursementData> disbursementData = retrieveLoanDisbursementDetails(accountData.getId());
         final LoanScheduleData repaymentSchedule = retrieveRepaymentSchedule(accountData.getId(), repaymentScheduleRelatedData,
                 disbursementData, accountData.isInterestRecalculationEnabled(),
-                accountData.getSummary() != null ? accountData.getSummary().getFeeChargesPaid() : BigDecimal.ZERO);
+                LoanScheduleType.fromEnumOptionData(accountData.getLoanScheduleType()));
         accountData.setRepaymentSchedule(repaymentSchedule);
         return accountData;
     }
@@ -253,13 +253,13 @@
     @Override
     public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
             final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData,
-            boolean isInterestRecalculationEnabled, BigDecimal totalPaidFeeCharges) {
+            boolean isInterestRecalculationEnabled, LoanScheduleType loanScheduleType) {
 
         try {
             this.context.authenticatedUser();
 
             final LoanScheduleResultSetExtractor fullResultsetExtractor = new LoanScheduleResultSetExtractor(
-                    repaymentScheduleRelatedLoanData, disbursementData, isInterestRecalculationEnabled);
+                    repaymentScheduleRelatedLoanData, disbursementData, isInterestRecalculationEnabled, loanScheduleType);
             final String sql = "select " + fullResultsetExtractor.schema() + " where ls.loan_id = ? order by ls.loan_id, ls.installment";
 
             return this.jdbcTemplate.query(sql, fullResultsetExtractor, loanId); // NOSONAR
@@ -1123,19 +1123,21 @@
         private final DisbursementData disbursement;
         private final BigDecimal totalFeeChargesDueAtDisbursement;
         private final Collection<DisbursementData> disbursementData;
+        private final LoanScheduleType loanScheduleType;
         private LocalDate lastDueDate;
         private BigDecimal outstandingLoanPrincipalBalance;
-        private boolean excludePastUndisbursed;
+        private boolean excludePastUnDisbursed;
 
         LoanScheduleResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
-                Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled) {
+                Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled, LoanScheduleType loanScheduleType) {
             this.currency = repaymentScheduleRelatedLoanData.getCurrency();
             this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
             this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
             this.lastDueDate = this.disbursement.disbursementDate();
             this.outstandingLoanPrincipalBalance = this.disbursement.getPrincipal();
             this.disbursementData = disbursementData;
-            this.excludePastUndisbursed = isInterestRecalculationEnabled;
+            this.excludePastUnDisbursed = isInterestRecalculationEnabled;
+            this.loanScheduleType = loanScheduleType;
         }
 
         public String schema() {
@@ -1160,7 +1162,7 @@
                     this.disbursement.disbursementDate(), this.disbursement.getPrincipal(), this.totalFeeChargesDueAtDisbursement,
                     this.disbursement.isDisbursed());
 
-            final Collection<LoanSchedulePeriodData> periods = new ArrayList<>();
+            final List<LoanSchedulePeriodData> periods = new ArrayList<>();
             final MonetaryCurrency monCurrency = new MonetaryCurrency(this.currency.getCode(), this.currency.getDecimalPlaces(),
                     this.currency.getInMultiplesOf());
             BigDecimal totalPrincipalDisbursed = BigDecimal.ZERO;
@@ -1170,7 +1172,7 @@
                 totalPrincipalDisbursed = Money.of(monCurrency, this.disbursement.getPrincipal()).getAmount();
             } else {
                 if (!this.disbursement.isDisbursed()) {
-                    excludePastUndisbursed = false;
+                    excludePastUnDisbursed = false;
                 }
                 for (DisbursementData data : disbursementData) {
                     if (data.getChargeAmount() != null) {
@@ -1211,56 +1213,11 @@
                 final LocalDate obligationsMetOnDate = JdbcSupport.getLocalDate(rs, "obligationsMetOnDate");
                 final boolean complete = rs.getBoolean("complete");
                 final boolean isAdditional = rs.getBoolean("isAdditional");
-                BigDecimal principal = BigDecimal.ZERO;
+                BigDecimal disbursedAmount = BigDecimal.ZERO;
                 if (!isAdditional) {
-                    for (final DisbursementData data : disbursementData) {
-                        if (fromDate.equals(this.disbursement.disbursementDate()) && data.disbursementDate().equals(fromDate)
-                                && !disbursementPeriodIds.contains(data.getId())) {
-                            principal = principal.add(data.getPrincipal());
-                            LoanSchedulePeriodData periodData = null;
-                            if (data.getChargeAmount() == null) {
-                                periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(),
-                                        disbursementChargeAmount, data.isDisbursed());
-                            } else {
-                                periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(),
-                                        disbursementChargeAmount.add(data.getChargeAmount()).subtract(waivedChargeAmount),
-                                        data.isDisbursed());
-                            }
-                            periods.add(periodData);
-                            this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.getPrincipal());
-                            disbursementPeriodIds.add(data.getId());
-                        } else if (data.isDueForDisbursement(fromDate, dueDate) && !disbursementPeriodIds.contains(data.getId())) {
-                            if (!excludePastUndisbursed || data.isDisbursed() || !DateUtils.isBeforeBusinessDate(data.disbursementDate())) {
-                                principal = principal.add(data.getPrincipal());
-                                LoanSchedulePeriodData periodData;
-                                if (data.getChargeAmount() == null) {
-                                    periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(),
-                                            BigDecimal.ZERO, data.isDisbursed());
-                                } else {
-                                    periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(),
-                                            data.getChargeAmount(), data.isDisbursed());
-                                }
-                                periods.add(periodData);
-                                this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.getPrincipal());
-                                disbursementPeriodIds.add(data.getId());
-                            }
-                        } else if (fromDate.equals(dueDate) && data.disbursementDate().equals(fromDate)
-                                && !disbursementPeriodIds.contains(data.getId())) {
-                            principal = principal.add(data.getPrincipal());
-                            LoanSchedulePeriodData periodData = null;
-                            if (data.getChargeAmount() == null) {
-                                periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(),
-                                        disbursementChargeAmount, data.isDisbursed());
-                            } else {
-                                periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(),
-                                        disbursementChargeAmount.add(data.getChargeAmount()).subtract(waivedChargeAmount),
-                                        data.isDisbursed());
-                            }
-                            periods.add(periodData);
-                            this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.getPrincipal());
-                            disbursementPeriodIds.add(data.getId());
-                        }
-                    }
+                    disbursedAmount = processDisbursementData(loanScheduleType, disbursementData, fromDate, dueDate, disbursementPeriodIds,
+                            disbursementChargeAmount, waivedChargeAmount, periods);
+
                 }
                 // Add the Charge back or Credits to the initial amount to avoid negative balance
                 final BigDecimal credits = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalCredits");
@@ -1268,7 +1225,7 @@
                     this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(credits);
                 }
 
-                totalPrincipalDisbursed = totalPrincipalDisbursed.add(principal);
+                totalPrincipalDisbursed = totalPrincipalDisbursed.add(disbursedAmount);
 
                 Integer daysInPeriod = 0;
                 if (fromDate != null) {
@@ -1379,6 +1336,39 @@
                     totalPaidLate.getAmount(), totalOutstanding.getAmount(), totalCredits.getAmount());
         }
 
+        private BigDecimal processDisbursementData(LoanScheduleType loanScheduleType, Collection<DisbursementData> disbursementData,
+                LocalDate fromDate, LocalDate dueDate, Set<Long> disbursementPeriodIds, BigDecimal disbursementChargeAmount,
+                BigDecimal waivedChargeAmount, List<LoanSchedulePeriodData> periods) {
+            BigDecimal disbursedAmount = BigDecimal.ZERO;
+            for (final DisbursementData data : disbursementData) {
+                boolean isDueForDisbursement = data.isDueForDisbursement(loanScheduleType, fromDate, dueDate);
+                if (((fromDate.equals(this.disbursement.disbursementDate()) && data.disbursementDate().equals(fromDate))
+                        || (fromDate.equals(dueDate) && data.disbursementDate().equals(fromDate))
+                        || canAddDisbursementData(data, isDueForDisbursement, excludePastUnDisbursed))
+                        && !disbursementPeriodIds.contains(data.getId())) {
+                    disbursedAmount = disbursedAmount.add(data.getPrincipal());
+                    LoanSchedulePeriodData periodData = createLoanSchedulePeriodData(data, disbursementChargeAmount, waivedChargeAmount);
+                    periods.add(periodData);
+                    this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(periodData.getPrincipalDisbursed());
+                    disbursementPeriodIds.add(data.getId());
+                }
+            }
+            return disbursedAmount;
+        }
+
+        private LoanSchedulePeriodData createLoanSchedulePeriodData(final DisbursementData data, BigDecimal disbursementChargeAmount,
+                BigDecimal waivedChargeAmount) {
+            BigDecimal chargeAmount = data.getChargeAmount() == null ? disbursementChargeAmount
+                    : disbursementChargeAmount.add(data.getChargeAmount()).subtract(waivedChargeAmount);
+            return LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(), chargeAmount,
+                    data.isDisbursed());
+        }
+
+        private boolean canAddDisbursementData(DisbursementData data, boolean isDueForDisbursement, boolean excludePastUnDisbursed) {
+            return (!excludePastUnDisbursed || data.isDisbursed() || !DateUtils.isBeforeBusinessDate(data.disbursementDate()))
+                    && isDueForDisbursement;
+        }
+
     }
 
     private static final class LoanTransactionsMapper implements RowMapper<LoanTransactionData> {
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 64c51a6..e587e12 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
@@ -57,7 +57,6 @@
 import org.apache.fineract.integrationtests.common.BusinessDateHelper;
 import org.apache.fineract.integrationtests.common.ClientHelper;
 import org.apache.fineract.integrationtests.common.CommonConstants;
-import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
 import org.apache.fineract.integrationtests.common.LoanRescheduleRequestHelper;
 import org.apache.fineract.integrationtests.common.Utils;
 import org.apache.fineract.integrationtests.common.accounting.Account;
@@ -78,7 +77,7 @@
 import org.slf4j.LoggerFactory;
 
 @ExtendWith(LoanTestLifecycleExtension.class)
-public class AdvancedPaymentAllocationLoanRepaymentScheduleTest {
+public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoanIntegrationTest {
 
     private static final Logger LOG = LoggerFactory.getLogger(AdvancedPaymentAllocationLoanRepaymentScheduleTest.class);
     private static final String DATETIME_PATTERN = "dd MMMM yyyy";
@@ -122,10 +121,7 @@
 
     @Test
     public void uc1() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -182,9 +178,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 0.0, 0.0);
             validateLoanTransaction(loanDetails, 4, 125.0, 125.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
     // UC2: Overpayment1
     // ADVANCED_PAYMENT_ALLOCATION_STRATEGY
@@ -195,10 +189,7 @@
 
     @Test
     public void uc2() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -255,9 +246,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 25.0, 0.0);
             validateLoanTransaction(loanDetails, 4, 125.0, 100.0, 25.0, 0.0);
             assertTrue(loanDetails.getStatus().getOverpaid());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
     // UC3: Overpayment2
     // ADVANCED_PAYMENT_ALLOCATION_STRATEGY
@@ -267,10 +256,7 @@
 
     @Test
     public void uc3() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -327,9 +313,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 25.0, 0.0);
             validateLoanTransaction(loanDetails, 4, 125.0, 100.0, 25.0, 0.0);
             assertTrue(loanDetails.getStatus().getOverpaid());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
     // UC4: Delinquent balance
     // ADVANCED_PAYMENT_ALLOCATION_STRATEGY
@@ -340,10 +324,7 @@
 
     @Test
     public void uc4() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -419,9 +400,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 0.0, 0.0);
             validateLoanTransaction(loanDetails, 5, 360.0, 360.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC5: Refund past due
@@ -432,10 +411,7 @@
     // 4. Pay rest on time
     @Test
     public void uc5() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -507,9 +483,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 58.34, 0.0);
             validateLoanTransaction(loanDetails, 5, 66.66, 66.66, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC7: Refund & due reamortization
@@ -521,10 +495,7 @@
     // 4. Pay rest on time
     @Test
     public void uc7() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -594,9 +565,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 100.0, 0.0);
             validateLoanTransaction(loanDetails, 5, 25.0, 25.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC8: Refund after due & past due
@@ -608,10 +577,7 @@
     // 4. Pay rest on time
     @Test
     public void uc8() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -686,9 +652,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 25.0, 0.0);
             validateLoanTransaction(loanDetails, 5, 100.0, 100.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC9: Refund next installment
@@ -699,10 +663,7 @@
     // 4. Pay rest on time
     @Test
     public void uc9() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -759,9 +720,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 0.0, 0.0);
             validateLoanTransaction(loanDetails, 4, 125.0, 125.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC10: Refund PD and next installment
@@ -773,10 +732,7 @@
     // 4. Pay rest on time
     @Test
     public void uc10() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -848,9 +804,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 0.0, 0.0);
             validateLoanTransaction(loanDetails, 5, 125.0, 125.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC11: Refund Past, pay in advance installments
@@ -861,10 +815,7 @@
     // 4. Pay rest on time
     @Test
     public void uc11() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -913,9 +864,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 25.0, 0.0);
             validateLoanTransaction(loanDetails, 3, 100.0, 100.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC12: Refund last installment
@@ -926,10 +875,7 @@
     // 4. Pay rest on time
     @Test
     public void uc12() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -986,9 +932,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 125.0, 0.0);
             validateLoanTransaction(loanDetails, 3, 125.0, 125.0, 0.0, 50.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC13: Due apply last installment
@@ -1000,10 +944,7 @@
     // 5. Pay rest on time
     @Test
     public void uc13() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1074,9 +1015,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 75.0, 0.0);
             validateLoanTransaction(loanDetails, 5, 50.0, 50.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC14: Refund PD
@@ -1088,10 +1027,7 @@
     // 5. Pay rest on time
     @Test
     public void uc14() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1164,9 +1100,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 0.0, 0.0);
             validateLoanTransaction(loanDetails, 5, 175.0, 175.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC15: Goodwill credit PD
@@ -1178,10 +1112,7 @@
     // 5. Pay rest on time
     @Test
     public void uc15() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1251,9 +1182,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 75.0, 0.0);
             validateLoanTransaction(loanDetails, 5, 50.0, 50.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC17a: Full refund with CBR
@@ -1265,10 +1194,7 @@
     // 5. CBR
     @Test
     public void uc17a() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1312,9 +1238,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 125.0, 0.0);
             validateLoanTransaction(loanDetails, 3, 125.0, 0.0, 125.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC17b: Full refund with CBR
@@ -1326,10 +1250,7 @@
     // 5. CBR
     @Test
     public void uc17b() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1373,9 +1294,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 125.0, 0.0);
             validateLoanTransaction(loanDetails, 3, 125.0, 0.0, 125.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC17c: Full refund with CBR
@@ -1387,10 +1306,7 @@
     // 5. CBR
     @Test
     public void uc17c() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("15 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1434,9 +1350,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 125.0, 0.0);
             validateLoanTransaction(loanDetails, 3, 125.0, 0.0, 125.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC18: Full refund with CBR (N+1)
@@ -1448,10 +1362,7 @@
     // 5. CBR
     @Test
     public void uc18() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.20").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("20 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1530,9 +1441,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 0.0, 0.0);
             validateLoanTransaction(loanDetails, 6, 500.0, 0.0, 500.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC24: Merchant issued credit reverse-replay
@@ -1546,10 +1455,7 @@
     // 7. Payments
     @Test
     public void uc24() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.20").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("20 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1651,9 +1557,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 0.0, 0.0);
             validateLoanTransaction(loanDetails, 7, 125.0, 125.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC25: Merchant issued credit reverse-replay with uneven balances
@@ -1665,10 +1569,7 @@
     // 5. Merchant issued credit
     @Test
     public void uc25() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.20").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("20 February 2023", () -> {
 
             final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
                     BigDecimal.valueOf(500.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
@@ -1725,9 +1626,7 @@
             validateRepaymentPeriod(loanDetails, 4, 125.0, 115.0, 10.0, 115.0, 0.0);
             validateLoanTransaction(loanDetails, 4, 40.0, 40.0, 0.0, 10.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC101: Multiple disbursement test
@@ -1737,11 +1636,7 @@
     // 3. Disburse again
     @Test
     public void uc101() {
-        try {
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.20").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("20 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -1808,9 +1703,7 @@
             validateRepaymentPeriod(loanDetails, 6, LocalDate.of(2023, 2, 22), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0, 0.0, 100.0, 0.0, 0.0,
                     0.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC102: Multiple disbursement & reschedule test
@@ -1822,11 +1715,7 @@
     // 4. Reschedule the 3rd period to be later than the 2nd disbursement
     @Test
     public void uc102() {
-        try {
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.20").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("20 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -1907,9 +1796,7 @@
             validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 25), 218.75, 100.0, 118.75, 100.0, 0.0);
             validateRepaymentPeriod(loanDetails, 5, LocalDate.of(2023, 3, 12), 218.75, 0.0, 218.75, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC103: Advanced payment allocation, add charge after maturity -> N+1 installment, repay the loan
@@ -1919,11 +1806,7 @@
     // 3. Fully repay the loan
     @Test
     public void uc103() {
-        try {
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -1978,9 +1861,7 @@
             validateRepaymentPeriod(loanDetails, 5, LocalDate.of(2023, 2, 22), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 0.0, 0.0,
                     0.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getClosedObligationsMet());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC104: Advanced payment allocation, horizontal repayment processing
@@ -1991,11 +1872,7 @@
     // 4. Pay little more than the principal of 1st installment and charge of 2nd installment
     @Test
     public void uc104() {
-        try {
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2063,9 +1940,7 @@
             validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 125.0, 0.0, 125.0, 0.0, 0.0, 0.0, 25.0, 0.0, 25.0, 0.0, 0.0,
                     0.0, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC105: Advanced payment allocation, vertical repayment processing
@@ -2076,11 +1951,7 @@
     // 4. Pay little more than the charges
     @Test
     public void uc105() {
-        try {
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2148,9 +2019,7 @@
             validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 125.0, 0.0, 125.0, 0.0, 0.0, 0.0, 25.0, 25.0, 0.0, 0.0, 0.0,
                     0.0, 0.0, 25.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC106: Advanced payment allocation, horizontal repayment processing, mixed grouping of allocation rules
@@ -2158,11 +2027,7 @@
     // 1. Create a Loan product, but the allocation rules are mixed -> expect validation error
     @Test
     public void uc106() {
-        try {
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2176,9 +2041,7 @@
             assertNotNull(loanProductErrorData);
             assertEquals("mixed.due.type.allocation.rules.are.not.supported.with.horizontal.installment.processing",
                     loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC107: Advanced payment allocation, vertical repayment processing, mixed grouping of allocation rules
@@ -2188,11 +2051,7 @@
     // 3. Change to HORIZONTAL loan schedule processing and allocation rules are mixed - > expect validation error
     @Test
     public void uc107() {
-        try {
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2220,9 +2079,7 @@
             assertEquals(400, exception.getResponse().code());
             assertTrue(exception.getMessage()
                     .contains("mixed.due.type.allocation.rules.are.not.supported.with.horizontal.installment.processing"));
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC108: Advanced payment allocation, progressive loan schedule handling, rounding test
@@ -2231,10 +2088,7 @@
     // 2. Submit the loan, and check the generated repayment schedule
     @Test
     public void uc108() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2313,9 +2167,7 @@
             validateRepaymentPeriod(loanDetails, 6, LocalDate.of(2023, 4, 1), 166.65, 0.0, 166.65, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
 
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC109: Advanced payment allocation, cumulative loan schedule handling, rounding test
@@ -2324,10 +2176,7 @@
     // 2. Submit the loan, and check the generated repayment schedule
     @Test
     public void uc109() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2406,9 +2255,7 @@
             validateRepaymentPeriod(loanDetails, 6, LocalDate.of(2023, 4, 1), 166.65, 0.0, 166.65, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
 
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC110: Advanced payment allocation, progressive loan schedule handling, rounding test
@@ -2417,10 +2264,7 @@
     // 2. Submit the loan, and check the generated repayment schedule
     @Test
     public void uc110() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2462,9 +2306,7 @@
             validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 10.13, 0.0, 10.13, 0.0, 0.0);
             validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 10.12, 0.0, 10.12, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC111: Advanced payment allocation, cumulative loan schedule handling, rounding test
@@ -2473,10 +2315,7 @@
     // 2. Submit the loan, and check the generated repayment schedule
     @Test
     public void uc111() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.02.22").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("22 February 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2518,9 +2357,7 @@
             validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 10.13, 0.0, 10.13, 0.0, 0.0);
             validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 10.12, 0.0, 10.12, 0.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC112: Advanced payment allocation, horizontal repayment processing
@@ -2534,10 +2371,7 @@
     // 7. Do goodwill credit (in advance payment)
     @Test
     public void uc112() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.09.01").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("01 September 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2629,9 +2463,7 @@
             validateLoanCharge(loanDetails, 1, LocalDate.of(2023, 10, 16), 20.0, 20.0, 0.0);
             validateLoanCharge(loanDetails, 2, LocalDate.of(2023, 10, 17), 20.0, 20.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC113: Advanced payment allocation, vertical repayment processing
@@ -2645,10 +2477,7 @@
     // 7. Do goodwill credit (in advance payment)
     @Test
     public void uc113() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.09.01").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("01 September 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2739,9 +2568,7 @@
             validateLoanCharge(loanDetails, 1, LocalDate.of(2023, 10, 16), 20.0, 20.0, 0.0);
             validateLoanCharge(loanDetails, 2, LocalDate.of(2023, 10, 17), 20.0, 20.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC114: Advanced payment allocation, horizontal repayment processing
@@ -2755,10 +2582,7 @@
     // 7. Do merchant issued refund (in advance payment)
     @Test
     public void uc114() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.09.01").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("01 September 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2849,9 +2673,7 @@
             validateLoanCharge(loanDetails, 1, LocalDate.of(2023, 10, 16), 20.0, 10.0, 10.0);
             validateLoanCharge(loanDetails, 2, LocalDate.of(2023, 10, 17), 20.0, 10.0, 10.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
     }
 
     // UC115: Advanced payment allocation, vertical repayment processing
@@ -2865,10 +2687,7 @@
     // 7. Do merchant issued refund (in advance payment)
     @Test
     public void uc115() {
-        try {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
-            businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
-                    .date("2023.09.01").dateFormat("yyyy.MM.dd").locale("en"));
+        runAt("01 September 2023", () -> {
 
             final Account assetAccount = accountHelper.createAssetAccount();
             final Account incomeAccount = accountHelper.createIncomeAccount();
@@ -2957,9 +2776,239 @@
             validateLoanCharge(loanDetails, 1, LocalDate.of(2023, 10, 16), 20.0, 10.0, 10.0);
             validateLoanCharge(loanDetails, 2, LocalDate.of(2023, 10, 17), 20.0, 10.0, 10.0);
             assertTrue(loanDetails.getStatus().getActive());
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
-        }
+        });
+    }
+
+    // UC116: Advanced payment allocation, horizontal repayment processing, disbursement on due date of an installment
+    // ADVANCED_PAYMENT_ALLOCATION_STRATEGY
+    // 1. Disburse the loan (1000)
+    // 2. Add charge on disbursement date(50)
+    // 3. Repay down payment fully on disbursement date (250)
+    // 4. Disburse on 1st installment due date (400)
+    @Test
+    public void uc116() {
+        runAt("01 January 2023", () -> {
+            final Account assetAccount = accountHelper.createAssetAccount();
+            final Account incomeAccount = accountHelper.createIncomeAccount();
+            final Account expenseAccount = accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = accountHelper.createLiabilityAccount();
+            Integer localLoanProductId = createLoanProduct("1000", "15", "3", true, "25", false, LoanScheduleType.PROGRESSIVE,
+                    LoanScheduleProcessingType.HORIZONTAL, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+            final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), localLoanProductId,
+                    BigDecimal.valueOf(1000.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
+
+            loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
+                            .approvedOnDate("01 January 2023").locale("en"));
+
+            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().actualDisbursementDate("01 January 2023").dateFormat(DATETIME_PATTERN)
+                            .transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
+
+            GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1000.0, 0.0, 1000.0, 0.0, null);
+            validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 250.0, 0.0, 250.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+
+            // Add Charge Fee
+            Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
+                    ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
+            loanTransactionHelper.addChargesForLoan(loanResponse.getLoanId().intValue(),
+                    LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee), "01 January 2023", "50"));
+
+            loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1050.0, 0.0, 1000.0, 0.0, null);
+            validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), 250.0, 0.0, 250.0, 50.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 250.0, 0.0, 250.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+
+            loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
+                    .dateFormat(DATETIME_PATTERN).transactionDate("01 January 2023").locale("en").transactionAmount(250.0));
+            loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 800.0, 250.0, 750.0, 250.0, null);
+            validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 250.0, 250.0, 0.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), 250.0, 0.0, 250.0, 50.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 250.0, 0.0, 250.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+
+            updateBusinessDate("16 January 2023");
+            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().actualDisbursementDate("16 January 2023").dateFormat(DATETIME_PATTERN)
+                            .transactionAmount(BigDecimal.valueOf(400.0)).locale("en"));
+            loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1200.0, 250.0, 1150.0, 250.0, null);
+            validatePeriod(loanDetails, 0, LocalDate.of(2023, 1, 1), null, 1000.0, null, null, null, 0.0, 0.0, null, null, null, null, null,
+                    null, null, null, null);
+            validatePeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), LocalDate.of(2023, 1, 1), 750.0, 250.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), null, 500.0, 250.0, 0.0, 250.0, 50.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 3, LocalDate.of(2023, 1, 16), null, 400.0, null, null, null, 0.0, 0.0, null, null, null, null, null,
+                    null, null, null, null);
+            validatePeriod(loanDetails, 4, LocalDate.of(2023, 1, 16), null, 800.0, 100.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 5, LocalDate.of(2023, 1, 31), null, 400.0, 400.0, 0.0, 400.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 6, LocalDate.of(2023, 2, 15), null, 0.0, 400.0, 0.0, 400.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+        });
+    }
+
+    // UC117: Advanced payment allocation, horizontal repayment processing, multi disbursement on due date of an
+    // installment
+    // ADVANCED_PAYMENT_ALLOCATION_STRATEGY
+    // 1. Disburse the loan (1000)
+    // 2. Add charge on disbursement date(50)
+    // 3. Repay down payment fully on disbursement date (250)
+    // 4. Disburse on 1st installment due date (400)
+    // 4. Disburse on 1st installment due date (80)
+    @Test
+    public void uc117() {
+        runAt("01 January 2023", () -> {
+            final Account assetAccount = accountHelper.createAssetAccount();
+            final Account incomeAccount = accountHelper.createIncomeAccount();
+            final Account expenseAccount = accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = accountHelper.createLiabilityAccount();
+            Integer localLoanProductId = createLoanProduct("1000", "15", "3", true, "25", false, LoanScheduleType.PROGRESSIVE,
+                    LoanScheduleProcessingType.HORIZONTAL, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+            final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), localLoanProductId,
+                    BigDecimal.valueOf(1000.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
+
+            loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
+                            .approvedOnDate("01 January 2023").locale("en"));
+
+            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().actualDisbursementDate("01 January 2023").dateFormat(DATETIME_PATTERN)
+                            .transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
+
+            GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1000.0, 0.0, 1000.0, 0.0, null);
+            validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 250.0, 0.0, 250.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+
+            // Add Charge Fee
+            Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
+                    ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
+            loanTransactionHelper.addChargesForLoan(loanResponse.getLoanId().intValue(),
+                    LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee), "01 January 2023", "50"));
+
+            loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1050.0, 0.0, 1000.0, 0.0, null);
+            validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), 250.0, 0.0, 250.0, 50.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 250.0, 0.0, 250.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+
+            loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
+                    .dateFormat(DATETIME_PATTERN).transactionDate("01 January 2023").locale("en").transactionAmount(250.0));
+            loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 800.0, 250.0, 750.0, 250.0, null);
+            validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 250.0, 250.0, 0.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), 250.0, 0.0, 250.0, 50.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 250.0, 0.0, 250.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+
+            updateBusinessDate("16 January 2023");
+            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().actualDisbursementDate("16 January 2023").dateFormat(DATETIME_PATTERN)
+                            .transactionAmount(BigDecimal.valueOf(400.0)).locale("en"));
+            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().actualDisbursementDate("16 January 2023").dateFormat(DATETIME_PATTERN)
+                            .transactionAmount(BigDecimal.valueOf(80.0)).locale("en"));
+            loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1280.0, 250.0, 1230.0, 250.0, null);
+            validatePeriod(loanDetails, 0, LocalDate.of(2023, 1, 1), null, 1000.0, null, null, null, 0.0, 0.0, null, null, null, null, null,
+                    null, null, null, null);
+            validatePeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), LocalDate.of(2023, 1, 1), 750.0, 250.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), null, 500.0, 250.0, 0.0, 250.0, 50.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 3, LocalDate.of(2023, 1, 16), null, 400.0, null, null, null, 0.0, 0.0, null, null, null, null, null,
+                    null, null, null, null);
+            validatePeriod(loanDetails, 4, LocalDate.of(2023, 1, 16), null, 80.0, null, null, null, 0.0, 0.0, null, null, null, null, null,
+                    null, null, null, null);
+            validatePeriod(loanDetails, 5, LocalDate.of(2023, 1, 16), null, 880.0, 100.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 6, LocalDate.of(2023, 1, 16), null, 860.0, 20.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 7, LocalDate.of(2023, 1, 31), null, 430.0, 430.0, 0.0, 430.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 8, LocalDate.of(2023, 2, 15), null, 0.0, 430.0, 0.0, 430.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+        });
+    }
+
+    // UC118: Advanced payment allocation, horizontal repayment processing, multi disbursement on disbursement date
+    // ADVANCED_PAYMENT_ALLOCATION_STRATEGY
+    // 1. Disburse the loan (1000)
+    // 2. Disburse on disbursement date (400)
+    @Test
+    public void uc118() {
+        runAt("01 January 2023", () -> {
+            final Account assetAccount = accountHelper.createAssetAccount();
+            final Account incomeAccount = accountHelper.createIncomeAccount();
+            final Account expenseAccount = accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = accountHelper.createLiabilityAccount();
+            Integer localLoanProductId = createLoanProduct("1000", "15", "3", true, "25", false, LoanScheduleType.PROGRESSIVE,
+                    LoanScheduleProcessingType.HORIZONTAL, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+            final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), localLoanProductId,
+                    BigDecimal.valueOf(1000.0), 45, 15, 3, 0, "01 January 2023", "01 January 2023");
+
+            loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
+                            .approvedOnDate("01 January 2023").locale("en"));
+
+            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().actualDisbursementDate("01 January 2023").dateFormat(DATETIME_PATTERN)
+                            .transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
+
+            GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1000.0, 0.0, 1000.0, 0.0, null);
+            validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 250.0, 0.0, 250.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 250.0, 0.0, 250.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+
+            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().actualDisbursementDate("01 January 2023").dateFormat(DATETIME_PATTERN)
+                            .transactionAmount(BigDecimal.valueOf(400.0)).locale("en"));
+            loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1400.0, 0.0, 1400.0, 0.0, null);
+            validatePeriod(loanDetails, 0, LocalDate.of(2023, 1, 1), null, 1000.0, null, null, null, 0.0, 0.0, null, null, null, null, null,
+                    null, null, null, null);
+            validatePeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), null, 400.0, null, null, null, 0.0, 0.0, null, null, null, null, null,
+                    null, null, null, null);
+            validatePeriod(loanDetails, 2, LocalDate.of(2023, 1, 1), null, 1150.0, 250.0, 0.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 3, LocalDate.of(2023, 1, 1), null, 1050.0, 100.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 4, LocalDate.of(2023, 1, 16), null, 700.0, 350.0, 0.0, 350.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 5, LocalDate.of(2023, 1, 31), null, 350.0, 350.0, 0.0, 350.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0, 0.0);
+            validatePeriod(loanDetails, 6, LocalDate.of(2023, 2, 15), null, 0.0, 350.0, 0.0, 350.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    0.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+        });
     }
 
     private static void validateLoanSummaryBalances(GetLoansLoanIdResponse loanDetails, Double totalOutstanding, Double totalRepayment,
@@ -3085,6 +3134,30 @@
         return loanTransactionHelper.getLoanProductId(loanProductJSON);
     }
 
+    private static void validatePeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, LocalDate paidDate,
+            Double balanceOfLoan, Double principalDue, Double principalPaid, Double principalOutstanding, Double feeDue, Double feePaid,
+            Double feeOutstanding, Double penaltyDue, Double penaltyPaid, Double penaltyOutstanding, Double interestDue,
+            Double interestPaid, Double interestOutstanding, Double paidInAdvance, Double paidLate) {
+        GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().get(index);
+        assertEquals(dueDate, period.getDueDate());
+        assertEquals(paidDate, period.getObligationsMetOnDate());
+        assertEquals(balanceOfLoan, period.getPrincipalLoanBalanceOutstanding());
+        assertEquals(principalDue, period.getPrincipalDue());
+        assertEquals(principalPaid, period.getPrincipalPaid());
+        assertEquals(principalOutstanding, period.getPrincipalOutstanding());
+        assertEquals(feeDue, period.getFeeChargesDue());
+        assertEquals(feePaid, period.getFeeChargesPaid());
+        assertEquals(feeOutstanding, period.getFeeChargesOutstanding());
+        assertEquals(penaltyDue, period.getPenaltyChargesDue());
+        assertEquals(penaltyPaid, period.getPenaltyChargesPaid());
+        assertEquals(penaltyOutstanding, period.getPenaltyChargesOutstanding());
+        assertEquals(interestDue, period.getInterestDue());
+        assertEquals(interestPaid, period.getInterestPaid());
+        assertEquals(interestOutstanding, period.getInterestOutstanding());
+        assertEquals(paidInAdvance, period.getTotalPaidInAdvanceForPeriod());
+        assertEquals(paidLate, period.getTotalPaidLateForPeriod());
+    }
+
     private static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
             double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) {
         GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream()
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 6d8ec7b..469f3f3 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
@@ -498,4 +498,9 @@
         public static final Integer MONTHS = 2;
         public static final Integer YEARS = 3;
     }
+
+    public void updateBusinessDate(String date) {
+        businessDateHelper.updateBusinessDate(
+                new BusinessDateRequest().type(BUSINESS_DATE.getName()).date(date).dateFormat(DATETIME_PATTERN).locale("en"));
+    }
 }
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeOffWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeOffWithAdvancedPaymentAllocationTest.java
index 06275fb..ecbc697 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeOffWithAdvancedPaymentAllocationTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeOffWithAdvancedPaymentAllocationTest.java
@@ -18,9 +18,6 @@
  */
 package org.apache.fineract.integrationtests;
 
-import static java.lang.Boolean.FALSE;
-import static java.lang.Boolean.TRUE;
-import static org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType.BUSINESS_DATE;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -42,7 +39,6 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.fineract.client.models.AdvancedPaymentData;
 import org.apache.fineract.client.models.AllowAttributeOverrides;
-import org.apache.fineract.client.models.BusinessDateRequest;
 import org.apache.fineract.client.models.ChargeData;
 import org.apache.fineract.client.models.ChargeToGLAccountMapper;
 import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
@@ -61,7 +57,6 @@
 import org.apache.fineract.client.models.PostPaymentTypesResponse;
 import org.apache.fineract.integrationtests.common.BusinessDateHelper;
 import org.apache.fineract.integrationtests.common.ClientHelper;
-import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
 import org.apache.fineract.integrationtests.common.PaymentTypeHelper;
 import org.apache.fineract.integrationtests.common.Utils;
 import org.apache.fineract.integrationtests.common.accounting.Account;
@@ -83,7 +78,7 @@
 import org.junit.jupiter.api.extension.ExtendWith;
 
 @ExtendWith(LoanTestLifecycleExtension.class)
-public class LoanAccountChargeOffWithAdvancedPaymentAllocationTest {
+public class LoanAccountChargeOffWithAdvancedPaymentAllocationTest extends BaseLoanIntegrationTest {
 
     private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
     private ResponseSpecification responseSpec;
@@ -777,23 +772,4 @@
             return paymentAllocationOrder;
         }).toList();
     }
-
-    private void runAt(String date, Runnable runnable) {
-        try {
-            GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, 42, true);
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, TRUE);
-            businessDateHelper.updateBusinessDate(
-                    new BusinessDateRequest().type(BUSINESS_DATE.getName()).date(date).dateFormat(DATETIME_PATTERN).locale("en"));
-            runnable.run();
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, FALSE);
-            GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, 42, false);
-        }
-    }
-
-    private void updateBusinessDate(String date) {
-        businessDateHelper.updateBusinessDate(
-                new BusinessDateRequest().type(BUSINESS_DATE.getName()).date(date).dateFormat(DATETIME_PATTERN).locale("en"));
-    }
-
 }
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java
index 9a9ec44..34f17cf 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java
@@ -724,16 +724,16 @@
             // down payment period [1]
             verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(1), 1, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
                     LocalDate.of(2023, 3, 3), LocalDate.of(2023, 3, 3));
-            // disbursement period [2]
-            verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(2), LocalDate.of(2023, 4, 3), 200.0);
-            // down payment period [3]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(3), 2, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
-                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
-            // regular installment [4]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 3, 150.0, 0.0, 0.0, 150.0, 0.0, 0.0, 0.0, 0.0,
+            // regular installment [2]
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(2), 2, 75.0, 50.0, 50.0, 25.0, 0.0, 0.0, 0.0, 0.0,
                     false, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            // disbursement period [3]
+            verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(3), LocalDate.of(2023, 4, 3), 200.0);
+            // down payment period [4]
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 3, 50.0, 0.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, false,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
             // regular installment [5]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 4, 150.0, 0.0, 0.0, 150.0, 0.0, 0.0, 0.0, 0.0,
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 4, 225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
                     false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
 
             // same day third disbursement with overlapping installment i.e same due date as regular repayment due date
@@ -758,21 +758,21 @@
             // down payment period [1]
             verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(1), 1, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
                     LocalDate.of(2023, 3, 3), LocalDate.of(2023, 3, 3));
-            // disbursement period [2]
-            verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(2), LocalDate.of(2023, 4, 3), 200.0);
+            // regular installment [2]
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(2), 2, 75.0, 75.0, 75.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
             // disbursement period [3]
             verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(3), LocalDate.of(2023, 4, 3), 200.0);
-            // down payment period [4]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 2, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
-                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // disbursement period [4]
+            verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(4), LocalDate.of(2023, 4, 3), 200.0);
             // down payment period [5]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 50.0, 25.0, 25.0, 25.0, 0.0, 0.0, 0.0, 0.0,
+                    false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // down payment period [6]
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(6), 4, 50.0, 0.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, false,
                     LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
-            // regular installment [6]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(6), 4, 225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
-                    false, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
             // regular installment [7]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(7), 5, 225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(7), 5, 375.0, 0.0, 0.0, 375.0, 0.0, 0.0, 0.0, 0.0,
                     false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
 
             // make repayment for fully paying and verify that regular installment gets fully paid on 3rd april
@@ -791,21 +791,21 @@
             // down payment period [1]
             verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(1), 1, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
                     LocalDate.of(2023, 3, 3), LocalDate.of(2023, 3, 3));
-            // disbursement period [2]
-            verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(2), LocalDate.of(2023, 4, 3), 200.0);
+            // regular installment [2]
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(2), 2, 75.0, 75.0, 75.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
             // disbursement period [3]
             verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(3), LocalDate.of(2023, 4, 3), 200.0);
-            // down payment period [4]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 2, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
-                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // disbursement period [4]
+            verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(4), LocalDate.of(2023, 4, 3), 200.0);
             // down payment period [5]
             verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
                     LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
-            // regular installment [6]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(6), 4, 225.0, 225.0, 225.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-                    true, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            // down payment period [6]
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(6), 4, 50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
             // regular installment [7]
-            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(7), 5, 225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
+            verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(7), 5, 375.0, 150.0, 150.0, 225.0, 0.0, 0.0, 0.0, 0.0,
                     false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
 
         } finally {
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductRepaymentStartDateConfigurationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductRepaymentStartDateConfigurationTest.java
index c13939f..5cbf0e5 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductRepaymentStartDateConfigurationTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductRepaymentStartDateConfigurationTest.java
@@ -124,7 +124,7 @@
         try {
 
             // Set business date
-            LocalDate businessDate = LocalDate.of(2023, 03, 3);
+            LocalDate businessDate = LocalDate.of(2023, 3, 3);
 
             GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
             BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
@@ -169,25 +169,25 @@
 
             // first period [2023-03-03 to 2023-04-03]
             assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
-            assertEquals(LocalDate.of(2023, 03, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
-            assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
+            assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
+            assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
             assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
 
             // second period [2023-04-03 to 2023-05-03]
             assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
-            assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
-            assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
+            assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
+            assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
             assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
 
             // third period [2023-05-03 to 2023-06-03]
             assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
-            assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
-            assertEquals(LocalDate.of(2023, 06, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
+            assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
+            assertEquals(LocalDate.of(2023, 6, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
             assertEquals(333.34, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
 
             // first disbursement on a future date (7 March 2023)
 
-            LocalDate disbursementDate = LocalDate.of(2023, 03, 7);
+            LocalDate disbursementDate = LocalDate.of(2023, 3, 7);
 
             BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
 
@@ -208,25 +208,25 @@
 
             // first period [2023-03-03 to 2023-04-03]
             assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
-            assertEquals(LocalDate.of(2023, 03, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
-            assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
+            assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
+            assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
             assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
 
             // second period [2023-04-03 to 2023-05-03]
             assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
-            assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
-            assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
+            assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
+            assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
             assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
 
             // third period [2023-05-03 to 2023-06-03]
             assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
-            assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
-            assertEquals(LocalDate.of(2023, 06, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
+            assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
+            assertEquals(LocalDate.of(2023, 6, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
             assertEquals(166.66, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
 
             // second disbursement next month (7 April 2023)
 
-            disbursementDate = LocalDate.of(2023, 04, 7);
+            disbursementDate = LocalDate.of(2023, 4, 7);
 
             BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
 
@@ -248,20 +248,20 @@
 
             // first period [2023-03-03 to 2023-04-03]
             assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
-            assertEquals(LocalDate.of(2023, 03, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
-            assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
+            assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
+            assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
             assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
 
             // second period [2023-04-03 to 2023-05-03]
             assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
-            assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
-            assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
+            assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
+            assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
             assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
 
             // third period [2023-05-03 to 2023-06-03]
             assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod());
-            assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate());
-            assertEquals(LocalDate.of(2023, 06, 3), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate());
+            assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate());
+            assertEquals(LocalDate.of(2023, 6, 3), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate());
             assertEquals(500.00, loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod());
 
         } finally {
@@ -278,7 +278,7 @@
         try {
 
             // Set business date
-            LocalDate businessDate = LocalDate.of(2023, 03, 3);
+            LocalDate businessDate = LocalDate.of(2023, 3, 3);
 
             GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
             BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
@@ -324,25 +324,25 @@
 
             // first period [2023-03-07 to 2023-04-07]
             assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
-            assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
-            assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
+            assertEquals(LocalDate.of(2023, 3, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
+            assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
             assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
 
             // second period [2023-04-07 to 2023-05-07]
             assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
-            assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
-            assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
+            assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
+            assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
             assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
 
             // third period [2023-05-07 to 2023-06-07]
             assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
-            assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
-            assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
+            assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
+            assertEquals(LocalDate.of(2023, 6, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
             assertEquals(333.34, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
 
             // first disbursement (7 March 2023)
 
-            LocalDate disbursementDate = LocalDate.of(2023, 03, 7);
+            LocalDate disbursementDate = LocalDate.of(2023, 3, 7);
 
             BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
 
@@ -364,25 +364,25 @@
 
             // first period [2023-03-07 to 2023-04-07]
             assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
-            assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
-            assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
+            assertEquals(LocalDate.of(2023, 3, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
+            assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
             assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
 
             // second period [2023-04-07 to 2023-05-07]
             assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
-            assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
-            assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
+            assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
+            assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
             assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
 
             // third period [2023-05-07 to 2023-06-07]
             assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
-            assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
-            assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
+            assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
+            assertEquals(LocalDate.of(2023, 6, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
             assertEquals(166.66, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
 
             // second disbursement next month (7 April 2023)
 
-            disbursementDate = LocalDate.of(2023, 04, 7);
+            disbursementDate = LocalDate.of(2023, 4, 7);
 
             BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
 
@@ -405,20 +405,20 @@
 
             // first period [2023-03-07 to 2023-04-07]
             assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
-            assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
-            assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
+            assertEquals(LocalDate.of(2023, 3, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
+            assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
             assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
 
             // second period [2023-04-07 to 2023-05-07]
             assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
-            assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
-            assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
+            assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
+            assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
             assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
 
             // third period [2023-05-07 to 2023-06-07]
             assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod());
-            assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate());
-            assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate());
+            assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate());
+            assertEquals(LocalDate.of(2023, 6, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate());
             assertEquals(333.34, loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod());
 
         } finally {