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 09031aa5a7 FINERACT-2412: Full term tranche - Schedule handling and 
Calculations
09031aa5a7 is described below

commit 09031aa5a76d3374e727a40b7f72695ca208c6e4
Author: mariiaKraievska <[email protected]>
AuthorDate: Wed Jan 7 12:29:44 2026 +0200

    FINERACT-2412: Full term tranche - Schedule handling and Calculations
---
 .../test/data/loanproduct/DefaultLoanProduct.java  |   1 +
 .../global/LoanProductGlobalInitializerStep.java   |  33 +++
 .../fineract/test/support/TestContextKey.java      |   1 +
 .../features/LoanDelayedScheduleCaptures.feature   | 139 +++++++++++
 .../data/RepaymentScheduleRelatedLoanData.java     |  11 +
 .../portfolio/loanaccount/domain/Loan.java         |   5 +-
 .../LoanRepaymentScheduleProcessingWrapper.java    |   4 +
 .../loanschedule/domain/LoanApplicationTerms.java  |  26 ++-
 .../domain/LoanRepaymentScheduleModelData.java     |   3 +-
 .../mapper/LoanTermVariationsMapper.java           |   3 +-
 .../loanproduct/data/LoanConfigurationDetails.java |   5 +-
 .../domain/ILoanConfigurationDetails.java          |   2 +
 .../misc/Main.java                                 |   2 +-
 ...ddableProgressiveLoanScheduleGeneratorTest.java |   2 +-
 ...dvancedPaymentScheduleTransactionProcessor.java |  41 +++-
 .../mapper/LoanConfigurationDetailsMapper.java     |   3 +-
 .../loanproduct/calc/ProgressiveEMICalculator.java | 137 +++++++++--
 .../domain/LoanScheduleGeneratorTest.java          |   4 +-
 .../calc/ProgressiveEMICalculatorTest.java         |  95 ++++++++
 .../loanaccount/api/LoansApiResource.java          |   6 +-
 .../service/LoanScheduleAssembler.java             |   7 +-
 .../service/LoanReadPlatformServiceImpl.java       |   2 +-
 .../domain/DefaultScheduledDateGeneratorTest.java  |   4 +-
 .../LoanDisbursementDetailsIntegrationTest.java    | 254 +++++++++++++++++++++
 24 files changed, 739 insertions(+), 51 deletions(-)

diff --git 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java
 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java
