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 5c7724200 FINERACT-1958: downpayment periods for disbursements on same 
day
5c7724200 is described below

commit 5c7724200505f60e5c93400820e1502bab8130c4
Author: Ruchi Dhamankar <[email protected]>
AuthorDate: Wed Nov 8 17:57:50 2023 +0530

    FINERACT-1958: downpayment periods for disbursements on same day
---
 .../AbstractCumulativeLoanScheduleGenerator.java   |  14 +-
 .../AbstractProgressiveLoanScheduleGenerator.java  |  14 +-
 ...nWithOverlappingDownPaymentInstallmentTest.java | 271 ++++++++++++++++++++-
 3 files changed, 280 insertions(+), 19 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
index 236ecb7ed..fd3bf5bf6 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
@@ -1004,10 +1004,16 @@ public abstract class 
AbstractCumulativeLoanScheduleGenerator implements LoanSch
 
                 BigDecimal downPaymentAmt = BigDecimal.ZERO;
                 if (loanApplicationTerms.isDownPaymentEnabled()) {
-                    final LoanScheduleModelDownPaymentPeriod downPaymentPeriod 
= createDownPaymentPeriod(loanApplicationTerms,
-                            scheduleParams, disburseDetail.getKey(), 
disburseDetail.getValue().getAmount());
-                    periods.add(downPaymentPeriod);
-                    downPaymentAmt = downPaymentPeriod.principalDue();
+                    // get list of disbursements done on same day and create 
down payment periods
+                    List<DisbursementData> disbursementsOnSameDate = 
loanApplicationTerms.getDisbursementDatas().stream()
+                            .filter(disbursementData -> 
DateUtils.isEqual(disbursementData.disbursementDate(), disburseDetail.getKey()))
+                            .toList();
+                    for (DisbursementData disbursementData : 
disbursementsOnSameDate) {
+                        final LoanScheduleModelDownPaymentPeriod 
downPaymentPeriod = createDownPaymentPeriod(loanApplicationTerms,
+                                scheduleParams, 
disbursementData.disbursementDate(), disbursementData.getPrincipal());
+                        periods.add(downPaymentPeriod);
+                        downPaymentAmt = 
downPaymentAmt.add(downPaymentPeriod.principalDue());
+                    }
                 }
                 // updates actual outstanding balance with new
                 // disbursement detail
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
index d46b9aa1b..aa0645378 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
@@ -365,10 +365,16 @@ public abstract class 
AbstractProgressiveLoanScheduleGenerator implements LoanSc
 
                 BigDecimal downPaymentAmt = BigDecimal.ZERO;
                 if (loanApplicationTerms.isDownPaymentEnabled()) {
-                    final LoanScheduleModelDownPaymentPeriod downPaymentPeriod 
= createDownPaymentPeriod(loanApplicationTerms,
-                            scheduleParams, disburseDetail.getKey(), 
disburseDetail.getValue().getAmount());
-                    periods.add(downPaymentPeriod);
-                    downPaymentAmt = downPaymentPeriod.principalDue();
+                    // get list of disbursements done on same day and create 
down payment periods
+                    List<DisbursementData> disbursementsOnSameDate = 
loanApplicationTerms.getDisbursementDatas().stream()
+                            .filter(disbursementData -> 
DateUtils.isEqual(disbursementData.disbursementDate(), disburseDetail.getKey()))
+                            .toList();
+                    for (DisbursementData disbursementData : 
disbursementsOnSameDate) {
+                        final LoanScheduleModelDownPaymentPeriod 
downPaymentPeriod = createDownPaymentPeriod(loanApplicationTerms,
+                                scheduleParams, 
disbursementData.disbursementDate(), disbursementData.getPrincipal());
+                        periods.add(downPaymentPeriod);
+                        downPaymentAmt = 
downPaymentAmt.add(downPaymentPeriod.principalDue());
+                    }
                 }
                 // updates actual outstanding balance with new
                 // disbursement detail
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java
index 4e560a925..9a9ec44a6 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java
@@ -32,11 +32,16 @@ import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 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.GetLoanProductsProductIdResponse;
 import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.PaymentAllocationOrder;
 import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
 import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
 import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
@@ -50,6 +55,8 @@ import 
org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuil
 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.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;
@@ -549,7 +556,7 @@ public class 
LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTe
             assertNotNull(loanDetails.getRepaymentSchedule());
 
             // periods
-            assertEquals(7, 
loanDetails.getRepaymentSchedule().getPeriods().size());
+            assertEquals(8, 
loanDetails.getRepaymentSchedule().getPeriods().size());
             // disbursement period [0]
             
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(0),
 LocalDate.of(2023, 3, 3), 200.0);
             // down payment period [1]
@@ -560,13 +567,16 @@ public class 
LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTe
             // disbursement period [3]
             
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(3),
 LocalDate.of(2023, 4, 3), 200.0);
             // down payment period [4]
