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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 5be1001fd FINERACT-1981: Fix down-payment handling on overpaid loan 
(Advanced payment allocation loan)
5be1001fd is described below

commit 5be1001fd5d973db6080fd81d3c9703e88396996
Author: Adam Saghy <[email protected]>
AuthorDate: Tue Feb 27 12:07:49 2024 +0100

    FINERACT-1981: Fix down-payment handling on overpaid loan (Advanced payment 
allocation loan)
---
 .../portfolio/loanaccount/domain/Loan.java         |  33 +-
 ...dvancedPaymentScheduleTransactionProcessor.java |  14 +-
 .../service/LoanDownPaymentHandlerService.java     |   4 +-
 .../service/LoanDownPaymentHandlerServiceImpl.java |  17 +-
 .../LoanWritePlatformServiceJpaRepositoryImpl.java |   4 +-
 .../LoanDownPaymentHandlerServiceImplTest.java     |  37 +-
 ...PaymentAllocationLoanRepaymentScheduleTest.java |   2 +-
 ...oanProductWithDownPaymentConfigurationTest.java | 459 --------------
 .../LoanRepaymentScheduleWithDownPaymentTest.java  | 701 ++++++++++++++++++++-
 ...oanDisbursalWithDownPaymentIntegrationTest.java |   8 +-
 10 files changed, 773 insertions(+), 506 deletions(-)

diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 5f7275fa6..8c7b42477 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -2955,7 +2955,7 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
 
     }
 
-    public LoanTransaction handleDownPayment(final BigDecimal disbursedAmount, 
final JsonCommand command,
+    public LoanTransaction handleDownPayment(final LoanTransaction 
disbursementTransaction, final JsonCommand command,
             final ScheduleGeneratorDTO scheduleGeneratorDTO) {
         LocalDate disbursedOn = 
command.localDateValueOfParameterNamed(ACTUAL_DISBURSEMENT_DATE);
         BigDecimal disbursedAmountPercentageForDownPayment = 
this.loanRepaymentScheduleDetail.getDisbursedAmountPercentageForDownPayment();
@@ -2964,19 +2964,26 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
             externalId = ExternalId.generate();
         }
         Money downPaymentMoney = Money.of(getCurrency(),
-                MathUtil.percentageOf(disbursedAmount, 
disbursedAmountPercentageForDownPayment, 19));
-        LoanTransaction downPaymentTransaction = 
LoanTransaction.downPayment(getOffice(), downPaymentMoney, null, disbursedOn, 
externalId);
-
-        LoanEvent event = LoanEvent.LOAN_REPAYMENT_OR_WAIVER;
-        validateRepaymentTypeAccountStatus(downPaymentTransaction, event);
-        HolidayDetailDTO holidayDetailDTO = 
scheduleGeneratorDTO.getHolidayDetailDTO();
-        
validateRepaymentDateIsOnHoliday(downPaymentTransaction.getTransactionDate(), 
holidayDetailDTO.isAllowTransactionsOnHoliday(),
-                holidayDetailDTO.getHolidays());
-        
validateRepaymentDateIsOnNonWorkingDay(downPaymentTransaction.getTransactionDate(),
 holidayDetailDTO.getWorkingDays(),
-                holidayDetailDTO.isAllowTransactionsOnNonWorkingDay());
+                MathUtil.percentageOf(disbursementTransaction.getAmount(), 
disbursedAmountPercentageForDownPayment, 19));
+
+        Money adjustedDownPaymentMoney = MathUtil
+                
.negativeToZero(downPaymentMoney.minus(disbursementTransaction.getOverPaymentPortion(getCurrency())));
+        if (adjustedDownPaymentMoney.isGreaterThanZero()) {
+            LoanTransaction downPaymentTransaction = 
LoanTransaction.downPayment(getOffice(), adjustedDownPaymentMoney, null, 
disbursedOn,
+                    externalId);
+            LoanEvent event = LoanEvent.LOAN_REPAYMENT_OR_WAIVER;
+            validateRepaymentTypeAccountStatus(downPaymentTransaction, event);
+            HolidayDetailDTO holidayDetailDTO = 
scheduleGeneratorDTO.getHolidayDetailDTO();
+            
validateRepaymentDateIsOnHoliday(downPaymentTransaction.getTransactionDate(), 
holidayDetailDTO.isAllowTransactionsOnHoliday(),
+                    holidayDetailDTO.getHolidays());
+            
validateRepaymentDateIsOnNonWorkingDay(downPaymentTransaction.getTransactionDate(),
 holidayDetailDTO.getWorkingDays(),
+                    holidayDetailDTO.isAllowTransactionsOnNonWorkingDay());
 
-        handleRepaymentOrRecoveryOrWaiverTransaction(downPaymentTransaction, 
loanLifecycleStateMachine, null, scheduleGeneratorDTO);
-        return downPaymentTransaction;
+            
handleRepaymentOrRecoveryOrWaiverTransaction(downPaymentTransaction, 
loanLifecycleStateMachine, null, scheduleGeneratorDTO);
+            return downPaymentTransaction;
+        } else {
+            return null;
+        }
     }
 
     public boolean isAutoRepaymentForDownPaymentEnabled() {
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 1afa4f617..53de2b0ef 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
@@ -465,10 +465,13 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
                 newLoanTransaction.adjustInterestComponent(currency);
             }
             /*
-             * Check if the transaction amounts have changed. If so, reverse 
the original transaction and update
-             * changedTransactionDetail accordingly
+             * Check if the transaction amounts have changed or was there any 
transaction for the same date which was
+             * reverse-replayed. If so, reverse the original transaction and 
update changedTransactionDetail accordingly
              */
-            if (LoanTransaction.transactionAmountsMatch(currency, 
loanTransaction, newLoanTransaction)) {
+            boolean aTransactionWasAlreadyReplayedForTheSameDate = 
changedTransactionDetail.getNewTransactionMappings().values().stream()
+                    .anyMatch(lt -> 
lt.getTransactionDate().equals(loanTransaction.getTransactionDate()));
+            if (LoanTransaction.transactionAmountsMatch(currency, 
loanTransaction, newLoanTransaction)
+                    && !aTransactionWasAlreadyReplayedForTheSameDate) {
                 
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(
                         
newLoanTransaction.getLoanTransactionToRepaymentScheduleMappings());
             } else {
@@ -503,6 +506,7 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
 
     private void updateLoanSchedule(LoanTransaction disbursementTransaction, 
MonetaryCurrency currency,
             List<LoanRepaymentScheduleInstallment> installments, MoneyHolder 
overpaymentHolder) {
+        disbursementTransaction.resetDerivedComponents();
         final MathContext mc = MoneyHelper.getMathContext();
         List<LoanRepaymentScheduleInstallment> candidateRepaymentInstallments 
= installments.stream().filter(
                 i -> 
i.getDueDate().isAfter(disbursementTransaction.getTransactionDate()) && 
!i.isDownPayment() && !i.isAdditional())
@@ -570,9 +574,7 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
                 transactionAmountUnprocessed = 
processPeriodsVertically(loanTransaction, currency, installments,
                         overpaymentHolder.getMoneyObject(), 
defaultPaymentAllocationRule, transactionMappings, Set.of(), balances);
             }
-            if (transactionAmountUnprocessed != null && 
transactionAmountUnprocessed.isGreaterThanZero()) {
-                overpaymentHolder.setMoneyObject(transactionAmountUnprocessed);
-            }
+            overpaymentHolder.setMoneyObject(transactionAmountUnprocessed);
             
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(transactionMappings);
         }
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerService.java
index 1bf1564cd..57ee4e9c3 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerService.java
@@ -19,12 +19,12 @@
 package org.apache.fineract.portfolio.loanaccount.service;
 
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
 
 public interface LoanDownPaymentHandlerService {
 
-    LoanTransaction handleDownPayment(ScheduleGeneratorDTO 
scheduleGeneratorDTO, JsonCommand command, Money amountToDisburse, Loan loan);
+    LoanTransaction handleDownPayment(ScheduleGeneratorDTO 
scheduleGeneratorDTO, JsonCommand command,
+            LoanTransaction disbursementTransaction, Loan loan);
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
index 1825fff8f..8fdc76e98 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
@@ -25,7 +25,6 @@ import 
org.apache.fineract.infrastructure.event.business.domain.loan.LoanBalance
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionDownPaymentPostBusinessEvent;
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionDownPaymentPreBusinessEvent;
 import 
org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
-import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
@@ -39,13 +38,15 @@ public class LoanDownPaymentHandlerServiceImpl implements 
LoanDownPaymentHandler
     private final BusinessEventNotifierService businessEventNotifierService;
 
     @Override
-    public LoanTransaction handleDownPayment(ScheduleGeneratorDTO 
scheduleGeneratorDTO, JsonCommand command, Money amountToDisburse,
-            Loan loan) {
+    public LoanTransaction handleDownPayment(ScheduleGeneratorDTO 
scheduleGeneratorDTO, JsonCommand command,
+            LoanTransaction disbursementTransaction, Loan loan) {
         businessEventNotifierService.notifyPreBusinessEvent(new 
LoanTransactionDownPaymentPreBusinessEvent(loan));
-        LoanTransaction downPaymentTransaction = 
loan.handleDownPayment(amountToDisburse.getAmount(), command, 
scheduleGeneratorDTO);
-        LoanTransaction savedLoanTransaction = 
loanTransactionRepository.saveAndFlush(downPaymentTransaction);
-        businessEventNotifierService.notifyPostBusinessEvent(new 
LoanTransactionDownPaymentPostBusinessEvent(savedLoanTransaction));
-        businessEventNotifierService.notifyPostBusinessEvent(new 
LoanBalanceChangedBusinessEvent(loan));
-        return savedLoanTransaction;
+        LoanTransaction downPaymentTransaction = 
loan.handleDownPayment(disbursementTransaction, command, scheduleGeneratorDTO);
+        if (downPaymentTransaction != null) {
+            downPaymentTransaction = 
loanTransactionRepository.saveAndFlush(downPaymentTransaction);
+            businessEventNotifierService.notifyPostBusinessEvent(new 
LoanTransactionDownPaymentPostBusinessEvent(downPaymentTransaction));
+            businessEventNotifierService.notifyPostBusinessEvent(new 
LoanBalanceChangedBusinessEvent(loan));
+        }
+        return downPaymentTransaction;
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 565812c8e..a34a3071f 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -485,7 +485,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                             fromSavingsAccount, isRegularTransaction, 
isExceptionForBalanceCheck);
                     
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
                 } else {
-                    
loanDownPaymentHandlerService.handleDownPayment(scheduleGeneratorDTO, command, 
amountToDisburse, loan);
+                    
loanDownPaymentHandlerService.handleDownPayment(scheduleGeneratorDTO, command, 
disbursementTransaction, loan);
                 }
             }
         }