index 4776e322bb..992a0dae7e 100644
--- 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java
+++ 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java
@@ -182,6 +182,7 @@ public enum DefaultLoanProduct implements LoanProduct {
     LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY, //
     
LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_PRINCIPAL_FIRST, 
//
     LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD, 
//
+    
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_FULL_TERM_TRANCHE,
 //
     ;
 
     @Override
diff --git 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java
 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java
index 0fd7cceefd..afe1063e47 100644
--- 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java
+++ 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java
@@ -4318,6 +4318,39 @@ public class LoanProductGlobalInitializerStep implements 
FineractGlobalInitializ
         TestContext.INSTANCE.set(
                 
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD,
                 
responseLoanProductsResponseAdvCustomPaymentAllocationProgressiveLoanScheduleHorizontalUSD);
+
+        // LP2 with progressive loan schedule + horizontal + interest 
recalculation daily EMI + 360/30 +
+        // multidisbursement with full term tranche enabled
+        // Frequency for recalculate Outstanding Principal: Daily, Frequency 
Interval for recalculation: 1
+        // 
(LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_FULL_TERM_TRANCHE)
+        String name170 = 
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_FULL_TERM_TRANCHE
+                .getName();
+        PostLoanProductsRequest 
loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyMultiDisburseFullTermTranche
 = loanProductsRequestFactory
+                .defaultLoanProductsRequestLP2Emi()//
+                .name(name170)//
+                .daysInYearType(DaysInYearType.DAYS360.value)//
+                .daysInMonthType(DaysInMonthType.DAYS30.value)//
+                .isInterestRecalculationEnabled(true)//
+                .preClosureInterestCalculationStrategy(1)//
+                .rescheduleStrategyMethod(4)//
+                .interestRecalculationCompoundingMethod(0)//
+                .recalculationRestFrequencyType(2)//
+                .recalculationRestFrequencyInterval(1)//
+                .paymentAllocation(List.of(//
+                        createPaymentAllocation("DEFAULT", 
"NEXT_INSTALLMENT"), //
+                        createPaymentAllocation("GOODWILL_CREDIT", 
"LAST_INSTALLMENT"), //
+                        createPaymentAllocation("MERCHANT_ISSUED_REFUND", 
"REAMORTIZATION"), //
+                        createPaymentAllocation("PAYOUT_REFUND", 
"NEXT_INSTALLMENT")))//
+                .multiDisburseLoan(true)//
+                .disallowExpectedDisbursements(true)//
+                .allowFullTermForTranche(true)//
+                .maxTrancheCount(10)//
+                .outstandingLoanBalance(10000.0);//
+        PostLoanProductsResponse 
responseLoanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyMultiDisburseFullTermTranche
 = createLoanProductIdempotent(
+                
loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyMultiDisburseFullTermTranche);
+        TestContext.INSTANCE.set(
+                
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_FULL_TERM_TRANCHE,
+                
responseLoanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyMultiDisburseFullTermTranche);
     }
 
     public static AdvancedPaymentData createPaymentAllocation(String 
transactionType, String futureInstallmentAllocationRule,
diff --git 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
index 56e52d42c7..1285378693 100644
--- 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
+++ 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
@@ -293,5 +293,6 @@ public abstract class TestContextKey {
     public static final String 
LP1_INTEREST_FLAT_DAILY_ACTUAL_ACTUAL_MULTIDISB_EXPECT_TRANCHES = 
"loanProductCreateResponseLP1InterestFlatDailyActualActualMultiDisbursementExpectTranches";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY
 = 
"loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOffBehaviourAccrualActivity";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_PRINCIPAL_FIRST
 = "loanProductCreateResponseLP2AdvancedPaymentHorizontalPrincipalFirst";
+    public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_FULL_TERM_TRANCHE
 = 
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyMultidisburseFullTermTranche";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD
 = "loanProductCreateResponseLP2AdvancedPaymentHorizontal36030Usd";
 }
diff --git 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanDelayedScheduleCaptures.feature
 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanDelayedScheduleCaptures.feature
new file mode 100644
index 0000000000..dece132e6d
--- /dev/null
+++ 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanDelayedScheduleCaptures.feature
@@ -0,0 +1,139 @@
+@DelayedScheduleCapturesFeature
+Feature: Full Term Tranche - Schedule handling and Calculations
+
+  @TestRailId:C4366
+  Scenario: Verify full term tranche interest bearing progressive loan - 
Schedule handling and Calculations - Disbursement on Installment Date - UC1
+    When Admin sets the business date to "01 January 2024"
+    When Admin creates a client with random data
+    When Admin creates a fully customized loan with the following data:
+      | LoanProduct                                                            
                       | submitted on date | with Principal | ANNUAL interest 
rate % | interest type     | interest calculation period | amortization type  | 
loanTermFrequency | loanTermFrequencyType | repaymentEvery | 
repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | 
graceOnInterestPayment | interest free period | Payment strategy            |
+      | 
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_FULL_TERM_TRANCHE
 | 01 January 2024   | 200            | 9.4822                 | 
DECLINING_BALANCE | DAILY                       | EQUAL_INSTALLMENTS | 6        
         | MONTHS                | 1              | MONTHS                 | 6  
                | 0                       | 0                      | 0          
          | ADVANCED_PAYMENT_ALLOCATION |
+    And Admin successfully approves the loan on "01 January 2024" with "200" 
amount and expected disbursement date on "01 January 2024"
+    When Admin successfully disburse the loan on "01 January 2024" with "100" 
EUR transaction amount
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date | Balance of loan | Principal 
due | Interest | Fees | Penalties | Due    | Paid | In advance | Late | 
Outstanding |
+      |    |      | 01 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      | 1  | 31   | 01 February 2024 |           | 83.66           | 16.34     
    | 0.79     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 2  | 29   | 01 March 2024    |           | 67.19           | 16.47     
    | 0.66     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 3  | 31   | 01 April 2024    |           | 50.59           | 16.6      
    | 0.53     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 4  | 30   | 01 May 2024      |           | 33.86           | 16.73     
    | 0.4      | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 5  | 31   | 01 June 2024     |           | 17.0            | 16.86     
    | 0.27     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 6  | 30   | 01 July 2024     |           | 0.0             | 17.0      
    | 0.13     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid | In 
advance | Late | Outstanding |
+      | 100.0         | 2.78     | 0.0  | 0.0       | 102.78 | 0.0  | 0.0      
  | 0.0  | 102.78      |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+#   --- 2nd disbursement on installment date ---
+    When Admin sets the business date to "01 February 2024"
+    When Admin successfully disburse the loan on "01 February 2024" with "100" 
EUR transaction amount
+    Then Loan Repayment schedule has 7 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date | Balance of loan | Principal 
due | Interest | Fees | Penalties | Due    | Paid | In advance | Late | 
Outstanding |
+      |    |      | 01 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      | 1  | 31   | 01 February 2024 |           | 83.66           | 16.34     
    | 0.79     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      |    |      | 01 February 2024 |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      | 2  | 29   | 01 March 2024    |           | 150.85          | 32.81     
    | 1.45     | 0.0  | 0.0       | 34.26  | 0.0  | 0.0        | 0.0  | 34.26   
    |
+      | 3  | 31   | 01 April 2024    |           | 117.78          | 33.07     
    | 1.19     | 0.0  | 0.0       | 34.26  | 0.0  | 0.0        | 0.0  | 34.26   
    |
+      | 4  | 30   | 01 May 2024      |           | 84.45           | 33.33     
    | 0.93     | 0.0  | 0.0       | 34.26  | 0.0  | 0.0        | 0.0  | 34.26   
    |
+      | 5  | 31   | 01 June 2024     |           | 50.86           | 33.59     
    | 0.67     | 0.0  | 0.0       | 34.26  | 0.0  | 0.0        | 0.0  | 34.26   
    |
+      | 6  | 30   | 01 July 2024     |           | 17.0            | 33.86     
    | 0.4      | 0.0  | 0.0       | 34.26  | 0.0  | 0.0        | 0.0  | 34.26   
    |
+      | 7  | 31   | 01 August 2024   |           | 0.0             | 17.0      
    | 0.13     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid | In 
advance | Late | Outstanding |
+      | 200.0         | 5.56     | 0.0  | 0.0       | 205.56 | 0.0  | 0.0      
  | 0.0  | 205.56      |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 01 February 2024 | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 200.0        | false    | false    |
+
+  @TestRailId:C4367
+  Scenario: Verify full term tranche interest bearing progressive loan - 
Schedule handling and Calculations - Disbursement mid-period - UC2
+    When Admin sets the business date to "01 January 2024"
+    When Admin creates a client with random data
+    When Admin creates a fully customized loan with the following data:
+      | LoanProduct                                                            
                       | submitted on date | with Principal | ANNUAL interest 
rate % | interest type     | interest calculation period | amortization type  | 
loanTermFrequency | loanTermFrequencyType | repaymentEvery | 
repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | 
graceOnInterestPayment | interest free period | Payment strategy            |
+      | 
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_FULL_TERM_TRANCHE
 | 01 January 2024   | 200            | 9.4822                 | 
DECLINING_BALANCE | DAILY                       | EQUAL_INSTALLMENTS | 6        
         | MONTHS                | 1              | MONTHS                 | 6  
                | 0                       | 0                      | 0          
          | ADVANCED_PAYMENT_ALLOCATION |
+    And Admin successfully approves the loan on "01 January 2024" with "200" 
amount and expected disbursement date on "01 January 2024"
+    When Admin successfully disburse the loan on "01 January 2024" with "100" 
EUR transaction amount
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date | Balance of loan | Principal 
due | Interest | Fees | Penalties | Due    | Paid | In advance | Late | 
Outstanding |
+      |    |      | 01 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      | 1  | 31   | 01 February 2024 |           | 83.66           | 16.34     
    | 0.79     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 2  | 29   | 01 March 2024    |           | 67.19           | 16.47     
    | 0.66     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 3  | 31   | 01 April 2024    |           | 50.59           | 16.6      
    | 0.53     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 4  | 30   | 01 May 2024      |           | 33.86           | 16.73     
    | 0.4      | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 5  | 31   | 01 June 2024     |           | 17.0            | 16.86     
    | 0.27     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 6  | 30   | 01 July 2024     |           | 0.0             | 17.0      
    | 0.13     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid | In 
advance | Late | Outstanding |
+      | 100.0         | 2.78     | 0.0  | 0.0       | 102.78 | 0.0  | 0.0      
  | 0.0  | 102.78      |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+#   --- 2nd disbursement mid-period (Feb 15) ---
+    When Admin sets the business date to "15 February 2024"
+    When Admin successfully disburse the loan on "15 February 2024" with "100" 
EUR transaction amount
+    Then Loan Repayment schedule has 7 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date | Balance of loan | Principal 
due | Interest | Fees | Penalties | Due    | Paid | In advance | Late | 
Outstanding |
+      |    |      | 01 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      | 1  | 31   | 01 February 2024 |           | 83.66           | 16.34     
    | 0.79     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      |    |      | 15 February 2024 |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      | 2  | 29   | 01 March 2024    |           | 150.59          | 33.07     
    | 1.13     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 3  | 31   | 01 April 2024    |           | 117.58          | 33.01     
    | 1.19     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 4  | 30   | 01 May 2024      |           | 84.31           | 33.27     
    | 0.93     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 5  | 31   | 01 June 2024     |           | 50.78           | 33.53     
    | 0.67     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 6  | 30   | 01 July 2024     |           | 16.92           | 33.86     
    | 0.4      | 0.0  | 0.0       | 34.26  | 0.0  | 0.0        | 0.0  | 34.26   
    |
+      | 7  | 31   | 01 August 2024   |           | 0.0             | 16.92     
    | 0.13     | 0.0  | 0.0       | 17.05  | 0.0  | 0.0        | 0.0  | 17.05   
    |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid | In 
advance | Late | Outstanding |
+      | 200.0         | 5.24     | 0.0  | 0.0       | 205.24 | 0.0  | 0.0      
  | 0.0  | 205.24      |
+    Then Loan Transactions tab has the following data:
+      | Transaction date  | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024   | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 15 February 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 200.0        | false    | false    |
+
+  @TestRailId:C4368
+  Scenario: Verify full term tranche interest bearing progressive loan - 
Schedule handling and Calculations - Both disbursements before first repayment 
- UC3
+    When Admin sets the business date to "01 January 2024"
+    When Admin creates a client with random data
+    When Admin creates a fully customized loan with the following data:
+      | LoanProduct                                                            
                       | submitted on date | with Principal | ANNUAL interest 
rate % | interest type     | interest calculation period | amortization type  | 
loanTermFrequency | loanTermFrequencyType | repaymentEvery | 
repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | 
graceOnInterestPayment | interest free period | Payment strategy            |
+      | 
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_FULL_TERM_TRANCHE
 | 01 January 2024   | 200            | 9.4822                 | 
DECLINING_BALANCE | DAILY                       | EQUAL_INSTALLMENTS | 6        
         | MONTHS                | 1              | MONTHS                 | 6  
                | 0                       | 0                      | 0          
          | ADVANCED_PAYMENT_ALLOCATION |
+    And Admin successfully approves the loan on "01 January 2024" with "200" 
amount and expected disbursement date on "01 January 2024"
+    When Admin successfully disburse the loan on "01 January 2024" with "100" 
EUR transaction amount
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date | Balance of loan | Principal 
due | Interest | Fees | Penalties | Due    | Paid | In advance | Late | 
Outstanding |
+      |    |      | 01 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      | 1  | 31   | 01 February 2024 |           | 83.66           | 16.34     
    | 0.79     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 2  | 29   | 01 March 2024    |           | 67.19           | 16.47     
    | 0.66     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 3  | 31   | 01 April 2024    |           | 50.59           | 16.6      
    | 0.53     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 4  | 30   | 01 May 2024      |           | 33.86           | 16.73     
    | 0.4      | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 5  | 31   | 01 June 2024     |           | 17.0            | 16.86     
    | 0.27     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+      | 6  | 30   | 01 July 2024     |           | 0.0             | 17.0      
    | 0.13     | 0.0  | 0.0       | 17.13  | 0.0  | 0.0        | 0.0  | 17.13   
    |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid | In 
advance | Late | Outstanding |
+      | 100.0         | 2.78     | 0.0  | 0.0       | 102.78 | 0.0  | 0.0      
  | 0.0  | 102.78      |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+#   --- 2nd disbursement before first repayment date (Jan 15) - no term 
extension ---
+    When Admin sets the business date to "15 January 2024"
+    When Admin successfully disburse the loan on "15 January 2024" with "100" 
EUR transaction amount
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date | Balance of loan | Principal 
due | Interest | Fees | Penalties | Due    | Paid | In advance | Late | 
Outstanding |
+      |    |      | 01 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      |    |      | 15 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0    | 0.0  |            |      |         
    |
+      | 1  | 31   | 01 February 2024 |           | 167.02          | 32.98     
    | 1.22     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 2  | 29   | 01 March 2024    |           | 134.14          | 32.88     
    | 1.32     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 3  | 31   | 01 April 2024    |           | 101.0           | 33.14     
    | 1.06     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 4  | 30   | 01 May 2024      |           | 67.6            | 33.4      
    | 0.8      | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 5  | 31   | 01 June 2024     |           | 33.93           | 33.67     
    | 0.53     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+      | 6  | 30   | 01 July 2024     |           | 0.0             | 33.93     
    | 0.27     | 0.0  | 0.0       | 34.2   | 0.0  | 0.0        | 0.0  | 34.2    
    |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid | In 
advance | Late | Outstanding |
+      | 200.0         | 5.2      | 0.0  | 0.0       | 205.2  | 0.0  | 0.0      
  | 0.0  | 205.2       |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 15 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 200.0        | false    | false    |
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/RepaymentScheduleRelatedLoanData.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/RepaymentScheduleRelatedLoanData.java
index c4997ca9d8..3f2b621f91 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/RepaymentScheduleRelatedLoanData.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/RepaymentScheduleRelatedLoanData.java
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.data;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
+import lombok.Getter;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
 
 /**
@@ -34,10 +35,19 @@ public class RepaymentScheduleRelatedLoanData {
     private final BigDecimal netDisbursalAmount;
     private final BigDecimal inArrearsTolerance;
     private final BigDecimal totalFeeChargesAtDisbursement;
+    @Getter
+    private final boolean allowFullTermForTranche;
 
     public RepaymentScheduleRelatedLoanData(final LocalDate 
expectedDisbursementDate, final LocalDate actualDisbursementDate,
             final CurrencyData currency, final BigDecimal principal, final 
BigDecimal inArrearsTolerance,
             final BigDecimal totalFeeChargesAtDisbursement) {
+        this(expectedDisbursementDate, actualDisbursementDate, currency, 
principal, inArrearsTolerance, totalFeeChargesAtDisbursement,
+                false);
+    }
+
+    public RepaymentScheduleRelatedLoanData(final LocalDate 
expectedDisbursementDate, final LocalDate actualDisbursementDate,
+            final CurrencyData currency, final BigDecimal principal, final 
BigDecimal inArrearsTolerance,
+            final BigDecimal totalFeeChargesAtDisbursement, final boolean 
allowFullTermForTranche) {
         this.expectedDisbursementDate = expectedDisbursementDate;
         this.actualDisbursementDate = actualDisbursementDate;
         this.currency = currency;
@@ -45,6 +55,7 @@ public class RepaymentScheduleRelatedLoanData {
         this.inArrearsTolerance = inArrearsTolerance;
         this.totalFeeChargesAtDisbursement = totalFeeChargesAtDisbursement;
         this.netDisbursalAmount = 
this.principal.subtract(this.totalFeeChargesAtDisbursement);
+        this.allowFullTermForTranche = allowFullTermForTranche;
     }
 
     public LocalDate disbursementDate() {
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 d8bfda8bc6..fa1984c86b 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
@@ -427,6 +427,7 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom<Long> {
     @Column(name = "enable_installment_level_delinquency", nullable = false)
     private boolean enableInstallmentLevelDelinquency = false;
 
+    @Getter
     @Column(name = "allow_full_term_for_tranche", nullable = false)
     private boolean allowFullTermForTranche = false;
 
@@ -1787,10 +1788,6 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom<Long> {
         this.enableInstallmentLevelDelinquency = 
enableInstallmentLevelDelinquency;
     }
 
-    public boolean isAllowFullTermForTranche() {
-        return this.allowFullTermForTranche;
-    }
-
     public void updateAllowFullTermForTranche(boolean allowFullTermForTranche) 
{
         this.allowFullTermForTranche = allowFullTermForTranche;
     }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
index 2ddf2b2465..ba233d7260 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
@@ -253,6 +253,10 @@ public class LoanRepaymentScheduleProcessingWrapper {
                 : DateUtils.isDateInRangeFromExclusiveToInclusive(targetDate, 
fromDate, toDate);
     }
 
+    public static boolean isInPeriodFromInclusiveToExclusive(final LocalDate 
targetDate, final LocalDate fromDate, final LocalDate toDate) {
+        return DateUtils.isDateInRangeFromInclusiveToExclusive(fromDate, 
toDate, targetDate);
+    }
+
     public static boolean isBeforePeriod(LocalDate targetDate, 
LoanRepaymentScheduleInstallment installment, boolean isFirstPeriod) {
         LocalDate fromDate = installment.getFromDate();
         return isFirstPeriod ? DateUtils.isBefore(targetDate, fromDate) : 
!DateUtils.isAfter(targetDate, fromDate);
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
index fc85244e2f..297ce1b0e4 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import lombok.Getter;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
@@ -247,6 +248,8 @@ public final class LoanApplicationTerms {
     private LoanBuyDownFeeStrategy buyDownFeeStrategy;
     private LoanBuyDownFeeIncomeType buyDownFeeIncomeType;
     private boolean merchantBuyDownFee;
+    @Getter
+    private boolean allowFullTermForTranche = false;
 
     private LoanApplicationTerms(Builder builder) {
         this.currency = builder.currency;
@@ -292,6 +295,7 @@ public final class LoanApplicationTerms {
         this.buyDownFeeStrategy = builder.buyDownFeeStrategy;
         this.buyDownFeeIncomeType = builder.buyDownFeeIncomeType;
         this.merchantBuyDownFee = builder.merchantBuyDownFee;
+        this.allowFullTermForTranche = builder.allowFullTermForTranche;
         this.interestMethod = builder.interestMethod;
         this.allowPartialPeriodInterestCalculation = 
builder.allowPartialPeriodInterestCalculation;
     }
@@ -333,6 +337,7 @@ public final class LoanApplicationTerms {
         private LoanBuyDownFeeStrategy buyDownFeeStrategy;
         private LoanBuyDownFeeIncomeType buyDownFeeIncomeType;
         private boolean merchantBuyDownFee;
+        private boolean allowFullTermForTranche;
         private boolean allowPartialPeriodInterestCalculation;
 
         public Builder interestMethod(InterestMethod interestMethod) {
@@ -500,6 +505,11 @@ public final class LoanApplicationTerms {
             return this;
         }
 
+        public Builder allowFullTermForTranche(boolean value) {
+            this.allowFullTermForTranche = value;
+            return this;
+        }
+
         public LoanApplicationTerms build() {
             return new LoanApplicationTerms(this);
         }
@@ -542,7 +552,8 @@ public final class LoanApplicationTerms {
                 
.submittedOnDate(modelData.scheduleGenerationStartDate()).seedDate(seedDate)
                 
.interestRecognitionOnDisbursementDate(modelData.interestRecognitionOnDisbursementDate())
                 
.daysInYearCustomStrategy(modelData.daysInYearCustomStrategy()).interestMethod(modelData.interestMethod())
-                
.allowPartialPeriodInterestCalculation(modelData.allowPartialPeriodInterestCalculation()).mc(mc).build();
+                
.allowPartialPeriodInterestCalculation(modelData.allowPartialPeriodInterestCalculation())
+                
.allowFullTermForTranche(modelData.allowFullTermForTranche()).mc(mc).build();
     }
 
     public static LoanApplicationTerms assembleFrom(final CurrencyData 
currency, final Integer loanTermFrequency,
@@ -579,7 +590,7 @@ public final class LoanApplicationTerms {
             final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, 
final LoanCapitalizedIncomeType capitalizedIncomeType,
             final boolean enableBuyDownFee, final 
LoanBuyDownFeeCalculationType buyDownFeeCalculationType,
             final LoanBuyDownFeeStrategy buyDownFeeStrategy, final 
LoanBuyDownFeeIncomeType buyDownFeeIncomeType,
-            final boolean merchantBuyDownFee) {
+            final boolean merchantBuyDownFee, final boolean 
allowFullTermForTranche) {
 
         final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
         final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -601,7 +612,7 @@ public final class LoanApplicationTerms {
                 fixedLength, enableAccrualActivityPosting, 
supportedInterestRefundTypes, chargeOffBehaviour,
                 interestRecognitionOnDisbursementDate, 
daysInYearCustomStrategy, enableIncomeCapitalization,
                 capitalizedIncomeCalculationType, capitalizedIncomeStrategy, 
capitalizedIncomeType, enableBuyDownFee,
-                buyDownFeeCalculationType, buyDownFeeStrategy, 
buyDownFeeIncomeType, merchantBuyDownFee);
+                buyDownFeeCalculationType, buyDownFeeStrategy, 
buyDownFeeIncomeType, merchantBuyDownFee, allowFullTermForTranche);
 
     }
 
@@ -622,7 +633,7 @@ public final class LoanApplicationTerms {
             final boolean isSkipRepaymentOnFirstDayOfMonth, final 
HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
             final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean 
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
             final BigDecimal fixedPrincipalPercentagePerInstallment, final 
boolean isPrincipalCompoundingDisabledForOverdueLoans,
-            final RepaymentStartDateType repaymentStartDateType, final 
LocalDate submittedOnDate) {
+            final RepaymentStartDateType repaymentStartDateType, final 
LocalDate submittedOnDate, final boolean allowFullTermForTranche) {
 
         final Integer numberOfRepayments = 
loanProductRelatedDetail.getNumberOfRepayments();
         final Integer repaymentEvery = 
loanProductRelatedDetail.getRepayEvery();
@@ -680,7 +691,7 @@ public final class LoanApplicationTerms {
                 loanProductRelatedDetail.getCapitalizedIncomeStrategy(), 
loanProductRelatedDetail.getCapitalizedIncomeType(),
                 loanProductRelatedDetail.isEnableBuyDownFee(), 
loanProductRelatedDetail.getBuyDownFeeCalculationType(),
                 loanProductRelatedDetail.getBuyDownFeeStrategy(), 
loanProductRelatedDetail.getBuyDownFeeIncomeType(),
-                loanProductRelatedDetail.isMerchantBuyDownFee());
+                loanProductRelatedDetail.isMerchantBuyDownFee(), 
allowFullTermForTranche);
     }
 
     private LoanApplicationTerms(final CurrencyData currency, final Integer 
loanTermFrequency,
@@ -716,7 +727,7 @@ public final class LoanApplicationTerms {
             final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, 
final LoanCapitalizedIncomeType capitalizedIncomeType,
             final boolean enableBuyDownFee, final 
LoanBuyDownFeeCalculationType buyDownFeeCalculationType,
             final LoanBuyDownFeeStrategy buyDownFeeStrategy, final 
LoanBuyDownFeeIncomeType buyDownFeeIncomeType,
-            final boolean merchantBuyDownFee) {
+            final boolean merchantBuyDownFee, final boolean 
allowFullTermForTranche) {
 
         this.currency = currency;
         this.loanTermFrequency = loanTermFrequency;
@@ -827,6 +838,7 @@ public final class LoanApplicationTerms {
         this.buyDownFeeStrategy = buyDownFeeStrategy;
         this.buyDownFeeIncomeType = buyDownFeeIncomeType;
         this.merchantBuyDownFee = merchantBuyDownFee;
+        this.allowFullTermForTranche = allowFullTermForTranche;
     }
 
     public Money adjustPrincipalIfLastRepaymentPeriod(final Money 
principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -1703,7 +1715,7 @@ public final class LoanApplicationTerms {
                 repaymentEvery, numberOfRepayments,
                 isInterestChargedFromDateSameAsDisbursalDateEnabled != null && 
isInterestChargedFromDateSameAsDisbursalDateEnabled,
                 daysInYearCustomStrategy, 
allowPartialPeriodInterestCalculation, interestRecalculationEnabled, 
recalculationFrequencyType,
-                preClosureInterestCalculationStrategy);
+                preClosureInterestCalculationStrategy, 
allowFullTermForTranche);
     }
 
     public Integer getLoanTermFrequency() {
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanRepaymentScheduleModelData.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanRepaymentScheduleModelData.java
index fe6b1e055a..66fca947cb 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanRepaymentScheduleModelData.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanRepaymentScheduleModelData.java
@@ -35,5 +35,6 @@ public record LoanRepaymentScheduleModelData(@NotNull 
LocalDate scheduleGenerati
         @NotNull boolean downPaymentEnabled, @NotNull DaysInMonthType 
daysInMonth, @NotNull DaysInYearType daysInYear,
         BigDecimal downPaymentPercentage, Integer 
installmentAmountInMultiplesOf, Integer fixedLength,
         @NotNull Boolean interestRecognitionOnDisbursementDate, @Nullable 
DaysInYearCustomStrategyType daysInYearCustomStrategy,
-        @NotNull InterestMethod interestMethod, @NotNull boolean 
allowPartialPeriodInterestCalculation) {
+        @NotNull InterestMethod interestMethod, @NotNull boolean 
allowPartialPeriodInterestCalculation,
+        @NotNull boolean allowFullTermForTranche) {
 }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanTermVariationsMapper.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanTermVariationsMapper.java
index 7fd5591e75..a4b909c6d6 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanTermVariationsMapper.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanTermVariationsMapper.java
@@ -120,7 +120,8 @@ public class LoanTermVariationsMapper {
                 scheduleGeneratorDTO.getNumberOfdays(), 
scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), holidayDetailDTO,
                 allowCompoundingOnEod, 
scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
                 
scheduleGeneratorDTO.isInterestToBeRecoveredFirstWhenGreaterThanEMI(), 
loan.getFixedPrincipalPercentagePerInstallment(),
-                
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), 
repaymentStartDateType, loan.getSubmittedOnDate());
+                
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), 
repaymentStartDateType, loan.getSubmittedOnDate(),
+                loan.isAllowFullTermForTranche());
     }
 
     private BigDecimal constructFloatingInterestRates(final BigDecimal 
annualNominalInterestRate, final FloatingRateDTO floatingRateDTO,
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanConfigurationDetails.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanConfigurationDetails.java
index a774dae562..977e9a513c 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanConfigurationDetails.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanConfigurationDetails.java
@@ -58,6 +58,8 @@ public class LoanConfigurationDetails implements 
ILoanConfigurationDetails {
     private final RecalculationFrequencyType restFrequencyType;
     @Getter
     private final LoanPreCloseInterestCalculationStrategy 
preCloseInterestCalculationStrategy;
+    @Getter
+    private final boolean allowFullTermForTranche;
 
     public LoanConfigurationDetails(CurrencyData currency, BigDecimal 
interestRatePerPeriod, BigDecimal annualNominalInterestRate,
             Integer interestChargingGrace, Integer interestPaymentGrace, 
Integer principalGrace,
@@ -67,7 +69,7 @@ public class LoanConfigurationDetails implements 
ILoanConfigurationDetails {
             Integer numberOfRepayments, boolean 
interestRecognitionOnDisbursementDate,
             DaysInYearCustomStrategyType daysInYearCustomStrategy, boolean 
allowPartialPeriodInterestCalculation,
             boolean isInterestRecalculationEnabled, RecalculationFrequencyType 
restFrequencyType,
-            LoanPreCloseInterestCalculationStrategy 
preCloseInterestCalculationStrategy) {
+            LoanPreCloseInterestCalculationStrategy 
preCloseInterestCalculationStrategy, boolean allowFullTermForTranche) {
         this.currency = currency;
         this.interestRatePerPeriod = interestRatePerPeriod;
         this.annualNominalInterestRate = annualNominalInterestRate;
@@ -89,6 +91,7 @@ public class LoanConfigurationDetails implements 
ILoanConfigurationDetails {
         this.isInterestRecalculationEnabled = isInterestRecalculationEnabled;
         this.restFrequencyType = restFrequencyType;
         this.preCloseInterestCalculationStrategy = 
preCloseInterestCalculationStrategy;
+        this.allowFullTermForTranche = allowFullTermForTranche;
     }
 
     private Integer defaultToNullIfZero(final Integer value) {
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/ILoanConfigurationDetails.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/ILoanConfigurationDetails.java
index ef5095198f..4ec89f0fd0 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/ILoanConfigurationDetails.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/ILoanConfigurationDetails.java
@@ -73,4 +73,6 @@ public interface ILoanConfigurationDetails {
     RecalculationFrequencyType getRestFrequencyType();
 
     LoanPreCloseInterestCalculationStrategy 
getPreCloseInterestCalculationStrategy();
+
+    boolean isAllowFullTermForTranche();
 }
diff --git 
a/fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java 
b/fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java
index 1b7d006eb6..e3fd40de21 100644
--- a/fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java
+++ b/fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java
@@ -62,7 +62,7 @@ public class Main {
         final InterestMethod interestMethod = InterestMethod.DECLINING_BALANCE;
         final boolean allowPartialPeriodInterestCalculation = true;
 
-        var config = new LoanRepaymentScheduleModelData(startDate, currency, 
disbursedAmount, disbursementDate, noRepayments, repaymentFrequency, 
repaymentFrequencyType, annualNominalInterestRate, isDownPaymentEnabled, 
daysInMonthType, daysInYearType, downPaymentPercentage, 
installmentAmountInMultiplesOf, fixedLength, 
interestRecognitionOnDisbursementDate, dasInYearCustomStrategy, interestMethod, 
allowPartialPeriodInterestCalculation);
+        var config = new LoanRepaymentScheduleModelData(startDate, currency, 
disbursedAmount, disbursementDate, noRepayments, repaymentFrequency, 
repaymentFrequencyType, annualNominalInterestRate, isDownPaymentEnabled, 
daysInMonthType, daysInYearType, downPaymentPercentage, 
installmentAmountInMultiplesOf, fixedLength, 
interestRecognitionOnDisbursementDate, dasInYearCustomStrategy, interestMethod, 
allowPartialPeriodInterestCalculation, false);
 
         final LoanSchedulePlan plan = calculator.generate(mc, config);
         printPlan(plan);
diff --git 
a/fineract-progressive-loan-embeddable-schedule-generator/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/EmbeddableProgressiveLoanScheduleGeneratorTest.java
 
b/fineract-progressive-loan-embeddable-schedule-generator/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/EmbeddableProgressiveLoanScheduleGeneratorTest.java
index 0eea0ff98f..7bf3e57311 100644
--- 
a/fineract-progressive-loan-embeddable-schedule-generator/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/EmbeddableProgressiveLoanScheduleGeneratorTest.java
+++ 
b/fineract-progressive-loan-embeddable-schedule-generator/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/EmbeddableProgressiveLoanScheduleGeneratorTest.java
@@ -67,7 +67,7 @@ class EmbeddableProgressiveLoanScheduleGeneratorTest {
         var config = new LoanRepaymentScheduleModelData(startDate, currency, 
disbursedAmount, disbursementDate, noRepayments,
                 repaymentFrequency, repaymentFrequencyType, 
annualNominalInterestRate, isDownPaymentEnabled, daysInMonthType,
                 daysInYearType, downPaymentPercentage, 
installmentAmountInMultiplesOf, fixedLength, 
interestRecognitionOnDisbursementDate,
-                daysInYearCustomStrategy, interestMethod, 
allowPartialPeriodInterestCalculation);
+                daysInYearCustomStrategy, interestMethod, 
allowPartialPeriodInterestCalculation, false);
 
         final LoanSchedulePlan plan = calculator.generate(mc, config);
 
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index a0b789a7fe..52c4a3267b 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -119,6 +119,7 @@ import 
org.apache.fineract.portfolio.loanproduct.domain.AllocationType;
 import 
org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType;
 import org.apache.fineract.portfolio.loanproduct.domain.DueType;
 import 
org.apache.fineract.portfolio.loanproduct.domain.FutureInstallmentAllocationRule;
+import 
org.apache.fineract.portfolio.loanproduct.domain.ILoanConfigurationDetails;
 import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
 import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
 import org.apache.fineract.portfolio.util.InstallmentProcessingHelper;
@@ -1595,7 +1596,7 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
         }
 
         disbursementTransaction.resetDerivedComponents();
-        recalculateRepaymentPeriodsWithEMICalculation(amortizableAmount, 
model, installments, transactionDate, currency);
+        recalculateRepaymentPeriodsWithEMICalculation(amortizableAmount, 
model, installments, disbursementTransaction, currency);
         allocateOverpayment(disbursementTransaction, transactionCtx);
     }
 
@@ -1669,7 +1670,7 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
         Money amortizableAmount = 
capitalizedIncomeTransaction.getAmount(currency);
         emiCalculator.addCapitalizedIncome(model, transactionDate, 
amortizableAmount);
 
-        recalculateRepaymentPeriodsWithEMICalculation(amortizableAmount, 
model, installments, transactionDate, currency);
+        recalculateRepaymentPeriodsWithEMICalculation(amortizableAmount, 
model, installments, capitalizedIncomeTransaction, currency);
         allocateOverpayment(capitalizedIncomeTransaction, transactionCtx);
     }
 
@@ -1689,9 +1690,11 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
         allocateOverpayment(capitalizedIncomeTransaction, transactionCtx);
     }
 
-    private void recalculateRepaymentPeriodsWithEMICalculation(Money 
amortizableAmount, ProgressiveLoanInterestScheduleModel model,
-            List<LoanRepaymentScheduleInstallment> installments, LocalDate 
transactionDate, MonetaryCurrency currency) {
-        boolean isPostMaturityDisbursement = installments.stream().filter(i -> 
!i.isDownPayment() && !i.isAdditional())
+    private void recalculateRepaymentPeriodsWithEMICalculation(final Money 
amortizableAmount,
+            final ProgressiveLoanInterestScheduleModel model, final 
List<LoanRepaymentScheduleInstallment> installments,
+            final LoanTransaction loanTransaction, final MonetaryCurrency 
currency) {
+        final LocalDate transactionDate = loanTransaction.getTransactionDate();
+        final boolean isPostMaturityDisbursement = 
installments.stream().filter(i -> !i.isDownPayment() && !i.isAdditional())
                 .allMatch(i -> i.getDueDate().isBefore(transactionDate));
 
         if (amortizableAmount.isGreaterThanZero()) {
@@ -1703,14 +1706,34 @@ public class 
AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
                 }
             }
 
+            final ListIterator<LoanRepaymentScheduleInstallment> iterator = 
installments.listIterator();
+            final AtomicInteger installmentCounter = new AtomicInteger();
+            final ILoanConfigurationDetails loanProductRelatedDetail = 
model.loanProductRelatedDetail();
+
             model.repaymentPeriods().forEach(rm -> {
-                LoanRepaymentScheduleInstallment installment = 
installments.stream().filter(
-                        ri -> ri.getDueDate().equals(rm.getDueDate()) && 
!ri.isDownPayment() && !ri.getDueDate().isBefore(transactionDate))
-                        .findFirst().orElse(null);
-                if (installment != null) {
+                LoanRepaymentScheduleInstallment installment = null;
+                while (iterator.hasNext() && (installment == null || 
installment.isAdditional() || installment.isDownPayment())) {
+                    installment = iterator.next();
+                    installmentCounter.getAndIncrement();
+                }
+
+                if (installment != null && 
installment.getDueDate().equals(rm.getDueDate())
+                        && 
!installment.getDueDate().isBefore(transactionDate)) {
                     
installment.updatePrincipal(rm.getDuePrincipal().getAmount());
                     
installment.updateInterestCharged(rm.getDueInterest().getAmount());
                     installment.updateObligationsMet(currency, 
transactionDate);
+                } else {
+                    if (loanProductRelatedDetail != null && 
loanProductRelatedDetail.isAllowFullTermForTranche()
+                            && 
loanProductRelatedDetail.getNumberOfRepayments() > 0 && 
!rm.getDueDate().isBefore(transactionDate)) {
+                        installmentCounter.getAndIncrement();
+                        final LoanRepaymentScheduleInstallment newInstallment 
= new LoanRepaymentScheduleInstallment(
+                                loanTransaction.getLoan(), 
installmentCounter.get(), rm.getFromDate(), rm.getDueDate(),
+                                rm.getDuePrincipal().getAmount(), 
rm.getDueInterest().getAmount(), null, null, null, null, null, null,
+                                false, false, false);
+
+                        newInstallment.updateObligationsMet(currency, 
transactionDate);
+                        iterator.add(newInstallment);
+                    }
                 }
             });
         }
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanConfigurationDetailsMapper.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanConfigurationDetailsMapper.java
index 9e80895dc0..487c7069ed 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanConfigurationDetailsMapper.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanConfigurationDetailsMapper.java
@@ -56,7 +56,8 @@ public final class LoanConfigurationDetailsMapper {
                 loanProductRelatedDetail.getRepaymentPeriodFrequencyType(), 
loanProductRelatedDetail.getRepayEvery(),
                 loanProductRelatedDetail.getNumberOfRepayments(), 
loanProductRelatedDetail.isInterestRecognitionOnDisbursementDate(),
                 loanProductRelatedDetail.getDaysInYearCustomStrategy(), 
loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation(),
-                loan.isInterestRecalculationEnabled(), 
getRestFrequencyType(loan), getPreCloseInterestCalculationStrategy(loan));
+                loan.isInterestRecalculationEnabled(), 
getRestFrequencyType(loan), getPreCloseInterestCalculationStrategy(loan),
+                loan.isAllowFullTermForTranche());
     }
 
     private static RecalculationFrequencyType getRestFrequencyType(Loan loan) {
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
index 041e7c97f7..83868d5789 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
@@ -18,6 +18,9 @@
  */
 package org.apache.fineract.portfolio.loanproduct.calc;
 
+import static java.math.BigDecimal.ZERO;
+import static 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper.isInPeriodFromInclusiveToExclusive;
+
 import jakarta.annotation.Nonnull;
 import jakarta.validation.constraints.NotNull;
 import java.math.BigDecimal;
@@ -134,12 +137,112 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
         scheduleModel.repaymentPeriods().stream().filter(rp -> 
!operation.getSubmittedOnDate().isAfter(rp.getFromDate()))
                 .forEach(rp -> 
rp.setTotalDisbursedAmount(rp.getTotalDisbursedAmount().add(operation.getAmount())));
 
-        scheduleModel
-                
.changeOutstandingBalanceAndUpdateInterestPeriods(operation.getSubmittedOnDate(),
 operation.getAmount(),
-                        scheduleModel.zero(), scheduleModel.zero())
-                .ifPresent((repaymentPeriod) -> 
calculateEMIValueAndRateFactors(
-                        getEffectiveRepaymentDueDate(scheduleModel, 
repaymentPeriod, operation.getSubmittedOnDate()), scheduleModel,
-                        operation));
+        final int numberOfRepayments = 
scheduleModel.loanProductRelatedDetail().getNumberOfRepayments();
+        if 
(scheduleModel.loanProductRelatedDetail().isAllowFullTermForTranche() && 
numberOfRepayments > 0) {
+            addFullTermTrancheDisbursement(scheduleModel, operation);
+        } else {
+            scheduleModel
+                    
.changeOutstandingBalanceAndUpdateInterestPeriods(operation.getSubmittedOnDate(),
 operation.getAmount(),
+                            scheduleModel.zero(), scheduleModel.zero())
+                    .ifPresent((repaymentPeriod) -> 
calculateEMIValueAndRateFactors(
+                            getEffectiveRepaymentDueDate(scheduleModel, 
repaymentPeriod, operation.getSubmittedOnDate()), scheduleModel,
+                            operation));
+        }
+    }
+
+    private void addFullTermTrancheDisbursement(final 
ProgressiveLoanInterestScheduleModel scheduleModel,
+            final EmiChangeOperation operation) {
+        final MathContext mc = scheduleModel.mc();
+        final LocalDate disbursementDate = operation.getSubmittedOnDate();
+        final Money disbursedAmount = operation.getAmount();
+        final ILoanConfigurationDetails loanProductRelatedDetail = 
scheduleModel.loanProductRelatedDetail();
+        final Optional<RepaymentPeriod> firstDisbursedPeriod = 
scheduleModel.repaymentPeriods().stream()
+                .filter(period -> 
isInPeriodFromInclusiveToExclusive(disbursementDate, period.getFromDate(), 
period.getDueDate()))
+                .findFirst();
+        final LocalDate firstDisbursedPeriodStartDate = 
firstDisbursedPeriod.isPresent() ? firstDisbursedPeriod.get().getFromDate()
+                : scheduleModel.getMaturityDate();
+
+        final LoanApplicationTerms loanApplicationTerms = 
buildLoanApplicationTerms(loanProductRelatedDetail, 
firstDisbursedPeriodStartDate,
+                disbursedAmount, mc);
+
+        final ProgressiveLoanInterestScheduleModel 
temporaryReAgedScheduleModel = 
generateTemporaryScheduleModel(loanApplicationTerms, mc,
+                firstDisbursedPeriodStartDate, disbursementDate);
+
+        mergeNewScheduleModelWithExistingOne(scheduleModel, 
temporaryReAgedScheduleModel, operation);
+    }
+
+    private LoanApplicationTerms buildLoanApplicationTerms(final 
ILoanConfigurationDetails loanProductRelatedDetail,
+            final LocalDate firstDisbursedPeriodStartDate, final Money 
disbursedAmount, final MathContext mc) {
+        return new LoanApplicationTerms.Builder()
+                // Loan basics
+                
.currency(loanProductRelatedDetail.getCurrencyData()).principal(disbursedAmount)
+                
.repaymentsStartingFromDate(firstDisbursedPeriodStartDate).downPaymentPercentage(ZERO)
+                
.seedDate(firstDisbursedPeriodStartDate).inArrearsTolerance(Money.zero(loanProductRelatedDetail.getCurrencyData()))
+                // Term & frequency
+                
.loanTermFrequency(loanProductRelatedDetail.getNumberOfRepayments())
+                
.loanTermPeriodFrequencyType(loanProductRelatedDetail.getRepaymentPeriodFrequencyType())
+                
.numberOfRepayments(loanProductRelatedDetail.getNumberOfRepayments())
+                .repaymentEvery(loanProductRelatedDetail.getRepayEvery())
+                
.repaymentPeriodFrequencyType(loanProductRelatedDetail.getRepaymentPeriodFrequencyType())
+                // Interest configuration
+                
.interestRatePerPeriod(loanProductRelatedDetail.getAnnualNominalInterestRate())
+                
.annualNominalInterestRate(loanProductRelatedDetail.getAnnualNominalInterestRate())
+                
.interestRatePeriodFrequencyType(loanProductRelatedDetail.getRepaymentPeriodFrequencyType())
+                .interestMethod(loanProductRelatedDetail.getInterestMethod())
+                
.interestRecognitionOnDisbursementDate(loanProductRelatedDetail.isInterestRecognitionOnDisbursementDate())
+                // Day count conventions
+                
.daysInMonthType(DaysInMonthType.fromInt(loanProductRelatedDetail.getDaysInMonthType()))
+                
.daysInYearType(DaysInYearType.fromInt(loanProductRelatedDetail.getDaysInYearType()))
+                
.daysInYearCustomStrategy(loanProductRelatedDetail.getDaysInYearCustomStrategy())
+                // Flags & options
+                .isDownPaymentEnabled(false)
+                
.allowPartialPeriodInterestCalculation(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation())
+                // Technical
+                .mc(mc).build();
+    }
+
+    private void mergeNewScheduleModelWithExistingOne(final 
ProgressiveLoanInterestScheduleModel scheduleModel,
+            final ProgressiveLoanInterestScheduleModel temporaryScheduleModel, 
final EmiChangeOperation operation) {
+        final List<RepaymentPeriod> newPeriods = 
temporaryScheduleModel.repaymentPeriods();
+
+        if (newPeriods.isEmpty()) {
+            return;
+        }
+
+        final List<RepaymentPeriod> existingRepaymentPeriods = 
scheduleModel.repaymentPeriods();
+
+        
scheduleModel.changeOutstandingBalanceAndUpdateInterestPeriods(operation.getSubmittedOnDate(),
 operation.getAmount(),
+                scheduleModel.zero(), scheduleModel.zero());
+
+        for (final RepaymentPeriod newPeriod : newPeriods) {
+            final Money newPrincipal = newPeriod.getDuePrincipal();
+            final Money newInterest = newPeriod.getDueInterest();
+
+            final Optional<RepaymentPeriod> existingRepaymentPeriod = 
existingRepaymentPeriods.stream()
+                    .filter(ep -> 
ep.getFromDate().isEqual(newPeriod.getFromDate()) && 
ep.getDueDate().equals(newPeriod.getDueDate()))
+                    .findFirst();
+
+            if (existingRepaymentPeriod.isPresent()) {
+                
existingRepaymentPeriod.get().setEmi(existingRepaymentPeriod.get().getEmi().add(newPrincipal.add(newInterest)));
+                
existingRepaymentPeriod.get().setOriginalEmi(existingRepaymentPeriod.get().getEmi());
+                
calculateRateFactorForRepaymentPeriod(existingRepaymentPeriod.get(), 
scheduleModel);
+            } else {
+                final RepaymentPeriod rp = RepaymentPeriod.create(
+                        !existingRepaymentPeriods.isEmpty() ? 
existingRepaymentPeriods.getLast() : null,
+                        (newPeriod.equals(newPeriods.getFirst()) && 
!existingRepaymentPeriods.isEmpty())
+                                ? 
existingRepaymentPeriods.getLast().getDueDate()
+                                : newPeriod.getFromDate(),
+                        newPeriod.getDueDate(), newPrincipal.add(newInterest), 
scheduleModel.mc(),
+                        scheduleModel.loanProductRelatedDetail());
+                
rp.setTotalDisbursedAmount(scheduleModel.getLastRepaymentPeriod().getTotalDisbursedAmount());
+
+                existingRepaymentPeriods.add(rp);
+                calculateRateFactorForRepaymentPeriod(rp, scheduleModel);
+            }
+        }
+
+        calculateOutstandingBalance(scheduleModel);
+        calculateLastUnpaidRepaymentPeriodEMI(scheduleModel, 
operation.getSubmittedOnDate());
     }
 
     private LocalDate getEffectiveRepaymentDueDate(final 
ProgressiveLoanInterestScheduleModel scheduleModel,
@@ -590,10 +693,10 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
 
         
moveOutstandingAmountsFromPeriodsBeforeTransactionDate(scheduleModel.repaymentPeriods(),
 targetDate);
 
-        final ProgressiveLoanInterestScheduleModel 
temporaryReAgedScheduleModel = 
generateTemporaryReAgedScheduleModel(loanApplicationTerms,
-                mc, reAgePeriodStartDate);
+        final ProgressiveLoanInterestScheduleModel 
temporaryReAgedScheduleModel = 
generateTemporaryScheduleModel(loanApplicationTerms, mc,
+                reAgePeriodStartDate, reAgePeriodStartDate);
 
-        mergeNewInterestScheduleModelWithExistingOne(scheduleModel, 
temporaryReAgedScheduleModel, reAgeFirstDueDate, targetDate,
+        
attachTemporaryScheduleModelReAgedPeriodsToExistingModel(scheduleModel, 
temporaryReAgedScheduleModel, reAgeFirstDueDate, targetDate,
                 paidBalancesFromTransactionDate);
     }
 
@@ -853,11 +956,11 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
     }
 
     /**
-     * * Merging the new temporary model of re-aged repayment periods and 
existing one together. After that recalculate
-     * the balances of the updated model and also recalculate the EMI if the 
EMI of the last repayment period differs
-     * significantly from other periods.
+     * * Attaching re-aged repayment periods of the new temporary model to 
existing model repayment periods. After that
+     * recalculate the balances of the updated model and also recalculate the 
EMI if the EMI of the last repayment
+     * period differs significantly from other periods.
      */