-            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 2, 
100.0, 100.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-                    true, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
-            // regular installment [5]
-            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 
225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
-                    false, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 2, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // down payment period [5]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
             // regular installment [6]
             
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(6), 4, 
225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
+                    false, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [7]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(7), 5, 
225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
                     false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
 
             // make repayment for fully paying and verify that regular 
installment gets fully paid on 3rd april
@@ -579,7 +589,7 @@ public class 
LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTe
             assertNotNull(loanDetails.getRepaymentSchedule());
 
             // periods
-            assertEquals(7, 
loanDetails.getRepaymentSchedule().getPeriods().size());
+            assertEquals(8, 
loanDetails.getRepaymentSchedule().getPeriods().size());
             // disbursement period [0]
             
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(0),
 LocalDate.of(2023, 3, 3), 200.0);
             // down payment period [1]
@@ -590,13 +600,212 @@ public class 
LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTe
             // disbursement period [3]
             
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(3),
 LocalDate.of(2023, 4, 3), 200.0);
             // down payment period [4]
-            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 2, 
100.0, 100.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-                    true, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
-            // regular installment [5]
-            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 
225.0, 225.0, 225.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 2, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // down payment period [5]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [6]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(6), 4, 
225.0, 225.0, 225.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                     true, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [7]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(7), 5, 
225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
+                    false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
+
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+
+    }
+
+    @Test
+    public void 
loanAccountWithEnableDownPaymentWithAdvancedPaymentAllocationWithProgressiveScheduleGenerationMultipleDisbursementsOnSameDayTest()
 {
+        try {
+
+            // Test with
+            // Enable Down Payment
+            // Disable Auto Repayment For Down Payment
+            // Overlapping down payment and regular installment with multiple 
disbursements on same day
+            // Progressive Schedule generation with Advanced Payment Allocation
+
+            // Set business date
+            LocalDate disbursementDate = LocalDate.of(2023, 3, 3);
+
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
+
+            // 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();
+
+            String futureInstallmentAllocationRule = "NEXT_INSTALLMENT";
+            AdvancedPaymentData defaultAllocation = 
createDefaultPaymentAllocation(futureInstallmentAllocationRule);
+
+            // Loan Product creation with down-payment configuration and 
progressive schedule
+            final GetLoanProductsProductIdResponse 
getLoanProductsProductResponse = 
createLoanProductWithAdvancedPaymentStrategyAndProgressiveLoanSchedule(
+                    loanTransactionHelper, enableDownPayment, "25", 
enableAutoRepaymentForDownPayment, defaultAllocation);
+
+            assertNotNull(getLoanProductsProductResponse);
+            assertEquals(enableDownPayment, 
getLoanProductsProductResponse.getEnableDownPayment());
+            assertEquals(0, 
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+                    .compareTo(disbursedAmountPercentageForDownPayment));
+            assertEquals(enableAutoRepaymentForDownPayment, 
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+            // create loan account
+
+            final Integer loanId = 
createLoanAccountMultipleRepaymentsDisbursement(clientId, 
getLoanProductsProductResponse.getId(),
+                    loanExternalIdStr, "advanced-payment-allocation-strategy");
+
+            // 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, "200");
+
+            // make repayment on 3rd March
+            final PostLoansLoanIdTransactionsResponse repaymentTransaction = 
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+                    new PostLoansLoanIdTransactionsRequest().dateFormat("dd 
MMMM yyyy").transactionDate("3 March 2023").locale("en")
+                            .transactionAmount(50.0));
+
+            // verify loan schedule
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+            assertNotNull(loanDetails.getRepaymentSchedule());
+
+            // periods
+            assertEquals(4, 
loanDetails.getRepaymentSchedule().getPeriods().size());
+            // disbursement period [0]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(0),
 LocalDate.of(2023, 3, 3), 200.0);
+            // down payment period [1]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(1), 1, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 3, 3), LocalDate.of(2023, 3, 3));
+            // regular installment [2]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(2), 2, 
75.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0, 0.0, false,
+                    LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [3]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(3), 3, 
75.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0, 0.0, false,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
+
+            // second disbursement with overlapping installment i.e same due 
date as regular repayment due date
+
+            disbursementDate = LocalDate.of(2023, 4, 3);
+            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, disbursementDate);
+            loanTransactionHelper.disburseLoanWithTransactionAmount("03 April 
2023", loanId, "200");
+
+            // make repayment on 3rd April
+            final PostLoansLoanIdTransactionsResponse repaymentTransaction_1 = 
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+                    new PostLoansLoanIdTransactionsRequest().dateFormat("dd 
MMMM yyyy").transactionDate("3 April 2023").locale("en")
+                            .transactionAmount(50.0));
+
+            // verify loan schedule
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+            assertNotNull(loanDetails.getRepaymentSchedule());
+
+            // periods
+            assertEquals(6, 
loanDetails.getRepaymentSchedule().getPeriods().size());
+            // disbursement period [0]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(0),
 LocalDate.of(2023, 3, 3), 200.0);
+            // down payment period [1]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(1), 1, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 3, 3), LocalDate.of(2023, 3, 3));
+            // disbursement period [2]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(2),
 LocalDate.of(2023, 4, 3), 200.0);