@@ -563,6 +563,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
             businessEventNotifierService.notifyPostBusinessEvent(new 
LoanDisbursalTransactionBusinessEvent(disbursalTransaction));
         }
 
+        loan.updateLoanSummaryAndStatus();
+
         return new CommandProcessingResultBuilder() //
                 .withCommandId(command.commandId()) //
                 .withEntityId(loan.getId()) //
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImplTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImplTest.java
index eae94acf4..0bfa16ad2 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImplTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImplTest.java
@@ -19,13 +19,13 @@
 package org.apache.fineract.portfolio.loanaccount.service;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.math.BigDecimal;
 import java.math.RoundingMode;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.LoanBalanceChangedBusinessEvent;
@@ -33,7 +33,6 @@ import 
org.apache.fineract.infrastructure.event.business.domain.loan.transaction
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionDownPaymentPreBusinessEvent;
 import 
org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
-import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -88,19 +87,19 @@ public class LoanDownPaymentHandlerServiceImplTest {
     public void testDownPaymentHandler() {
         // given
         Loan loanForProcessing = Mockito.mock(Loan.class);
+        LoanTransaction disbursement = Mockito.mock(LoanTransaction.class);
         MonetaryCurrency loanCurrency = Mockito.mock(MonetaryCurrency.class);
         
doNothing().when(businessEventNotifierService).notifyPreBusinessEvent(any(LoanTransactionDownPaymentPreBusinessEvent.class));
         
doNothing().when(businessEventNotifierService).notifyPostBusinessEvent(any(LoanTransactionDownPaymentPostBusinessEvent.class));
         
doNothing().when(businessEventNotifierService).notifyPostBusinessEvent(any(LoanBalanceChangedBusinessEvent.class));
         
when(loanTransactionRepository.saveAndFlush(any(LoanTransaction.class))).thenReturn(loanTransaction);
-        when(loanForProcessing.handleDownPayment(any(BigDecimal.class), 
eq(command), eq(scheduleGeneratorDTO))).thenReturn(loanTransaction);
+        when(loanForProcessing.handleDownPayment(eq(disbursement), 
eq(command), eq(scheduleGeneratorDTO))).thenReturn(loanTransaction);
         when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
         when(loanCurrency.getCode()).thenReturn("CODE");
         when(loanCurrency.getCurrencyInMultiplesOf()).thenReturn(1);
         when(loanCurrency.getDigitsAfterDecimal()).thenReturn(1);
-        Money amount = Money.of(loanCurrency, BigDecimal.TEN);
         // when
-        LoanTransaction actual = 
underTest.handleDownPayment(scheduleGeneratorDTO, command, amount, 
loanForProcessing);
+        LoanTransaction actual = 
underTest.handleDownPayment(scheduleGeneratorDTO, command, disbursement, 
loanForProcessing);
 
         // then
         assertNotNull(actual);
@@ -109,6 +108,32 @@ public class LoanDownPaymentHandlerServiceImplTest {
         verify(businessEventNotifierService, Mockito.times(1))
                 
.notifyPostBusinessEvent(Mockito.any(LoanTransactionDownPaymentPostBusinessEvent.class));
         verify(businessEventNotifierService, 
Mockito.times(1)).notifyPostBusinessEvent(Mockito.any(LoanBalanceChangedBusinessEvent.class));
-        verify(loanForProcessing, 
Mockito.times(1)).handleDownPayment(any(BigDecimal.class), eq(command), 
eq(scheduleGeneratorDTO));
+        verify(loanForProcessing, 
Mockito.times(1)).handleDownPayment(eq(disbursement), eq(command), 
eq(scheduleGeneratorDTO));
+    }
+
+    @Test
+    public void testDownPaymentHandlerNoNewTransaction() {
+        // given
+        Loan loanForProcessing = Mockito.mock(Loan.class);
+        LoanTransaction disbursement = Mockito.mock(LoanTransaction.class);
+        MonetaryCurrency loanCurrency = Mockito.mock(MonetaryCurrency.class);
+        
doNothing().when(businessEventNotifierService).notifyPreBusinessEvent(any(LoanTransactionDownPaymentPreBusinessEvent.class));
+        when(loanForProcessing.handleDownPayment(eq(disbursement), 
eq(command), eq(scheduleGeneratorDTO))).thenReturn(null);
+        when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
+        when(loanCurrency.getCode()).thenReturn("CODE");
+        when(loanCurrency.getCurrencyInMultiplesOf()).thenReturn(1);
+        when(loanCurrency.getDigitsAfterDecimal()).thenReturn(1);
+        // when
+        LoanTransaction actual = 
underTest.handleDownPayment(scheduleGeneratorDTO, command, disbursement, 
loanForProcessing);
+
+        // then
+        assertNull(actual);
+        verify(businessEventNotifierService, Mockito.times(1))
+                
.notifyPreBusinessEvent(Mockito.any(LoanTransactionDownPaymentPreBusinessEvent.class));
+        verify(businessEventNotifierService, Mockito.never())
+                
.notifyPostBusinessEvent(Mockito.any(LoanTransactionDownPaymentPostBusinessEvent.class));
+        verify(businessEventNotifierService, 
Mockito.never()).notifyPostBusinessEvent(Mockito.any(LoanBalanceChangedBusinessEvent.class));
+        verify(loanForProcessing, 
Mockito.times(1)).handleDownPayment(eq(disbursement), eq(command), 
eq(scheduleGeneratorDTO));
+        verify(loanTransactionRepository, 
Mockito.never()).saveAndFlush(any(LoanTransaction.class));
     }
 }
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 f6723cf77..d6cb8f4f5 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
@@ -3264,7 +3264,7 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 7), 
32.0, 32.0, 0.0, 32.0, 0.0);
             validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 12, 