-    private void mergeNewInterestScheduleModelWithExistingOne(final 
ProgressiveLoanInterestScheduleModel scheduleModel,
+    private void 
attachTemporaryScheduleModelReAgedPeriodsToExistingModel(final 
ProgressiveLoanInterestScheduleModel scheduleModel,
             final ProgressiveLoanInterestScheduleModel 
temporaryReAgedScheduleModel, final LocalDate reAgeFirstDueDate,
             final LocalDate targetDate, final OutstandingDetails 
paidBalancesFromTransactionDate) {
         final List<RepaymentPeriod> newPeriods = 
temporaryReAgedScheduleModel.repaymentPeriods();
@@ -914,18 +1017,18 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
     }
 
     /**
-     * * Generates temporary interestScheduleModel with re-aged repayment 
periods
+     * * Generates temporary interestScheduleModel with particular 
disbursement date
      */
     @NotNull
-    private ProgressiveLoanInterestScheduleModel 
generateTemporaryReAgedScheduleModel(final LoanApplicationTerms 
loanApplicationTerms,
-            final MathContext mc, final LocalDate periodStartDate) {
+    private ProgressiveLoanInterestScheduleModel 
generateTemporaryScheduleModel(final LoanApplicationTerms loanApplicationTerms,
+            final MathContext mc, final LocalDate periodStartDate, final 
LocalDate disbursementDate) {
         final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods 
= scheduledDateGenerator.generateRepaymentPeriods(mc,
                 periodStartDate, loanApplicationTerms, null);
         final ProgressiveLoanInterestScheduleModel 
temporaryReAgedScheduleModel = generatePeriodInterestScheduleModel(
                 expectedRepaymentPeriods, 
loanApplicationTerms.toLoanConfigurationDetails(),
                 loanApplicationTerms.getInstallmentAmountInMultiplesOf(), mc);
 
-        addDisbursement(temporaryReAgedScheduleModel, 
EmiChangeOperation.disburse(periodStartDate, 
loanApplicationTerms.getPrincipal()));
+        addDisbursement(temporaryReAgedScheduleModel, 
EmiChangeOperation.disburse(disbursementDate, 
loanApplicationTerms.getPrincipal()));
         return temporaryReAgedScheduleModel;
     }
 
diff --git 
a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
 
b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
index e192fe5fe1..06d86fe6ad 100644
--- 
a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
+++ 
b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
@@ -65,7 +65,7 @@ class LoanScheduleGeneratorTest {
         LoanRepaymentScheduleModelData modelData = new 
LoanRepaymentScheduleModelData(LocalDate.of(2024, 1, 1), CURRENCY,
                 DISBURSEMENT_AMOUNT, DISBURSEMENT_DATE, NUMBER_OF_REPAYMENTS, 
REPAYMENT_FREQUENCY, REPAYMENT_FREQUENCY_TYPE,
                 NOMINAL_INTEREST_RATE, false, DaysInMonthType.DAYS_30, 
DaysInYearType.DAYS_360, null, null, null, false, null,
-                InterestMethod.DECLINING_BALANCE, true);
+                InterestMethod.DECLINING_BALANCE, true, false);
 
         ScheduledDateGenerator scheduledDateGenerator = new 
DefaultScheduledDateGenerator();
         ProgressiveLoanScheduleGenerator generator = new 
ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator,
@@ -103,7 +103,7 @@ class LoanScheduleGeneratorTest {
         LoanRepaymentScheduleModelData modelData = new 
LoanRepaymentScheduleModelData(LocalDate.of(2024, 1, 1), CURRENCY,
                 DISBURSEMENT_AMOUNT_100, LocalDate.of(2024, 1, 1), 
NUMBER_OF_REPAYMENTS, REPAYMENT_FREQUENCY, REPAYMENT_FREQUENCY_TYPE,
                 NOMINAL_INTEREST_RATE, true, DaysInMonthType.DAYS_30, 
DaysInYearType.DAYS_360, DOWN_PAYMENT_PORTION, null, null, false,
-                null, InterestMethod.DECLINING_BALANCE, true);
+                null, InterestMethod.DECLINING_BALANCE, true, false);
 
         ScheduledDateGenerator scheduledDateGenerator = new 
DefaultScheduledDateGenerator();
         ProgressiveLoanScheduleGenerator generator = new 
ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator,
diff --git 
a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java
 
b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java
index c67c5a8bd0..9fb3cfc26a 100644
--- 
a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java
+++ 
b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java
@@ -235,6 +235,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
         Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+        
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                 expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -582,6 +583,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
         Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+        
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
         
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 15));
 