+            // down payment period [3]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(3), 2, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [4]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 3, 
150.0, 0.0, 0.0, 150.0, 0.0, 0.0, 0.0, 0.0,
+                    false, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [5]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 4, 
150.0, 0.0, 0.0, 150.0, 0.0, 0.0, 0.0, 0.0,
+                    false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
+
+            // same day third disbursement with overlapping installment i.e 
same due date as regular repayment due date
+            // 3-April
+            loanTransactionHelper.disburseLoanWithTransactionAmount("03 April 
2023", loanId, "200");
+
+            // make repayment on 3rd April
+            final PostLoansLoanIdTransactionsResponse repaymentTransaction_2 = 
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+                    new PostLoansLoanIdTransactionsRequest().dateFormat("dd 
MMMM yyyy").transactionDate("3 April 2023").locale("en")
+                            .transactionAmount(50.0));
+
+            // verify loan schedule
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+            assertNotNull(loanDetails.getRepaymentSchedule());
+
+            // periods
+            assertEquals(8, 
loanDetails.getRepaymentSchedule().getPeriods().size());
+            // disbursement period [0]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(0),
 LocalDate.of(2023, 3, 3), 200.0);
+            // down payment period [1]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(1), 1, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 3, 3), LocalDate.of(2023, 3, 3));
+            // disbursement period [2]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(2),
 LocalDate.of(2023, 4, 3), 200.0);
+            // disbursement period [3]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(3),
 LocalDate.of(2023, 4, 3), 200.0);
+            // down payment period [4]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 2, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // down payment period [5]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
             // regular installment [6]
             
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(6), 4, 
225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
+                    false, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [7]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(7), 5, 
225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
+                    false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
+
+            // make repayment for fully paying and verify that regular 
installment gets fully paid on 3rd april
+            final PostLoansLoanIdTransactionsResponse repaymentTransaction_3 = 
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+                    new PostLoansLoanIdTransactionsRequest().dateFormat("dd 
MMMM yyyy").transactionDate("3 April 2023").locale("en")
+                            .transactionAmount(225.0));
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+            assertNotNull(loanDetails.getRepaymentSchedule());
+
+            // periods
+            assertEquals(8, 
loanDetails.getRepaymentSchedule().getPeriods().size());
+            // disbursement period [0]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(0),
 LocalDate.of(2023, 3, 3), 200.0);
+            // down payment period [1]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(1), 1, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 3, 3), LocalDate.of(2023, 3, 3));
+            // disbursement period [2]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(2),
 LocalDate.of(2023, 4, 3), 200.0);
+            // disbursement period [3]
+            
verifyDisbursementPeriod(loanDetails.getRepaymentSchedule().getPeriods().get(3),
 LocalDate.of(2023, 4, 3), 200.0);
+            // down payment period [4]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(4), 2, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // down payment period [5]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(5), 3, 
50.0, 50.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, true,
+                    LocalDate.of(2023, 4, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [6]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(6), 4, 
225.0, 225.0, 225.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                    true, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3));
+            // regular installment [7]
+            
verifyPeriodDetails(loanDetails.getRepaymentSchedule().getPeriods().get(7), 5, 
225.0, 0.0, 0.0, 225.0, 0.0, 0.0, 0.0, 0.0,
                     false, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3));
 
         } finally {
@@ -657,6 +866,46 @@ public class 
LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTe
         return loanTransactionHelper.getLoanProduct(loanProductId);
     }
 
+    private GetLoanProductsProductIdResponse 
createLoanProductWithAdvancedPaymentStrategyAndProgressiveLoanSchedule(
+            LoanTransactionHelper loanTransactionHelper, Boolean 
enableDownPayment, String disbursedAmountPercentageForDownPayment,
+            boolean enableAutoRepaymentForDownPayment, AdvancedPaymentData... 
advancedPaymentData) {
+
+        final String loanProductJSON = new 
LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
+                
.withRepaymentAfterEvery("1").withNumberOfRepayments("2").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
+                
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
+                
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365")
+                .withMoratorium("0", 
"0").withMultiDisburse().withDisallowExpectedDisbursements(true)
+                .withEnableDownPayment(enableDownPayment, 
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
+                
.addAdvancedPaymentAllocation(advancedPaymentData).withLoanScheduleType(LoanScheduleType.PROGRESSIVE).build(null);
+        final Integer loanProductId = 
loanTransactionHelper.getLoanProductId(loanProductJSON);
+        return loanTransactionHelper.getLoanProduct(loanProductId);
+    }
+
+    private AdvancedPaymentData createDefaultPaymentAllocation(String 
futureInstallmentAllocationRule) {
+        AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
+        advancedPaymentData.setTransactionType("DEFAULT");
+        
advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule);
+
+        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 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 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,

Reply via email to