22), 32.0, 32.0, 0.0, 32.0, 0.0);
             validateRepaymentPeriod(loanDetails, 5, LocalDate.of(2024, 1, 6), 
32.0, 32.0, 0.0, 32.0, 0.0);
-            assertTrue(loanDetails.getStatus().getActive());
+            assertTrue(loanDetails.getStatus().getOverpaid());
 
             verifyTransactions(loanResponse.getLoanId(), //
                     transaction(100, "Disbursement", "22 November 2023", 
100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java
index 2b11a04b1..3dc8891ab 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java
@@ -19,9 +19,7 @@
 package org.apache.fineract.integrationtests;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import io.restassured.builder.RequestSpecBuilder;
 import io.restassured.builder.ResponseSpecBuilder;
@@ -29,29 +27,14 @@ import io.restassured.http.ContentType;
 import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
 import java.math.BigDecimal;
-import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.UUID;
 import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
 import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
-import org.apache.fineract.client.models.GetLoansLoanIdResponse;
-import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
-import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
 import org.apache.fineract.client.models.PutLoanProductsProductIdRequest;
 import org.apache.fineract.client.models.PutLoanProductsProductIdResponse;
-import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
-import org.apache.fineract.infrastructure.core.service.DateUtils;
-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.Utils;
-import org.apache.fineract.integrationtests.common.accounting.Account;
-import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
-import org.apache.fineract.integrationtests.common.accounting.JournalEntry;
-import 
org.apache.fineract.integrationtests.common.accounting.JournalEntryHelper;
-import 
org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
 import 
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
 import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
 import 
org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
@@ -63,9 +46,6 @@ public class LoanProductWithDownPaymentConfigurationTest {
     private ResponseSpecification responseSpec;
     private RequestSpecification requestSpec;
     private LoanTransactionHelper loanTransactionHelper;
-    private ClientHelper clientHelper;
-    private AccountHelper accountHelper;
-    private JournalEntryHelper journalEntryHelper;
 
     @BeforeEach
     public void setup() {
@@ -74,9 +54,6 @@ public class LoanProductWithDownPaymentConfigurationTest {
         this.requestSpec.header("Authorization", "Basic " + 
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
         this.responseSpec = new 
ResponseSpecBuilder().expectStatusCode(200).build();
         this.loanTransactionHelper = new 
LoanTransactionHelper(this.requestSpec, this.responseSpec);
-        this.clientHelper = new ClientHelper(this.requestSpec, 
this.responseSpec);
-        this.accountHelper = new AccountHelper(this.requestSpec, 
this.responseSpec);
-        this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, 
this.responseSpec);
     }
 
     @Test
@@ -198,412 +175,6 @@ public class LoanProductWithDownPaymentConfigurationTest {
                 
loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
     }
 
-    @Test
-    public void 
loanApplicationCreationWithLoanProductWithEnableDownPaymentConfiguration() {
-        // Loan ExternalId
-        String loanExternalIdStr = UUID.randomUUID().toString();
-
-        // Delinquency Bucket
-        final Integer delinquencyBucketId = 
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
-        final GetDelinquencyBucketsResponse delinquencyBucket = 
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
-                delinquencyBucketId);
-
-        // down-payment configuration
-        Boolean enableDownPayment = true;
-        BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
-        Boolean enableAutoRepaymentForDownPayment = false;
-
-        final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
-
-        // Loan Product creation with down-payment configuration
-        Integer loanProductId = 
createLoanProductWithDownPaymentConfiguration(loanTransactionHelper, 
delinquencyBucketId, enableDownPayment,
-                "25", enableAutoRepaymentForDownPayment);
-
-        final GetLoanProductsProductIdResponse getLoanProductsProductResponse 
= loanTransactionHelper.getLoanProduct(loanProductId);
-        assertNotNull(getLoanProductsProductResponse);
-        assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
-        assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
-                .compareTo(disbursedAmountPercentageForDownPayment));
-        assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
-
-        final Integer loanId = createApproveAndDisburseLoanAccount(clientId, 
loanProductId.longValue(), loanExternalIdStr);
-
-        // Retrieve Loan with loanId
-
-        GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
-
-        // verify down-payment details for Loan
-        assertNotNull(loanDetails);
-        assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
-        assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
-        assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
-
-    }
-
-    @Test
-    public void 
loanApplicationWithLoanProductWithEnableDownPaymentConfigurationDoesNotChangeWithUpdateProductConfiguration()
 {
-        // Loan ExternalId
-        String loanExternalIdStr = UUID.randomUUID().toString();
-
-        // Delinquency Bucket
-        final Integer delinquencyBucketId = 
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
-        final GetDelinquencyBucketsResponse delinquencyBucket = 
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
-                delinquencyBucketId);
-
-        // down-payment configuration
-        Boolean enableDownPayment = true;
-        BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(12.5);
-        Boolean enableAutoRepaymentForDownPayment = false;
-
-        final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
-
-        // Loan Product creation with down-payment configuration
-        Integer loanProductId = 
createLoanProductWithDownPaymentConfiguration(loanTransactionHelper, 
delinquencyBucketId, enableDownPayment,
-                "12.5", enableAutoRepaymentForDownPayment);
-
-        final GetLoanProductsProductIdResponse getLoanProductsProductResponse 
= loanTransactionHelper.getLoanProduct(loanProductId);
-        assertNotNull(getLoanProductsProductResponse);
-        assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
-        assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
-                .compareTo(disbursedAmountPercentageForDownPayment));
-        assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
-
-        final Integer loanId = createApproveAndDisburseLoanAccount(clientId, 
loanProductId.longValue(), loanExternalIdStr);
-
-        // Retrieve Loan with loanId
-
-        GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
-
-        // verify down-payment details for Loan
-        assertNotNull(loanDetails);
-        assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
-        assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
-        assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
-
-        // Modify Loan Product to update enable down payment configuration
-        PutLoanProductsProductIdResponse loanProductModifyResponse = 
updateLoanProduct(loanTransactionHelper,
-                getLoanProductsProductResponse.getId());
-        assertNotNull(loanProductModifyResponse);
-
-        // verify Loan product configuration change
-        GetLoanProductsProductIdResponse getLoanProductsProductResponse_1 = 
loanTransactionHelper.getLoanProduct(loanProductId);
-        assertNotNull(getLoanProductsProductResponse_1);
-        assertEquals(enableDownPayment, 
getLoanProductsProductResponse_1.getEnableDownPayment());
-        assertEquals(0, 
getLoanProductsProductResponse_1.getDisbursedAmountPercentageForDownPayment().compareTo(BigDecimal.valueOf(25.0)));
-        assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse_1.getEnableAutoRepaymentForDownPayment());
-
-        // make repayment for loan
-        final PostLoansLoanIdTransactionsResponse repaymentTransaction_1 = 
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
-                new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM 
yyyy").transactionDate("5 September 2022").locale("en")
-                        .transactionAmount(100.0));
-
-        loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
-
-        // verify down-payment details for Loan does not change
-        assertNotNull(loanDetails);
-        assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
-        assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
-        assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
-
-    }
-
-    @Test
-    public void 
loanApplicationWithLoanProductWithEnableDownPaymentAndEnableAutoRepaymentForDownPaymentTest()
 {
-        try {
-
-            // Set business date
-            LocalDate disbursementDate = LocalDate.of(2023, 3, 3);
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
-            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
-
-            // Accounts oof periodic accrual
-            final Account assetAccount = 
this.accountHelper.createAssetAccount();
-            final Account incomeAccount = 
this.accountHelper.createIncomeAccount();
-            final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
-            final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
-
-            // Loan ExternalId
-            String loanExternalIdStr = UUID.randomUUID().toString();
-
-            // Delinquency Bucket
-            final Integer delinquencyBucketId = 
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
-            final GetDelinquencyBucketsResponse delinquencyBucket = 
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
-                    delinquencyBucketId);
-
-            // down-payment configuration
-            Boolean enableDownPayment = true;
-            BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
-            Boolean enableAutoRepaymentForDownPayment = true;
-
-            final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
-
-            // Loan Product creation with down-payment configuration
-            final GetLoanProductsProductIdResponse 
getLoanProductsProductResponse = 
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
-                    loanTransactionHelper, delinquencyBucketId, 
enableDownPayment, "25", enableAutoRepaymentForDownPayment, assetAccount,
-                    incomeAccount, expenseAccount, overpaymentAccount);
-
-            assertNotNull(getLoanProductsProductResponse);
-            assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
-            assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
-                    .compareTo(disbursedAmountPercentageForDownPayment));
-            assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
-
-            final Integer loanId = 
createLoanAccountMultipleRepaymentsDisbursement(clientId, 
getLoanProductsProductResponse.getId(),
-                    loanExternalIdStr);
-
-            // Retrieve Loan with loanId
-
-            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
-
-            // verify down-payment details for Loan
-            assertNotNull(loanDetails);
-            assertEquals(enableDownPayment, 
loanDetails.getEnableDownPayment());
-            assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
-            assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
-
-            // first disbursement
-            loanTransactionHelper.disburseLoanWithTransactionAmount("03 March 
2023", loanId, "1000");
-
-            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
-            // verify down-payment transaction created
-            checkDownPaymentTransaction(disbursementDate, 250.0f, 0.0f, 0.0f, 
0.0f, loanId);
-
-            // verify journal entries for down-payment
-            
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "03 
March 2023",
-                    new JournalEntry(250, 
JournalEntry.TransactionType.CREDIT));
-            
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "03 
March 2023",
-                    new JournalEntry(250, JournalEntry.TransactionType.DEBIT));
-
-            // verify installment details
-            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate());
-            assertEquals(1000.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getPrincipalLoanBalanceOutstanding());
-            assertEquals(1, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
-            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
-            assertEquals(250.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
-            assertEquals(true, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDownPaymentPeriod());
-            assertEquals(2, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
-            assertEquals(LocalDate.of(2023, 4, 2), 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
-            assertEquals(750.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
-            assertEquals(false, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDownPaymentPeriod());
-
-            // second disbursement
-
-            disbursementDate = LocalDate.of(2023, 3, 5);
-            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
-            loanTransactionHelper.disburseLoanWithTransactionAmount("05 March 
2023", loanId, "200");
-            checkDownPaymentTransaction(disbursementDate, 50.0f, 0.0f, 0.0f, 
0.0f, loanId);
-
-            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
-            // verify installment details
-            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate());
-            assertEquals(1000.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getPrincipalLoanBalanceOutstanding());
-            assertEquals(1, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
-            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
-            assertEquals(250.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
-            assertEquals(true, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDownPaymentPeriod());
-            assertEquals(LocalDate.of(2023, 3, 5), 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
-            assertEquals(200.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getPrincipalLoanBalanceOutstanding());
-            assertEquals(false, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDownPaymentPeriod());
-            assertEquals(2, 
loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
-            assertEquals(LocalDate.of(2023, 3, 5), 
loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
-            assertEquals(50.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
-            assertEquals(true, 
loanDetails.getRepaymentSchedule().getPeriods().get(3).getDownPaymentPeriod());
-            assertEquals(3, 
loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod());
-            assertEquals(LocalDate.of(2023, 4, 2), 
loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate());
-            assertEquals(900.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod());
-            assertEquals(false, 
loanDetails.getRepaymentSchedule().getPeriods().get(4).getDownPaymentPeriod());
-
-            // verify journal entries for down-payment
-            
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "05 
March 2023",
-                    new JournalEntry(50, JournalEntry.TransactionType.CREDIT));
-            
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "05 
March 2023",
-                    new JournalEntry(50, JournalEntry.TransactionType.DEBIT));
-
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
-        }
-
-    }
-
-    @Test
-    public void 
loanApplicationWithLoanProductWithEnableDownPaymentAndDisableAutoRepaymentForDownPaymentVerifyNoDownPaymentCreatedTest()
 {
-        try {
-
-            // Set business date
-            LocalDate disbursementDate = LocalDate.of(2023, 3, 3);
-
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
-            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
-
-            // Accounts oof periodic accrual
-            final Account assetAccount = 
this.accountHelper.createAssetAccount();
-            final Account incomeAccount = 
this.accountHelper.createIncomeAccount();
-            final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
-            final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
-
-            // Loan ExternalId
-            String loanExternalIdStr = UUID.randomUUID().toString();
-
-            // Delinquency Bucket
-            final Integer delinquencyBucketId = 
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
-            final GetDelinquencyBucketsResponse delinquencyBucket = 
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
-                    delinquencyBucketId);
-
-            // down-payment configuration
-            Boolean enableDownPayment = true;
-            BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
-            Boolean enableAutoRepaymentForDownPayment = false;
-
-            final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
-
-            // Loan Product creation with down-payment configuration
-            final GetLoanProductsProductIdResponse 
getLoanProductsProductResponse = 
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
-                    loanTransactionHelper, delinquencyBucketId, 
enableDownPayment, "25", enableAutoRepaymentForDownPayment, assetAccount,
-                    incomeAccount, expenseAccount, overpaymentAccount);
-
-            assertNotNull(getLoanProductsProductResponse);
-            assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
-            assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
-                    .compareTo(disbursedAmountPercentageForDownPayment));
-            assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
-
-            final Integer loanId = 
createLoanAccountMultipleRepaymentsDisbursement(clientId, 
getLoanProductsProductResponse.getId(),
-                    loanExternalIdStr);
-
-            // Retrieve Loan with loanId
-
-            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
-
-            // verify down-payment details for Loan
-            assertNotNull(loanDetails);
-            assertEquals(enableDownPayment, 
loanDetails.getEnableDownPayment());
-            assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
-            assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
-
-            // first disbursement
-            loanTransactionHelper.disburseLoanWithTransactionAmount("03 March 
2023", loanId, "1000");
-
-            // verify no down-payment transaction created
-            checkNoDownPaymentTransaction(loanId);
-
-        } finally {
-            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
-        }
-
-    }
-
-    @Test
-    public void 
loanProductAndLoanAccountCreationWithEnableDownPaymentAndDisableRepaymentScheduleExtensionConfigurationTest()
 {
-        // Loan ExternalId
-        String loanExternalIdStr = UUID.randomUUID().toString();
-
-        // down-payment configuration
-        Boolean enableDownPayment = true;
-        BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
-        Boolean enableAutoRepaymentForDownPayment = false;
-
-        final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
-
-        // Loan Product creation with down-payment configuration
-        GetLoanProductsProductIdResponse getLoanProductsProductResponse = 
createLoanProductWithEnableDownPaymentAndMultipleDisbursementsWithDisableRepaymentConfiguration(
-                loanTransactionHelper, enableDownPayment, "25", 
enableAutoRepaymentForDownPayment);
-        assertNotNull(getLoanProductsProductResponse);
-        assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
-        assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
-                .compareTo(disbursedAmountPercentageForDownPayment));
-        assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
-
-        final Integer loanId = 
createLoanAccountMultipleRepaymentsDisbursement(clientId, 
getLoanProductsProductResponse.getId(),
-                loanExternalIdStr);
-
-        // Retrieve Loan with loanId
-
-        GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
-
-        // verify down-payment details for Loan
-        assertNotNull(loanDetails);
-        assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
-        assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
-        assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
-    }
-
-    private void checkNoDownPaymentTransaction(final Integer loanID) {
-        ArrayList<HashMap> transactions = (ArrayList<HashMap>) 
loanTransactionHelper.getLoanTransactions(this.requestSpec,
-                this.responseSpec, loanID);
-        boolean isTransactionFound = false;
-        for (int i = 0; i < transactions.size(); i++) {
-            HashMap transactionType = (HashMap) 
transactions.get(i).get("type");
-            boolean isDownPaymentTransaction = (Boolean) 
transactionType.get("downPayment");
-
-            if (isDownPaymentTransaction) {
-                isTransactionFound = true;
-                break;
-            }
-        }
-        assertFalse(isTransactionFound, "Down Payment entries are posted");
-    }
-
-    private void checkDownPaymentTransaction(final LocalDate transactionDate, 
final Float principalPortion, final Float interestPortion,
-            final Float feePortion, final Float penaltyPortion, final Integer 
loanID) {
-        ArrayList<HashMap> transactions = (ArrayList<HashMap>) 
loanTransactionHelper.getLoanTransactions(this.requestSpec,
-                this.responseSpec, loanID);
-        boolean isTransactionFound = false;
-        for (int i = 0; i < transactions.size(); i++) {
-            HashMap transactionType = (HashMap) 
transactions.get(i).get("type");
-            boolean isDownPaymentTransaction = (Boolean) 
transactionType.get("downPayment");
-
-            if (isDownPaymentTransaction) {
-                ArrayList<Integer> downPaymentDateAsArray = 
(ArrayList<Integer>) transactions.get(i).get("date");
-                LocalDate downPaymentEntryDate = 
LocalDate.of(downPaymentDateAsArray.get(0), downPaymentDateAsArray.get(1),
-                        downPaymentDateAsArray.get(2));
-
-                if (DateUtils.isEqual(transactionDate, downPaymentEntryDate)) {
-                    isTransactionFound = true;
-                    assertEquals(principalPortion, 
Float.valueOf(String.valueOf(transactions.get(i).get("principalPortion"))),
-                            "Mismatch in transaction amounts");
-                    assertEquals(interestPortion, 
Float.valueOf(String.valueOf(transactions.get(i).get("interestPortion"))),
-                            "Mismatch in transaction amounts");
-                    assertEquals(feePortion, 
Float.valueOf(String.valueOf(transactions.get(i).get("feeChargesPortion"))),
-                            "Mismatch in transaction amounts");
-                    assertEquals(penaltyPortion, 
Float.valueOf(String.valueOf(transactions.get(i).get("penaltyChargesPortion"))),
-                            "Mismatch in transaction amounts");
-                    break;
-                }
-            }
-        }
-        assertTrue(isTransactionFound, "No Down Payment entries are posted");
-    }
-
-    private Integer createLoanAccountMultipleRepaymentsDisbursement(final 
Integer clientID, final Long loanProductID,
-            final String externalId) {
-
-        String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("30")
-                
.withLoanTermFrequencyAsDays().withNumberOfRepayments("1").withRepaymentEveryAfter("30").withRepaymentFrequencyTypeAsDays()
-                
.withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments()
-                
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03
 March 2023")
-                .withSubmittedOnDate("03 March 
2023").withLoanType("individual").withExternalId(externalId)
-                .build(clientID.toString(), loanProductID.toString(), null);
-
-        final Integer loanId = 
loanTransactionHelper.getLoanId(loanApplicationJSON);
-        loanTransactionHelper.approveLoan("03 March 2023", "1000", loanId, 
null);
-        return loanId;
-    }
-
-    private GetLoanProductsProductIdResponse 
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
-            LoanTransactionHelper loanTransactionHelper, Integer 
delinquencyBucketId, Boolean enableDownPayment,
-            String disbursedAmountPercentageForDownPayment, boolean 
enableAutoRepaymentForDownPayment, final Account... accounts) {
-        final String loanProductJSON = new 
LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
-                
.withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
-                
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
-                
.withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30")
-                .withDaysInYear("365").withMoratorium("0", 
"0").withMultiDisburse().withDisallowExpectedDisbursements(true)
-                .withEnableDownPayment(enableDownPayment, 
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
-                .build(null);
-        final Integer loanProductId = 
loanTransactionHelper.getLoanProductId(loanProductJSON);
-        return loanTransactionHelper.getLoanProduct(loanProductId);
-    }
-
     private PutLoanProductsProductIdResponse 
updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id) {
         // down-payment configuration
         Boolean enableDownPayment = true;
@@ -629,34 +200,4 @@ public class LoanProductWithDownPaymentConfigurationTest {
         final Integer loanProductId = 
loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
         return loanProductId;
     }
-
-    private Integer createApproveAndDisburseLoanAccount(final Integer 
clientID, final Long loanProductID, final String externalId) {
-
-        String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")
-                
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1")
-                
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance()
-                
.withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
-                .withExpectedDisbursementDate("03 September 
2022").withSubmittedOnDate("01 September 2022").withLoanType("individual")
-                .withExternalId(externalId).build(clientID.toString(), 
loanProductID.toString(), null);
-
-        final Integer loanId = 
loanTransactionHelper.getLoanId(loanApplicationJSON);
-        loanTransactionHelper.approveLoan("02 September 2022", "1000", loanId, 
null);
-        loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September 
2022", loanId, "1000");
-        return loanId;
-    }
-
-    private GetLoanProductsProductIdResponse 
createLoanProductWithEnableDownPaymentAndMultipleDisbursementsWithDisableRepaymentConfiguration(
-            LoanTransactionHelper loanTransactionHelper, Boolean 
enableDownPayment, String disbursedAmountPercentageForDownPayment,
-            boolean enableAutoRepaymentForDownPayment) {
-        final String loanProductJSON = new 
LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
-                
.withRepaymentAfterEvery("1").withNumberOfRepayments("3").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
-                
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
-                
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365")
-                .withMoratorium("0", 
"0").withMultiDisburse().withDisallowExpectedDisbursements(true)
-                .withEnableDownPayment(enableDownPayment, 
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
-                .build(null);
-        final Integer loanProductId = 
loanTransactionHelper.getLoanProductId(loanProductJSON);
-        return loanTransactionHelper.getLoanProduct(loanProductId);
-    }
-
 }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java
index 3dd00a8d0..2db85269b 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java
@@ -18,7 +18,9 @@
  */
 package org.apache.fineract.integrationtests;
 
+import static 
org.apache.fineract.integrationtests.BaseLoanIntegrationTest.DATETIME_PATTERN;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -29,45 +31,71 @@ import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
 import java.math.BigDecimal;
 import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.fineract.client.models.AdvancedPaymentData;
 import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
 import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
 import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
 import org.apache.fineract.client.models.GetLoansLoanIdSummary;
+import org.apache.fineract.client.models.PaymentAllocationOrder;
 import org.apache.fineract.client.models.PostChargesResponse;
 import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
+import 
org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
+import org.apache.fineract.client.models.PutLoanProductsProductIdRequest;
+import org.apache.fineract.client.models.PutLoanProductsProductIdResponse;
 import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
 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.SchedulerJobHelper;
 import org.apache.fineract.integrationtests.common.Utils;
+import org.apache.fineract.integrationtests.common.accounting.Account;
+import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
+import org.apache.fineract.integrationtests.common.accounting.JournalEntry;
+import 
org.apache.fineract.integrationtests.common.accounting.JournalEntryHelper;
 import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
 import 
org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
 import 
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
+import 
org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
 import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
 import 
org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
+import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 
+@ExtendWith(LoanTestLifecycleExtension.class)
 public class LoanRepaymentScheduleWithDownPaymentTest {
 
     private ResponseSpecification responseSpec;
     private RequestSpecification requestSpec;
     private LoanTransactionHelper loanTransactionHelper;
     private ClientHelper clientHelper;
+    private AccountHelper accountHelper;
+    private JournalEntryHelper journalEntryHelper;
 
     @BeforeEach
     public void setup() {
         Utils.initializeRESTAssured();
-        this.requestSpec = new 
RequestSpecBuilder().setContentType(ContentType.JSON).build();
-        this.requestSpec.header("Authorization", "Basic " + 
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
-        this.responseSpec = new 
ResponseSpecBuilder().expectStatusCode(200).build();
-        this.loanTransactionHelper = new 
LoanTransactionHelper(this.requestSpec, this.responseSpec);
-        this.clientHelper = new ClientHelper(this.requestSpec, 
this.responseSpec);
+        requestSpec = new 
RequestSpecBuilder().setContentType(ContentType.JSON).build();
+        requestSpec.header("Authorization", "Basic " + 
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+        responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+        loanTransactionHelper = new LoanTransactionHelper(requestSpec, 
responseSpec);
+        clientHelper = new ClientHelper(requestSpec, responseSpec);
+        accountHelper = new AccountHelper(requestSpec, responseSpec);
+        journalEntryHelper = new JournalEntryHelper(requestSpec, responseSpec);
     }
 
     @Test
@@ -490,7 +518,7 @@ public class LoanRepaymentScheduleWithDownPaymentTest {
         final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
 
         Integer loanProductId = 
createLoanProductWithDownPaymentConfiguration(loanTransactionHelper, 
delinquencyBucketId, enableDownPayment,
-                "25", enableAutoRepaymentForDownPayment, true);
+                "25", enableAutoRepaymentForDownPayment, false);
 
         final GetLoanProductsProductIdResponse getLoanProductsProductResponse 
= loanTransactionHelper.getLoanProduct(loanProductId);
         assertNotNull(getLoanProductsProductResponse);
@@ -876,6 +904,658 @@ public class LoanRepaymentScheduleWithDownPaymentTest {
         }
     }
 
+    @Test
+    public void 
loanApplicationCreationWithLoanProductWithEnableDownPaymentConfiguration() {
+        // Loan ExternalId
+        String loanExternalIdStr = UUID.randomUUID().toString();
+
+        // Delinquency Bucket
+        final Integer delinquencyBucketId = 
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
+        final GetDelinquencyBucketsResponse delinquencyBucket = 
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
+                delinquencyBucketId);
+
+        // down-payment configuration
+        Boolean enableDownPayment = true;
+        BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
+        Boolean enableAutoRepaymentForDownPayment = false;
+
+        final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+
+        // Loan Product creation with down-payment configuration
+        Integer loanProductId = 
createLoanProductWithDownPaymentConfiguration(loanTransactionHelper, 
delinquencyBucketId, enableDownPayment,
+                "25", enableAutoRepaymentForDownPayment, false);
+
+        final GetLoanProductsProductIdResponse getLoanProductsProductResponse 
= loanTransactionHelper.getLoanProduct(loanProductId);
+        assertNotNull(getLoanProductsProductResponse);
+        assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
+        assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+                .compareTo(disbursedAmountPercentageForDownPayment));
+        assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+        final Integer loanId = createApproveAndDisburseLoanAccount(clientId, 
loanProductId.longValue(), loanExternalIdStr);
+
+        // Retrieve Loan with loanId
+
+        GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+        // verify down-payment details for Loan
+        assertNotNull(loanDetails);
+        assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
+        assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+        assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+    }
+
+    @Test
+    public void 
loanApplicationWithLoanProductWithEnableDownPaymentConfigurationDoesNotChangeWithUpdateProductConfiguration()
 {
+        // Loan ExternalId
+        String loanExternalIdStr = UUID.randomUUID().toString();
+
+        // Delinquency Bucket
+        final Integer delinquencyBucketId = 
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
+        final GetDelinquencyBucketsResponse delinquencyBucket = 
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
+                delinquencyBucketId);
+
+        // down-payment configuration
+        Boolean enableDownPayment = true;
+        BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(12.5);
+        Boolean enableAutoRepaymentForDownPayment = false;
+
+        final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+
+        // Loan Product creation with down-payment configuration
+        Integer loanProductId = 
createLoanProductWithDownPaymentConfiguration(loanTransactionHelper, 
delinquencyBucketId, enableDownPayment,
+                "12.5", enableAutoRepaymentForDownPayment, false);
+
+        final GetLoanProductsProductIdResponse getLoanProductsProductResponse 
= loanTransactionHelper.getLoanProduct(loanProductId);
+        assertNotNull(getLoanProductsProductResponse);
+        assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
+        assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+                .compareTo(disbursedAmountPercentageForDownPayment));
+        assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+        final Integer loanId = createApproveAndDisburseLoanAccount(clientId, 
loanProductId.longValue(), loanExternalIdStr);
+
+        // Retrieve Loan with loanId
+
+        GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+        // verify down-payment details for Loan
+        assertNotNull(loanDetails);
+        assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
+        assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+        assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+        // Modify Loan Product to update enable down payment configuration
+        PutLoanProductsProductIdResponse loanProductModifyResponse = 
updateLoanProduct(loanTransactionHelper,
+                getLoanProductsProductResponse.getId());
+        assertNotNull(loanProductModifyResponse);
+
+        // verify Loan product configuration change
+        GetLoanProductsProductIdResponse getLoanProductsProductResponse_1 = 
loanTransactionHelper.getLoanProduct(loanProductId);
+        assertNotNull(getLoanProductsProductResponse_1);
+        assertEquals(enableDownPayment, 
getLoanProductsProductResponse_1.getEnableDownPayment());
+        assertEquals(0, 
getLoanProductsProductResponse_1.getDisbursedAmountPercentageForDownPayment().compareTo(BigDecimal.valueOf(25.0)));
+        assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse_1.getEnableAutoRepaymentForDownPayment());
+
+        // make repayment for loan
+        final PostLoansLoanIdTransactionsResponse repaymentTransaction_1 = 
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+                new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM 
yyyy").transactionDate("5 September 2022").locale("en")
+                        .transactionAmount(100.0));
+
+        loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+        // verify down-payment details for Loan does not change
+        assertNotNull(loanDetails);
+        assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
+        assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+        assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+    }
+
+    @Test
+    public void 
loanApplicationWithLoanProductWithEnableDownPaymentAndEnableAutoRepaymentForDownPaymentTest()
 {
+        try {
+
+            // Set business date
+            LocalDate disbursementDate = LocalDate.of(2023, 3, 3);
+
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
+
+            // Accounts oof periodic accrual
+            final Account assetAccount = accountHelper.createAssetAccount();
+            final Account incomeAccount = accountHelper.createIncomeAccount();
+            final Account expenseAccount = 
accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = 
accountHelper.createLiabilityAccount();
+
+            // Loan ExternalId
+            String loanExternalIdStr = UUID.randomUUID().toString();
+
+            // Delinquency Bucket
+            final Integer delinquencyBucketId = 
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
+            final GetDelinquencyBucketsResponse delinquencyBucket = 
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
+                    delinquencyBucketId);
+
+            // down-payment configuration
+            Boolean enableDownPayment = true;
+            BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
+            Boolean enableAutoRepaymentForDownPayment = true;
+
+            final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+
+            // Loan Product creation with down-payment configuration
+            final GetLoanProductsProductIdResponse 
getLoanProductsProductResponse = 
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
+                    loanTransactionHelper, delinquencyBucketId, 
enableDownPayment, "25", enableAutoRepaymentForDownPayment, assetAccount,
+                    incomeAccount, expenseAccount, overpaymentAccount);
+
+            assertNotNull(getLoanProductsProductResponse);
+            assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
+            assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+                    .compareTo(disbursedAmountPercentageForDownPayment));
+            assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+            final Integer loanId = 
createLoanAccountMultipleRepaymentsDisbursement(clientId, 
getLoanProductsProductResponse.getId(),
+                    loanExternalIdStr);
+
+            // Retrieve Loan with loanId
+
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+            // verify down-payment details for Loan
+            assertNotNull(loanDetails);
+            assertEquals(enableDownPayment, 
loanDetails.getEnableDownPayment());
+            assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+            assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+            // first disbursement
+            loanTransactionHelper.disburseLoanWithTransactionAmount("03 March 
2023", loanId, "1000");
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+            // verify down-payment transaction created
+            checkDownPaymentTransaction(disbursementDate, 250.0f, 0.0f, 0.0f, 
0.0f, loanId);
+
+            // verify journal entries for down-payment
+            journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, 
"03 March 2023",
+                    new JournalEntry(250, 
JournalEntry.TransactionType.CREDIT));
+            journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, 
"03 March 2023",
+                    new JournalEntry(250, JournalEntry.TransactionType.DEBIT));
+
+            // verify installment details
+            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate());
+            assertEquals(1000.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getPrincipalLoanBalanceOutstanding());
+            assertEquals(1, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
+            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
+            assertEquals(250.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
+            assertEquals(true, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDownPaymentPeriod());
+            assertEquals(2, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
+            assertEquals(LocalDate.of(2023, 4, 2), 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
+            assertEquals(750.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
+            assertEquals(false, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDownPaymentPeriod());
+
+            // second disbursement
+
+            disbursementDate = LocalDate.of(2023, 3, 5);
+            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
+            loanTransactionHelper.disburseLoanWithTransactionAmount("05 March 
2023", loanId, "200");
+            checkDownPaymentTransaction(disbursementDate, 50.0f, 0.0f, 0.0f, 
0.0f, loanId);
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+            // verify installment details
+            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate());
+            assertEquals(1000.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getPrincipalLoanBalanceOutstanding());
+            assertEquals(1, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
+            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
+            assertEquals(250.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
+            assertEquals(true, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDownPaymentPeriod());
+            assertEquals(LocalDate.of(2023, 3, 5), 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
+            assertEquals(200.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getPrincipalLoanBalanceOutstanding());
+            assertEquals(false, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDownPaymentPeriod());
+            assertEquals(2, 
loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
+            assertEquals(LocalDate.of(2023, 3, 5), 
loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
+            assertEquals(50.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
+            assertEquals(true, 
loanDetails.getRepaymentSchedule().getPeriods().get(3).getDownPaymentPeriod());
+            assertEquals(3, 
loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod());
+            assertEquals(LocalDate.of(2023, 4, 2), 
loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate());
+            assertEquals(900.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod());
+            assertEquals(false, 
loanDetails.getRepaymentSchedule().getPeriods().get(4).getDownPaymentPeriod());
+
+            // verify journal entries for down-payment
+            journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, 
"05 March 2023",
+                    new JournalEntry(50, JournalEntry.TransactionType.CREDIT));
+            journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, 
"05 March 2023",
+                    new JournalEntry(50, JournalEntry.TransactionType.DEBIT));
+
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+
+    }
+
+    @Test
+    public void 
loanApplicationWithLoanProductWithEnableDownPaymentAndDisableAutoRepaymentForDownPaymentVerifyNoDownPaymentCreatedTest()
 {
+        try {
+
+            // Set business date
+            LocalDate disbursementDate = LocalDate.of(2023, 3, 3);
+
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
+
+            // Accounts oof periodic accrual
+            final Account assetAccount = accountHelper.createAssetAccount();
+            final Account incomeAccount = accountHelper.createIncomeAccount();
+            final Account expenseAccount = 
accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = 
accountHelper.createLiabilityAccount();
+
+            // Loan ExternalId
+            String loanExternalIdStr = UUID.randomUUID().toString();
+
+            // Delinquency Bucket
+            final Integer delinquencyBucketId = 
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
+            final GetDelinquencyBucketsResponse delinquencyBucket = 
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
+                    delinquencyBucketId);
+
+            // down-payment configuration
+            Boolean enableDownPayment = true;
+            BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
+            Boolean enableAutoRepaymentForDownPayment = false;
+
+            final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+
+            // Loan Product creation with down-payment configuration
+            final GetLoanProductsProductIdResponse 
getLoanProductsProductResponse = 
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
+                    loanTransactionHelper, delinquencyBucketId, 
enableDownPayment, "25", enableAutoRepaymentForDownPayment, assetAccount,
+                    incomeAccount, expenseAccount, overpaymentAccount);
+
+            assertNotNull(getLoanProductsProductResponse);
+            assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
+            assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+                    .compareTo(disbursedAmountPercentageForDownPayment));
+            assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+            final Integer loanId = 
createLoanAccountMultipleRepaymentsDisbursement(clientId, 
getLoanProductsProductResponse.getId(),
+                    loanExternalIdStr);
+
+            // Retrieve Loan with loanId
+
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+            // verify down-payment details for Loan
+            assertNotNull(loanDetails);
+            assertEquals(enableDownPayment, 
loanDetails.getEnableDownPayment());
+            assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+            assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+            // first disbursement
+            loanTransactionHelper.disburseLoanWithTransactionAmount("03 March 
2023", loanId, "1000");
+
+            // verify no down-payment transaction created
+            checkNoDownPaymentTransaction(loanId);
+
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+
+    }
+
+    @Test
+    public void 
loanProductAndLoanAccountCreationWithEnableDownPaymentAndDisableRepaymentScheduleExtensionConfigurationTest()
 {
+        // Loan ExternalId
+        String loanExternalIdStr = UUID.randomUUID().toString();
+
+        // down-payment configuration
+        Boolean enableDownPayment = true;
+        BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
+        Boolean enableAutoRepaymentForDownPayment = false;
+
+        final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+
+        // Loan Product creation with down-payment configuration
+        GetLoanProductsProductIdResponse getLoanProductsProductResponse = 
createLoanProductWithEnableDownPaymentAndMultipleDisbursementsWithDisableRepaymentConfiguration(
+                loanTransactionHelper, enableDownPayment, "25", 
enableAutoRepaymentForDownPayment);
+        assertNotNull(getLoanProductsProductResponse);
+        assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
+        assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+                .compareTo(disbursedAmountPercentageForDownPayment));
+        assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+        final Integer loanId = 
createLoanAccountMultipleRepaymentsDisbursement(clientId, 
getLoanProductsProductResponse.getId(),
+                loanExternalIdStr);
+
+        // Retrieve Loan with loanId
+
+        GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+        // verify down-payment details for Loan
+        assertNotNull(loanDetails);
+        assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
+        assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+        assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
+    }
+
+    @Test
+    public void downPaymentOnOverpaidLoan() {
+        try {
+
+            // Set business date
+            LocalDate disbursementDate = LocalDate.of(2023, 3, 3);
+
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
+
+            // Accounts oof periodic accrual
+            final Account assetAccount = accountHelper.createAssetAccount();
+            final Account incomeAccount = accountHelper.createIncomeAccount();
+            final Account expenseAccount = 
accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = 
accountHelper.createLiabilityAccount();
+
+            // Loan ExternalId
+            String loanExternalIdStr = UUID.randomUUID().toString();
+
+            // down-payment configuration
+            Boolean enableDownPayment = true;
+            BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25);
+            Boolean enableAutoRepaymentForDownPayment = true;
+
+            final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+
+            // Loan Product creation with down-payment configuration
+            final GetLoanProductsProductIdResponse 
getLoanProductsProductResponse = 
createProgressiveLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
+                    loanTransactionHelper, enableDownPayment, "25", 
enableAutoRepaymentForDownPayment, assetAccount, incomeAccount,
+                    expenseAccount, overpaymentAccount);
+
+            assertNotNull(getLoanProductsProductResponse);
+            assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
+            assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+                    .compareTo(disbursedAmountPercentageForDownPayment));
+            assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+            final Integer loanId = 
createLoanAccountWithAdvancedPaymentAllocation(clientId, 
getLoanProductsProductResponse.getId(),
+                    loanExternalIdStr);
+
+            // Retrieve Loan with loanId
+
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+            // verify down-payment details for Loan
+            assertNotNull(loanDetails);
+            assertEquals(enableDownPayment, 
loanDetails.getEnableDownPayment());
+            assertEquals(0, 
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+            assertEquals(enableAutoRepaymentForDownPayment, 
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+            // first disbursement
+            loanTransactionHelper.disburseLoanWithTransactionAmount("03 March 
2023", loanId, "1000");
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+            // verify down-payment transaction created
+            checkDownPaymentTransaction(disbursementDate, 250.0f, 0.0f, 0.0f, 
0.0f, loanId);
+
+            // verify journal entries for down-payment
+            journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, 
"03 March 2023",
+                    new JournalEntry(250, 
JournalEntry.TransactionType.CREDIT));
+            journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, 
"03 March 2023",
+                    new JournalEntry(250, JournalEntry.TransactionType.DEBIT));
+
+            // verify installment details
+            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate());
+            assertEquals(1000.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(0).getPrincipalLoanBalanceOutstanding());
+            assertEquals(1, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
+            assertEquals(LocalDate.of(2023, 3, 3), 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
+            assertEquals(250.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
+            assertEquals(true, 
loanDetails.getRepaymentSchedule().getPeriods().get(1).getDownPaymentPeriod());
+            assertEquals(2, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
+            assertEquals(LocalDate.of(2023, 4, 2), 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
+            assertEquals(750.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
+            assertEquals(false, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getDownPaymentPeriod());
+
+            loanTransactionHelper.makeLoanRepayment((long) loanId, new 
PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy")
+                    .transactionDate("03 March 
2023").locale("en").transactionAmount(800.0));
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+            // verify down-payment details for Loan
+            assertTrue(loanDetails.getStatus().getOverpaid());
+            assertEquals(50.0, loanDetails.getTotalOverpaid());
+
+            // second disbursement
+
+            disbursementDate = LocalDate.of(2023, 3, 5);
+            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
+            loanTransactionHelper.disburseLoanWithTransactionAmount("05 March 
2023", loanId, "20");
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+            
assertTrue(loanDetails.getTransactions().get(0).getType().getDisbursement());
+            assertEquals(1000.0, 
loanDetails.getTransactions().get(0).getAmount());
+            assertEquals("loanTransactionType.downPayment", 
loanDetails.getTransactions().get(1).getType().getCode());
+            assertEquals(250.0, 
loanDetails.getTransactions().get(1).getAmount());
+            
assertTrue(loanDetails.getTransactions().get(2).getType().getRepayment());
+            assertEquals(800.0, 
loanDetails.getTransactions().get(2).getAmount());
+            
assertTrue(loanDetails.getTransactions().get(3).getType().getDisbursement());
+            assertEquals(20.0, 
loanDetails.getTransactions().get(3).getAmount());
+            assertEquals(0.0, 
loanDetails.getTransactions().get(3).getOutstandingLoanBalance());
+            assertEquals(4, loanDetails.getTransactions().size());
+
+            assertTrue(loanDetails.getStatus().getOverpaid());
+            assertEquals(30.0, loanDetails.getTotalOverpaid());
+
+            loanTransactionHelper.disburseLoanWithTransactionAmount("05 March 
2023", loanId, "30");
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+            
assertTrue(loanDetails.getTransactions().get(4).getType().getDisbursement());
+            assertEquals(30.0, 
loanDetails.getTransactions().get(4).getAmount());
+            assertEquals(0.0, 
loanDetails.getTransactions().get(4).getOutstandingLoanBalance());
+            assertEquals(5, loanDetails.getTransactions().size());
+
+            assertTrue(loanDetails.getStatus().getClosedObligationsMet());
+            assertEquals(0.0, loanDetails.getSummary().getTotalOutstanding());
+            assertEquals(null, loanDetails.getTotalOverpaid());
+
+            PostLoansLoanIdTransactionsResponse repayment = 
loanTransactionHelper.makeLoanRepayment((long) loanId,
+                    new PostLoansLoanIdTransactionsRequest().dateFormat("dd 
MMMM yyyy").transactionDate("05 March 2023").locale("en")
+                            .transactionAmount(1.0));
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+            assertTrue(loanDetails.getStatus().getOverpaid());
+            assertEquals(1.0, loanDetails.getTotalOverpaid());
+
+            loanTransactionHelper.disburseLoanWithTransactionAmount("05 March 
2023", loanId, "40");
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+            
assertTrue(loanDetails.getTransactions().get(5).getType().getRepayment());
+            assertEquals(1.0, 
loanDetails.getTransactions().get(5).getAmount());
+            
assertTrue(loanDetails.getTransactions().get(6).getType().getDisbursement());
+            assertEquals(40.0, 
loanDetails.getTransactions().get(6).getAmount());
+            assertEquals(39.0, 
loanDetails.getTransactions().get(6).getOutstandingLoanBalance());
+            assertEquals("loanTransactionType.downPayment", 
loanDetails.getTransactions().get(7).getType().getCode());
+            assertEquals(9.0, 
loanDetails.getTransactions().get(7).getAmount());
+            assertEquals(30.0, 
loanDetails.getTransactions().get(7).getOutstandingLoanBalance());
+            assertEquals(8, loanDetails.getTransactions().size());
+
+            assertTrue(loanDetails.getStatus().getActive());
+            assertEquals(30.0, loanDetails.getSummary().getTotalOutstanding());
+
+            
loanTransactionHelper.reverseLoanTransaction(repayment.getLoanId(), 
repayment.getResourceId(),
+                    new 
PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN).transactionDate("05
 March 2023")
+                            .transactionAmount(0.0).locale("en"));
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+            
assertTrue(loanDetails.getTransactions().get(5).getType().getRepayment());
+            assertEquals(1.0, 
loanDetails.getTransactions().get(5).getAmount());
+            
assertTrue(loanDetails.getTransactions().get(5).getManuallyReversed());
+            
assertTrue(loanDetails.getTransactions().get(6).getType().getDisbursement());
+            assertEquals(40.0, 
loanDetails.getTransactions().get(6).getAmount());
+            assertEquals(40.0, 
loanDetails.getTransactions().get(6).getOutstandingLoanBalance());
+            assertEquals("loanTransactionType.downPayment", 
loanDetails.getTransactions().get(7).getType().getCode());
+            assertEquals(9.0, 
loanDetails.getTransactions().get(7).getAmount());
+            assertEquals(31.0, 
loanDetails.getTransactions().get(7).getOutstandingLoanBalance());
+            assertEquals(8, loanDetails.getTransactions().size());
+
+            assertTrue(loanDetails.getStatus().getActive());
+            assertEquals(31.0, loanDetails.getSummary().getTotalOutstanding());
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+    }
+
+    private void checkNoDownPaymentTransaction(final Integer loanID) {
+        ArrayList<HashMap> transactions = (ArrayList<HashMap>) 
loanTransactionHelper.getLoanTransactions(requestSpec, responseSpec, loanID);
+        boolean isTransactionFound = false;
+        for (int i = 0; i < transactions.size(); i++) {
+            HashMap transactionType = (HashMap) 
transactions.get(i).get("type");
+            boolean isDownPaymentTransaction = (Boolean) 
transactionType.get("downPayment");
+
+            if (isDownPaymentTransaction) {
+                isTransactionFound = true;
+                break;
+            }
+        }
+        assertFalse(isTransactionFound, "Down Payment entries are posted");
+    }
+
+    private void checkDownPaymentTransaction(final LocalDate transactionDate, 
final Float principalPortion, final Float interestPortion,
+            final Float feePortion, final Float penaltyPortion, final Integer 
loanID) {
+        ArrayList<HashMap> transactions = (ArrayList<HashMap>) 
loanTransactionHelper.getLoanTransactions(requestSpec, responseSpec, loanID);
+        boolean isTransactionFound = false;
+        for (int i = 0; i < transactions.size(); i++) {
+            HashMap transactionType = (HashMap) 
transactions.get(i).get("type");
+            boolean isDownPaymentTransaction = (Boolean) 
transactionType.get("downPayment");
+
+            if (isDownPaymentTransaction) {
+                ArrayList<Integer> downPaymentDateAsArray = 
(ArrayList<Integer>) transactions.get(i).get("date");
+                LocalDate downPaymentEntryDate = 
LocalDate.of(downPaymentDateAsArray.get(0), downPaymentDateAsArray.get(1),
+                        downPaymentDateAsArray.get(2));
+
+                if (DateUtils.isEqual(transactionDate, downPaymentEntryDate)) {
+                    isTransactionFound = true;
+                    assertEquals(principalPortion, 
Float.valueOf(String.valueOf(transactions.get(i).get("principalPortion"))),
+                            "Mismatch in transaction amounts");
+                    assertEquals(interestPortion, 
Float.valueOf(String.valueOf(transactions.get(i).get("interestPortion"))),
+                            "Mismatch in transaction amounts");
+                    assertEquals(feePortion, 
Float.valueOf(String.valueOf(transactions.get(i).get("feeChargesPortion"))),
+                            "Mismatch in transaction amounts");
+                    assertEquals(penaltyPortion, 
Float.valueOf(String.valueOf(transactions.get(i).get("penaltyChargesPortion"))),
+                            "Mismatch in transaction amounts");
+                    break;
+                }
+            }
+        }
+        assertTrue(isTransactionFound, "No Down Payment entries are posted");
+    }
+
+    private Integer createLoanAccountMultipleRepaymentsDisbursement(final 
Integer clientID, final Long loanProductID,
+            final String externalId) {
+
+        String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("30")
+                
.withLoanTermFrequencyAsDays().withNumberOfRepayments("1").withRepaymentEveryAfter("30").withRepaymentFrequencyTypeAsDays()
+                
.withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments()
+                
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03
 March 2023")
+                .withSubmittedOnDate("03 March 
2023").withLoanType("individual").withExternalId(externalId)
+                .build(clientID.toString(), loanProductID.toString(), null);
+
+        final Integer loanId = 
loanTransactionHelper.getLoanId(loanApplicationJSON);
+        loanTransactionHelper.approveLoan("03 March 2023", "1000", loanId, 
null);
+        return loanId;
+    }
+
+    private GetLoanProductsProductIdResponse 
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
+            LoanTransactionHelper loanTransactionHelper, Integer 
delinquencyBucketId, Boolean enableDownPayment,
+            String disbursedAmountPercentageForDownPayment, boolean 
enableAutoRepaymentForDownPayment, final Account... accounts) {
+        final String loanProductJSON = new 
LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
+                
.withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
+                
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
+                
.withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30")
+                .withDaysInYear("365").withMoratorium("0", 
"0").withMultiDisburse().withDisallowExpectedDisbursements(true)
+                .withEnableDownPayment(enableDownPayment, 
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
+                .build(null);
+        final Integer loanProductId = 
loanTransactionHelper.getLoanProductId(loanProductJSON);
+        return loanTransactionHelper.getLoanProduct(loanProductId);
+    }
+
+    private Integer createLoanAccountWithAdvancedPaymentAllocation(final 
Integer clientID, final Long loanProductID,
+            final String externalId) {
+
+        String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("30")
+                
.withRepaymentStrategy(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
+                
.withLoanTermFrequencyAsDays().withNumberOfRepayments("1").withRepaymentEveryAfter("30").withRepaymentFrequencyTypeAsDays()
+                
.withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments()
+                
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03
 March 2023")
+                .withSubmittedOnDate("03 March 
2023").withLoanType("individual").withExternalId(externalId)
+                .build(clientID.toString(), loanProductID.toString(), null);
+
+        final Integer loanId = 
loanTransactionHelper.getLoanId(loanApplicationJSON);
+        loanTransactionHelper.approveLoan("03 March 2023", "1000", loanId, 
null);
+        return loanId;
+    }
+
+    private GetLoanProductsProductIdResponse 
createProgressiveLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
+            LoanTransactionHelper loanTransactionHelper, Boolean 
enableDownPayment, String disbursedAmountPercentageForDownPayment,
+            boolean enableAutoRepaymentForDownPayment, final Account... 
accounts) {
+        final String loanProductJSON = new 
LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
+                
.withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL).withLoanScheduleType(LoanScheduleType.PROGRESSIVE)
+                
.addAdvancedPaymentAllocation(createDefaultPaymentAllocation()).withRepaymentAfterEvery("1").withNumberOfRepayments("1")
+                
.withRepaymentTypeAsMonth().withinterestRatePerPeriod("0").withInterestRateFrequencyTypeAsMonths()
+                
.withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
+                
.withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30")
+                .withDaysInYear("365").withMoratorium("0", 
"0").withMultiDisburse().withDisallowExpectedDisbursements(true)
+                .withEnableDownPayment(enableDownPayment, 
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
+                .build(null);
+        final Integer loanProductId = 
loanTransactionHelper.getLoanProductId(loanProductJSON);
+        return loanTransactionHelper.getLoanProduct(loanProductId);
+    }
+
+    private List<PaymentAllocationOrder> 
getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
+        AtomicInteger integer = new AtomicInteger(1);
+        return Arrays.stream(paymentAllocationTypes).map(pat -> {
+            PaymentAllocationOrder paymentAllocationOrder = new 
PaymentAllocationOrder();
+            paymentAllocationOrder.setPaymentAllocationRule(pat.name());
+            paymentAllocationOrder.setOrder(integer.getAndIncrement());
+            return paymentAllocationOrder;
+        }).toList();
+    }
+
+    private AdvancedPaymentData createDefaultPaymentAllocation() {
+        AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
+        advancedPaymentData.setTransactionType("DEFAULT");
+        
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
+
+        List<PaymentAllocationOrder> paymentAllocationOrders = 
getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
+                PaymentAllocationType.PAST_DUE_FEE, 
PaymentAllocationType.PAST_DUE_PRINCIPAL, 
PaymentAllocationType.PAST_DUE_INTEREST,
+                PaymentAllocationType.DUE_PENALTY, 
PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
+                PaymentAllocationType.DUE_INTEREST, 
PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
+                PaymentAllocationType.IN_ADVANCE_PRINCIPAL, 
PaymentAllocationType.IN_ADVANCE_INTEREST);
+
+        advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
+        return advancedPaymentData;
+    }
+
+    private Integer createApproveAndDisburseLoanAccount(final Integer 
clientID, final Long loanProductID, final String externalId) {
+
+        String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")
+                
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1")
+                
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance()
+                
.withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
+                .withExpectedDisbursementDate("03 September 
2022").withSubmittedOnDate("01 September 2022").withLoanType("individual")
+                .withExternalId(externalId).build(clientID.toString(), 
loanProductID.toString(), null);
+
+        final Integer loanId = 
loanTransactionHelper.getLoanId(loanApplicationJSON);
+        loanTransactionHelper.approveLoan("02 September 2022", "1000", loanId, 
null);
+        loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September 
2022", loanId, "1000");
+        return loanId;
+    }
+
+    private GetLoanProductsProductIdResponse 
createLoanProductWithEnableDownPaymentAndMultipleDisbursementsWithDisableRepaymentConfiguration(
+            LoanTransactionHelper loanTransactionHelper, Boolean 
enableDownPayment, String disbursedAmountPercentageForDownPayment,
+            boolean enableAutoRepaymentForDownPayment) {
+        final String loanProductJSON = new 
LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
+                
.withRepaymentAfterEvery("1").withNumberOfRepayments("3").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
+                
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
+                
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365")
+                .withMoratorium("0", 
"0").withMultiDisburse().withDisallowExpectedDisbursements(true)
+                .withEnableDownPayment(enableDownPayment, 
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
+                .build(null);
+        final Integer loanProductId = 
loanTransactionHelper.getLoanProductId(loanProductJSON);
+        return loanTransactionHelper.getLoanProduct(loanProductId);
+    }
+
     private Integer createLoanProductWithDownPaymentConfiguration(final 
LoanTransactionHelper loanTransactionHelper,
             final Integer delinquencyBucketId, Boolean enableDownPayment, 
String disbursedAmountPercentageForDownPayment,
             Boolean enableAutoRepaymentForDownPayment, boolean 
multiDisbursement) {
@@ -929,4 +1609,13 @@ public class LoanRepaymentScheduleWithDownPaymentTest {
         loanTransactionHelper.disburseLoanWithTransactionAmount("04 September 
2022", loanId, "300");
         return loanId;
     }
+
+    private PutLoanProductsProductIdResponse 
updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id) {
+        // down-payment configuration
+        Boolean enableDownPayment = true;
+        BigDecimal disbursedAmountPercentageForDownPayment = 
BigDecimal.valueOf(25.0);
+        final PutLoanProductsProductIdRequest requestModifyLoan = new 
PutLoanProductsProductIdRequest().enableDownPayment(enableDownPayment)
+                
.disbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment).locale("en");
+        return loanTransactionHelper.updateLoanProduct(id, requestModifyLoan);
+    }
 }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoLoanDisbursalWithDownPaymentIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoLoanDisbursalWithDownPaymentIntegrationTest.java
index b95b44ad5..6ecb979ac 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoLoanDisbursalWithDownPaymentIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoLoanDisbursalWithDownPaymentIntegrationTest.java
@@ -931,11 +931,11 @@ public class 
UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt
 
             // verify transactions
             verifyTransactions(loanId, //
-                    transaction(250.0, "Down Payment", "01 January 2023"), //
                     transaction(1000.0, "Disbursement", "01 January 2023"), //
+                    transaction(250.0, "Down Payment", "01 January 2023"), //
                     transaction(300.0, "Repayment", "10 January 2023"), //
-                    transaction(100.0, "Down Payment", "15 January 2023"), //
-                    transaction(400.0, "Disbursement", "15 January 2023") //
+                    transaction(400.0, "Disbursement", "15 January 2023"), //
+                    transaction(100.0, "Down Payment", "15 January 2023") //
             );
 
             // verify journal entries
@@ -966,8 +966,8 @@ public class 
UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt
 
             // verify transactions
             verifyTransactions(loanId, //
-                    transaction(250.0, "Down Payment", "01 January 2023"), //
                     transaction(1000.0, "Disbursement", "01 January 2023"), //
+                    transaction(250.0, "Down Payment", "01 January 2023"), //
                     transaction(300.0, "Repayment", "10 January 2023") //
             );
 

Reply via email to