@@ -1348,6 +1350,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
         Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+        
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
         final ProgressiveLoanInterestScheduleModel interestModel = 
emiCalculator.generatePeriodInterestScheduleModel(
                 expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -2476,6 +2479,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -2533,6 +2537,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -2601,6 +2606,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -2953,6 +2959,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -2991,6 +2998,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -3028,6 +3036,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -3068,6 +3077,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -3107,6 +3117,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(2);
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -3143,6 +3154,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
             
Mockito.when(loanProductRelatedDetail.getDaysInYearCustomStrategy())
                     
.thenReturn(DaysInYearCustomStrategyType.FEB_29_PERIOD_ONLY);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -3363,6 +3375,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(4);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
             
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
@@ -3402,6 +3415,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(4);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.ACTUAL.getValue());
             
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
@@ -3441,6 +3455,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.DAYS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(4);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(30);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.ACTUAL.getValue());
             
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
@@ -3530,6 +3545,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getInterestCalculationPeriodMethod())
                     
.thenReturn(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
                     expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
@@ -3558,6 +3574,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(8);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(2);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final List<LoanScheduleModelRepaymentPeriod> 
expectedRepaymentPeriods = generateExpectedRepaymentPeriods(disbursementDate);
             final Integer installmentAmountInMultiplesOf = null;
@@ -3587,6 +3604,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(3);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation()).thenReturn(true);
 
@@ -3620,6 +3638,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(3);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation()).thenReturn(false);
 
@@ -3653,6 +3672,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(3);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final List<LoanScheduleModelRepaymentPeriod> 
expectedRepaymentPeriods = generateExpectedRepaymentPeriods(disbursementDate);
 
@@ -3691,6 +3711,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(20);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final List<LoanScheduleModelRepaymentPeriod> 
expectedRepaymentPeriods = generateExpectedRepaymentPeriods(disbursementDate);
             final Integer installmentAmountInMultiplesOf = null;
@@ -3732,6 +3753,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(24);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final List<LoanScheduleModelRepaymentPeriod> 
expectedRepaymentPeriods = generateExpectedRepaymentPeriods(disbursementDate);
             final Integer installmentAmountInMultiplesOf = null;
@@ -3806,6 +3828,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(3);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
             
Mockito.when(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation()).thenReturn(false);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             final List<LoanScheduleModelRepaymentPeriod> 
expectedRepaymentPeriods = generateExpectedRepaymentPeriods(disbursementDate);
 
@@ -3855,6 +3878,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(3);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation()).thenReturn(true);
 
@@ -3892,6 +3916,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(3);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation()).thenReturn(true);
 
@@ -3928,6 +3953,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(3);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation()).thenReturn(false);
 
@@ -3986,6 +4012,7 @@ class ProgressiveEMICalculatorTest {
             
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
             
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(3);
             
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+            
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(false);
 
             
Mockito.when(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation()).thenReturn(false);
 
@@ -5152,4 +5179,72 @@ class ProgressiveEMICalculatorTest {
         return interestScheduleModelService.fromJson(json, 
toCopy.loanProductRelatedDetail(), toCopy.mc(),
                 toCopy.installmentAmountInMultiplesOf());
     }
+
+    @Test
+    public void 
test_fullTermTranche_disbursedAmt200_2ndOnDueDate_dayInYears360_daysInMonth30_repayEvery1Month()
 {
+        // Create 7 periods (6 original + 1 extension for second tranche)
+        final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods 
= new ArrayList<>();
+
+        expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), 
LocalDate.of(2024, 2, 1)));
+        expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), 
LocalDate.of(2024, 3, 1)));
+        expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), 
LocalDate.of(2024, 4, 1)));
+        expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), 
LocalDate.of(2024, 5, 1)));
+        expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), 
LocalDate.of(2024, 6, 1)));
+        expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), 
LocalDate.of(2024, 7, 1)));
+        expectedRepaymentPeriods.add(repayment(7, LocalDate.of(2024, 7, 1), 
LocalDate.of(2024, 8, 1)));
+
+        final BigDecimal interestRate = BigDecimal.valueOf(9.4822);
+        final Integer installmentAmountInMultiplesOf = null;
+
+        
Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate);
+        
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
+        
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
+        
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
+        Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
+        
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
+        
Mockito.when(loanProductRelatedDetail.getNumberOfRepayments()).thenReturn(6);
+        // Enable full term tranche feature
+        
Mockito.when(loanProductRelatedDetail.isAllowFullTermForTranche()).thenReturn(true);
+
+        final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+
+        // First disbursement: 100 on Jan 1 -> should set EMI ~17.13 on 
periods 0-5
+        final Money disbursedAmount1 = toMoney(100.0);
+        emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount1);
+
+        // Check EMI after first disbursement - periods 0-5 should have ~17.13
+        Assertions.assertEquals(17.13, 
toDouble(interestSchedule.repaymentPeriods().get(0).getEmi()), 0.01,
+                "Period 0 EMI after first disbursement");
+        Assertions.assertEquals(17.13, 
toDouble(interestSchedule.repaymentPeriods().get(1).getEmi()), 0.01,
+                "Period 1 EMI after first disbursement");
+        Assertions.assertEquals(17.13, 
toDouble(interestSchedule.repaymentPeriods().get(2).getEmi()), 0.01,
+                "Period 2 EMI after first disbursement");
+        Assertions.assertEquals(17.13, 
toDouble(interestSchedule.repaymentPeriods().get(3).getEmi()), 0.01,
+                "Period 3 EMI after first disbursement");
+        Assertions.assertEquals(17.13, 
toDouble(interestSchedule.repaymentPeriods().get(4).getEmi()), 0.01,
+                "Period 4 EMI after first disbursement");
+        Assertions.assertEquals(17.13, 
toDouble(interestSchedule.repaymentPeriods().get(5).getEmi()), 0.01,
+                "Period 5 EMI after first disbursement");
+        Assertions.assertEquals(0.0, 
toDouble(interestSchedule.repaymentPeriods().get(6).getEmi()), 0.01,
+                "Period 6 EMI after first disbursement (should be 0)");
+
+        // Second disbursement: 100 on Feb 1 -> should ADD EMI ~17.13 to 
periods 1-6
+        final Money disbursedAmount2 = toMoney(100.0);
+        emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 2, 
1), disbursedAmount2);
+
+        // Verify EMI values:
+        // Period 0: EMI = 17.13 (only first tranche)
+        // Periods 1-5: EMI = 34.26 (both tranches)
+        // Period 6: EMI = 17.13 (only second tranche)
+        Assertions.assertEquals(17.13, 
toDouble(interestSchedule.repaymentPeriods().get(0).getEmi()), 0.01,
+                "Period 0 EMI (single tranche)");
+        Assertions.assertEquals(34.26, 
toDouble(interestSchedule.repaymentPeriods().get(1).getEmi()), 0.01, "Period 1 
EMI (aggregated)");
+        Assertions.assertEquals(34.26, 
toDouble(interestSchedule.repaymentPeriods().get(2).getEmi()), 0.01, "Period 2 
EMI (aggregated)");
+        Assertions.assertEquals(34.26, 
toDouble(interestSchedule.repaymentPeriods().get(3).getEmi()), 0.01, "Period 3 
EMI (aggregated)");
+        Assertions.assertEquals(34.26, 
toDouble(interestSchedule.repaymentPeriods().get(4).getEmi()), 0.01, "Period 4 
EMI (aggregated)");
+        Assertions.assertEquals(34.26, 
toDouble(interestSchedule.repaymentPeriods().get(5).getEmi()), 0.01, "Period 5 
EMI (aggregated)");
+        Assertions.assertEquals(17.13, 
toDouble(interestSchedule.repaymentPeriods().get(6).getEmi()), 0.01,
+                "Period 6 EMI (single tranche)");
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
index 01d0e2edde..306230d682 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
@@ -527,7 +527,8 @@ public class LoansApiResource {
 
                     RepaymentScheduleRelatedLoanData 
repaymentScheduleRelatedData = new RepaymentScheduleRelatedLoanData(
                             i.getTimeline().getExpectedDisbursementDate(), 
i.getTimeline().getActualDisbursementDate(), i.getCurrency(),
-                            i.getPrincipal(), i.getInArrearsTolerance(), 
i.getFeeChargesAtDisbursementCharged());
+                            i.getPrincipal(), i.getInArrearsTolerance(), 
i.getFeeChargesAtDisbursementCharged(),
+                            
Boolean.TRUE.equals(i.getAllowFullTermForTranche()));
                     LoanScheduleData repaymentSchedule = 
loanReadPlatformService.retrieveRepaymentSchedule(loanId,
                             repaymentScheduleRelatedData, disbursementData, 
capitalizedIncomeData, i.isInterestRecalculationEnabled(),
                             
LoanScheduleType.fromEnumOptionData(i.getLoanScheduleType()));
@@ -1098,7 +1099,8 @@ public class LoansApiResource {
                         
loanBasicDetails.getTimeline().getExpectedDisbursementDate(),
                         
loanBasicDetails.getTimeline().getActualDisbursementDate(), 
loanBasicDetails.getCurrency(),
                         loanBasicDetails.getPrincipal(), 
loanBasicDetails.getInArrearsTolerance(),
-                        loanBasicDetails.getFeeChargesAtDisbursementCharged());
+                        loanBasicDetails.getFeeChargesAtDisbursementCharged(),
+                        
Boolean.TRUE.equals(loanBasicDetails.getAllowFullTermForTranche()));
                 repaymentSchedule = 
this.loanReadPlatformService.retrieveRepaymentSchedule(resolvedLoanId, 
repaymentScheduleRelatedData,
                         disbursementData, capitalizedIncomeData, 
loanBasicDetails.isInterestRecalculationEnabled(),
                         
LoanScheduleType.fromEnumOptionData(loanBasicDetails.getLoanScheduleType()));
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index 768a38a64b..d07d48b59b 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -533,6 +533,11 @@ public class LoanScheduleAssembler {
                     
.extractBooleanNamed(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE,
 element);
         }
 
+        boolean allowFullTermForTranche = 
loanProduct.isAllowFullTermForTranche();
+        if 
(this.fromApiJsonHelper.parameterExists(LoanApiConstants.ALLOW_FULL_TERM_FOR_TRANCHE,
 element)) {
+            allowFullTermForTranche = 
this.fromApiJsonHelper.extractBooleanNamed(LoanApiConstants.ALLOW_FULL_TERM_FOR_TRANCHE,
 element);
+        }
+
         return LoanApplicationTerms.assembleFrom(applicationCurrency.toData(), 
loanTermFrequency, loanTermPeriodFrequencyType,
                 numberOfRepayments, repaymentEvery, 
repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, 
interestMethod,
                 interestRatePerPeriod, interestRatePeriodFrequencyType, 
annualNominalInterestRate, interestCalculationPeriodMethod,
@@ -561,7 +566,7 @@ public class LoanScheduleAssembler {
                 
loanProduct.getLoanProductRelatedDetail().getBuyDownFeeCalculationType(),
                 
loanProduct.getLoanProductRelatedDetail().getBuyDownFeeStrategy(),
                 
loanProduct.getLoanProductRelatedDetail().getBuyDownFeeIncomeType(),
-                
loanProduct.getLoanProductRelatedDetail().isMerchantBuyDownFee());
+                
loanProduct.getLoanProductRelatedDetail().isMerchantBuyDownFee(), 
allowFullTermForTranche);
     }
 
     private CalendarInstance createCalendarForSameAsRepayment(final Integer 
repaymentEvery,
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index 7003b0b73e..669206db30 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -259,7 +259,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService, Loa
         final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = 
new RepaymentScheduleRelatedLoanData(
                 accountData.getTimeline().getExpectedDisbursementDate(), 
accountData.getTimeline().getActualDisbursementDate(),
                 accountData.getCurrency(), accountData.getPrincipal(), 
accountData.getInArrearsTolerance(),
-                accountData.getFeeChargesAtDisbursementCharged());
+                accountData.getFeeChargesAtDisbursementCharged(), 
Boolean.TRUE.equals(accountData.getAllowFullTermForTranche()));
 
         final Collection<DisbursementData> disbursementData = 
retrieveLoanDisbursementDetails(accountData.getId());
         List<LoanTransactionRepaymentPeriodData> capitalizedIncomeData = 
loanCapitalizedIncomeBalanceRepository
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
index f929fdc8b3..c5fb2085b6 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
@@ -91,7 +91,7 @@ public class DefaultScheduledDateGeneratorTest {
                 DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, 
null, null, null, null, ZERO, null, NONE, null, ZERO,
                 EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, 
false, null, false, false, null, false, DISBURSEMENT_DATE,
                 submittedOnDate, CUMULATIVE, 
LoanScheduleProcessingType.HORIZONTAL, null, false, null, null, false, null, 
false, null, null,
-                null, false, null, null, null, false);
+                null, false, null, null, null, false, false);
 
         // when
         List<? extends LoanScheduleModelPeriod> result = 
underTest.generateRepaymentPeriods(mathContext, expectedDisbursementDate,
@@ -172,7 +172,7 @@ public class DefaultScheduledDateGeneratorTest {
                 EMPTY_LIST, BigDecimal.valueOf(36_000L), null, 
DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null,
                 null, ZERO, null, NONE, null, ZERO, EMPTY_LIST, true, 0, 
false, holidayDetailDTO, false, false, false, null, false, false,
                 null, false, DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, 
LoanScheduleProcessingType.HORIZONTAL, null, false, null, null,
-                false, null, false, null, null, null, false, null, null, null, 
false);
+                false, null, false, null, null, null, false, null, null, null, 
false, false);
     }
 
     private HolidayDetailDTO createHolidayDTO() {
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java
index 6d683485b8..291fb332e0 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java
@@ -880,4 +880,258 @@ public class LoanDisbursementDetailsIntegrationTest {
         assertEquals(false, loanDetails.getAllowFullTermForTranche());
         log.info("-------------------LOAN LEVEL OVERRIDE OF 
allowFullTermForTranche WORKED SUCCESSFULLY-------");
     }
+
+    @Test
+    public void testFullTermTranche_S1_DisbursementOnInstallmentDate() {
+        AdvancedPaymentData defaultAllocation = 
createDefaultPaymentAllocation("NEXT_INSTALLMENT");
+
+        final String loanProductJSON = new 
LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments()
+                .withInterestTypeAsDecliningBalance().withMoratorium("", 
"").withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
+                
.withinterestRatePerPeriod("9.4822").withInterestRateFrequencyTypeAsYear().withMultiDisburse()
+                
.withLoanScheduleType(LoanScheduleType.PROGRESSIVE).addAdvancedPaymentAllocation(defaultAllocation)
+                
.withAllowFullTermForTranche(true).withDaysInYear("360").withMinPrincipal("100").build(null);
+
+        final Integer loanProductId = 
this.loanTransactionHelper.getLoanProductId(loanProductJSON);
+        log.info("------------------LOAN PRODUCT CREATED WITH ID----------- 
{}", loanProductId);
+
+        final Integer clientId = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, "01 January 2024");
+        log.info("------------------CLIENT CREATED WITH ID----------- {}", 
clientId);
+
+        List<HashMap> createTranches = new ArrayList<>();
+        
createTranches.add(this.loanTransactionHelper.createTrancheDetail(null, "01 
January 2024", "100"));
+        
createTranches.add(this.loanTransactionHelper.createTrancheDetail(null, "01 
February 2024", "100"));
+
+        final String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("200").withLoanTermFrequency("6")
+                
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("6").withRepaymentEveryAfter("1")
+                
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("9.4822").withExpectedDisbursementDate("01
 January 2024")
+                .withTranches(createTranches).withSubmittedOnDate("01 January 
2024")
+                
.withRepaymentStrategy(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
+                .build(clientId.toString(), loanProductId.toString(), null);
+
+        final Integer loanId = 
this.loanTransactionHelper.getLoanId(loanApplicationJSON);
+        log.info("------------------LOAN CREATED WITH ID----------- {}", 
loanId);
+
+        this.loanTransactionHelper.approveLoanWithApproveAmount("01 January 
2024", "01 January 2024", "200", loanId, createTranches);
+        log.info("-------------------LOAN APPROVED-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 
2024", loanId, "100");
+        log.info("-------------------FIRST TRANCHE DISBURSED-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount("01 February 
2024", loanId, "100");
+        log.info("-------------------SECOND TRANCHE DISBURSED-------");
+
+        GetLoansLoanIdResponse loanDetails = 
this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        assertNotNull(loanDetails);
+
+        GetLoansLoanIdRepaymentSchedule schedule = 
loanDetails.getRepaymentSchedule();
+        assertNotNull(schedule);
+
+        List<GetLoansLoanIdRepaymentPeriod> periods = schedule.getPeriods();
+        assertNotNull(periods);
+        assertEquals(9, periods.size(), "Total periods should be 9 (2 
disbursements + 7 repayment periods)");
+
+        // Count disbursement periods (no period number) and repayment periods 
(with period number)
+        long disbursementPeriods = periods.stream().filter(p -> p.getPeriod() 
== null).count();
+        long repaymentPeriods = periods.stream().filter(p -> p.getPeriod() != 
null).count();
+        assertEquals(2, disbursementPeriods, "Should have 2 disbursement 
periods");
+        assertEquals(7, repaymentPeriods, "Should have 7 repayment periods");
+
+        log.info("-------------------S1 TEST: SCHEDULE VALIDATION-------");
+        log.info("Schedule structure validated: 2 disbursement + 7 repayment 
periods");
+
+        // Close the loan to allow LoanTestLifecycleExtension cleanup to 
succeed
+        closeFullTermTrancheLoan(loanId, "01 August 2024");
+    }
+
+    @Test
+    public void testFullTermTranche_S2_MidPeriodDisbursement() {
+        AdvancedPaymentData defaultAllocation = 
createDefaultPaymentAllocation("NEXT_INSTALLMENT");
+
+        final String loanProductJSON = new 
LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments()
+                .withInterestTypeAsDecliningBalance().withMoratorium("", 
"").withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
+                
.withinterestRatePerPeriod("9.4822").withInterestRateFrequencyTypeAsYear().withMultiDisburse()
+                
.withLoanScheduleType(LoanScheduleType.PROGRESSIVE).addAdvancedPaymentAllocation(defaultAllocation)
+                
.withAllowFullTermForTranche(true).withDaysInYear("360").withMinPrincipal("100").build(null);
+
+        final Integer loanProductId = 
this.loanTransactionHelper.getLoanProductId(loanProductJSON);
+        log.info("------------------LOAN PRODUCT CREATED WITH ID----------- 
{}", loanProductId);
+
+        final Integer clientId = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, "01 January 2024");
+        log.info("------------------CLIENT CREATED WITH ID----------- {}", 
clientId);
+
+        List<HashMap> createTranches = new ArrayList<>();
+        
createTranches.add(this.loanTransactionHelper.createTrancheDetail(null, "01 
January 2024", "100"));
+        
createTranches.add(this.loanTransactionHelper.createTrancheDetail(null, "15 
February 2024", "100"));
+
+        final String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("200").withLoanTermFrequency("6")
+                
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("6").withRepaymentEveryAfter("1")
+                
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("9.4822").withExpectedDisbursementDate("01
 January 2024")
+                .withTranches(createTranches).withSubmittedOnDate("01 January 
2024")
+                
.withRepaymentStrategy(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
+                .build(clientId.toString(), loanProductId.toString(), null);
+
+        final Integer loanId = 
this.loanTransactionHelper.getLoanId(loanApplicationJSON);
+        log.info("------------------LOAN CREATED WITH ID----------- {}", 
loanId);
+
+        this.loanTransactionHelper.approveLoanWithApproveAmount("01 January 
2024", "01 January 2024", "200", loanId, createTranches);
+        log.info("-------------------LOAN APPROVED-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 
2024", loanId, "100");
+        log.info("-------------------FIRST TRANCHE DISBURSED-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount("15 February 
2024", loanId, "100");
+        log.info("-------------------SECOND TRANCHE DISBURSED 
(MID-PERIOD)-------");
+
+        GetLoansLoanIdResponse loanDetails = 
this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        assertNotNull(loanDetails);
+
+        GetLoansLoanIdRepaymentSchedule schedule = 
loanDetails.getRepaymentSchedule();
+        assertNotNull(schedule);
+
+        List<GetLoansLoanIdRepaymentPeriod> periods = schedule.getPeriods();
+        assertNotNull(periods);
+        assertEquals(9, periods.size(), "Total periods should be 9 (2 
disbursements + 7 repayment periods)");
+
+        // Count disbursement periods (no period number) and repayment periods 
(with period number)
+        long disbursementPeriods = periods.stream().filter(p -> p.getPeriod() 
== null).count();
+        long repaymentPeriods = periods.stream().filter(p -> p.getPeriod() != 
null).count();
+        assertEquals(2, disbursementPeriods, "Should have 2 disbursement 
periods");
+        assertEquals(7, repaymentPeriods, "Should have 7 repayment periods");
+
+        log.info("-------------------S2 TEST: SCHEDULE VALIDATION-------");
+        log.info("Schedule structure validated: 2 disbursement + 7 repayment 
periods (mid-period disbursement)");
+
+        // Close the loan to allow LoanTestLifecycleExtension cleanup to 
succeed
+        closeFullTermTrancheLoan(loanId, "01 August 2024");
+    }
+
+    @Test
+    public void testFullTermTranche_S3_BothBeforeFirstRepayment() {
+        AdvancedPaymentData defaultAllocation = 
createDefaultPaymentAllocation("NEXT_INSTALLMENT");
+
+        final String loanProductJSON = new 
LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments()
+                .withInterestTypeAsDecliningBalance().withMoratorium("", 
"").withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
+                
.withinterestRatePerPeriod("9.4822").withInterestRateFrequencyTypeAsYear().withMultiDisburse()
+                
.withLoanScheduleType(LoanScheduleType.PROGRESSIVE).addAdvancedPaymentAllocation(defaultAllocation)
+                
.withAllowFullTermForTranche(true).withDaysInYear("360").withMinPrincipal("100").build(null);
+
+        final Integer loanProductId = 
this.loanTransactionHelper.getLoanProductId(loanProductJSON);
+        log.info("------------------LOAN PRODUCT CREATED WITH ID----------- 
{}", loanProductId);
+
+        final Integer clientId = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, "01 January 2024");
+        log.info("------------------CLIENT CREATED WITH ID----------- {}", 
clientId);
+
+        List<HashMap> createTranches = new ArrayList<>();
+        
createTranches.add(this.loanTransactionHelper.createTrancheDetail(null, "01 
January 2024", "100"));
+        
createTranches.add(this.loanTransactionHelper.createTrancheDetail(null, "15 
January 2024", "100"));
+
+        final String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("200").withLoanTermFrequency("6")
+                
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("6").withRepaymentEveryAfter("1")
+                
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("9.4822").withExpectedDisbursementDate("01
 January 2024")
+                .withTranches(createTranches).withSubmittedOnDate("01 January 
2024")
+                
.withRepaymentStrategy(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
+                .build(clientId.toString(), loanProductId.toString(), null);
+
+        final Integer loanId = 
this.loanTransactionHelper.getLoanId(loanApplicationJSON);
+        log.info("------------------LOAN CREATED WITH ID----------- {}", 
loanId);
+
+        this.loanTransactionHelper.approveLoanWithApproveAmount("01 January 
2024", "01 January 2024", "200", loanId, createTranches);
+        log.info("-------------------LOAN APPROVED-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 
2024", loanId, "100");
+        log.info("-------------------FIRST TRANCHE DISBURSED-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount("15 January 
2024", loanId, "100");
+        log.info("-------------------SECOND TRANCHE DISBURSED (BEFORE FIRST 
REPAYMENT)-------");
+
+        GetLoansLoanIdResponse loanDetails = 
this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        assertNotNull(loanDetails);
+
+        GetLoansLoanIdRepaymentSchedule schedule = 
loanDetails.getRepaymentSchedule();
+        assertNotNull(schedule);
+
+        List<GetLoansLoanIdRepaymentPeriod> periods = schedule.getPeriods();
+        assertNotNull(periods);
+        assertEquals(8, periods.size(), "Total periods should be 8 (2 
disbursements + 6 repayment periods - NO EXTENSION)");
+
+        // Count disbursement periods (no period number) and repayment periods 
(with period number)
+        long disbursementPeriods = periods.stream().filter(p -> p.getPeriod() 
== null).count();
+        long repaymentPeriods = periods.stream().filter(p -> p.getPeriod() != 
null).count();
+        assertEquals(2, disbursementPeriods, "Should have 2 disbursement 
periods");
+        assertEquals(6, repaymentPeriods, "Should have 6 repayment periods (no 
term extension)");
+
+        log.info("-------------------S3 TEST: SCHEDULE VALIDATION-------");
+        log.info("Schedule structure validated: 2 disbursement + 6 repayment 
periods (no term extension)");
+        log.info("Both disbursements before first repayment date result in 
same maturity date");
+
+        // Close the loan to allow LoanTestLifecycleExtension cleanup to 
succeed
+        closeFullTermTrancheLoan(loanId, "01 July 2024");
+    }
+
+    @Test
+    public void testFullTermTrancheBackwardCompatibility() {
+        AdvancedPaymentData defaultAllocation = 
createDefaultPaymentAllocation("NEXT_INSTALLMENT");
+
+        final String loanProductWithoutFlag = new 
LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments()
+                .withInterestTypeAsDecliningBalance().withMoratorium("", 
"").withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
+                
.withinterestRatePerPeriod("9.4822").withInterestRateFrequencyTypeAsYear().withMultiDisburse()
+                
.withLoanScheduleType(LoanScheduleType.PROGRESSIVE).addAdvancedPaymentAllocation(defaultAllocation)
+                
.withAllowFullTermForTranche(false).withDaysInYear("360").withMinPrincipal("100").build(null);
+
+        final Integer loanProductId = 
this.loanTransactionHelper.getLoanProductId(loanProductWithoutFlag);
+        log.info("------------------LOAN PRODUCT CREATED WITH 
allowFullTermForTranche=false ID----------- {}", loanProductId);
+
+        final Integer clientId = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, "01 January 2024");
+        log.info("------------------CLIENT CREATED WITH ID----------- {}", 
clientId);
+
+        List<HashMap> createTranches = new ArrayList<>();
+        
createTranches.add(this.loanTransactionHelper.createTrancheDetail(null, "01 
January 2024", "100"));
+        
createTranches.add(this.loanTransactionHelper.createTrancheDetail(null, "01 
February 2024", "100"));
+
+        final String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("200").withLoanTermFrequency("6")
+                
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("6").withRepaymentEveryAfter("1")
+                
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("9.4822").withExpectedDisbursementDate("01
 January 2024")
+                .withTranches(createTranches).withSubmittedOnDate("01 January 
2024")
+                
.withRepaymentStrategy(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
+                .build(clientId.toString(), loanProductId.toString(), null);
+
+        final Integer loanId = 
this.loanTransactionHelper.getLoanId(loanApplicationJSON);
+        log.info("------------------LOAN CREATED WITH ID----------- {}", 
loanId);
+
+        this.loanTransactionHelper.approveLoanWithApproveAmount("01 January 
2024", "01 January 2024", "200", loanId, createTranches);
+        log.info("-------------------LOAN APPROVED-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 
2024", loanId, "100");
+        log.info("-------------------FIRST TRANCHE DISBURSED-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount("01 February 
2024", loanId, "100");
+        log.info("-------------------SECOND TRANCHE DISBURSED-------");
+
+        GetLoansLoanIdResponse loanDetails = 
this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        assertNotNull(loanDetails);
+
+        GetLoansLoanIdRepaymentSchedule schedule = 
loanDetails.getRepaymentSchedule();
+        assertNotNull(schedule);
+
+        List<GetLoansLoanIdRepaymentPeriod> periods = schedule.getPeriods();
+        assertNotNull(periods);
+
+        log.info("-------------------BACKWARD COMPATIBILITY TEST: SCHEDULE 
VALIDATION-------");
+        log.info("Expected: OLD behavior when allowFullTermForTranche=false");
+        log.info("Schedule should NOT use full term tranche logic - should 
match existing multi-disburse behavior");
+    }
+
+    /**
+     * Helper method to close a loan by making a full prepayment. This ensures 
the loan is closed before the
+     * LoanTestLifecycleExtension cleanup runs.
+     */
+    private void closeFullTermTrancheLoan(Integer loanId, String 
lastRepaymentDate) {
+        GetLoansLoanIdResponse loanDetails = 
this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        BigDecimal outstandingAmount = 
loanDetails.getSummary().getTotalOutstanding();
+
+        if (outstandingAmount != null && 
outstandingAmount.compareTo(BigDecimal.ZERO) > 0) {
+            log.info("-------------------CLOSING LOAN {} WITH PREPAYMENT OF {} 
ON {}-------", loanId, outstandingAmount, lastRepaymentDate);
+            this.loanTransactionHelper.makeLoanRepayment(lastRepaymentDate, 
outstandingAmount.floatValue(), loanId);
+        }
+    }
 }

Reply via email to