Merge pull request #5824

FINERACT-2421: reschedule after reage schedule and balance fix
diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature
index 98a914f..3cf3825 100644
--- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature
+++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature
@@ -1771,4 +1771,226 @@
       | From Date        | Reason | Status   |
       | 01 February 2025 | None   | Approved |
       | 01 February 2025 | None   | Approved |
-      | 01 February 2025 | None   | Approved |
\ No newline at end of file
+      | 01 February 2025 | None   | Approved |
+
+  @TestRailId:C78849
+  Scenario: Verify that reschedule after ReAge produces correct schedule and balance for downpayment product
+    When Admin sets the business date to "21 January 2026"
+    When Admin creates a client with random data
+    When Admin set "LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
+    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_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION | 21 January 2026   | 480            | 0                      | FLAT          | SAME_AS_REPAYMENT_PERIOD    | EQUAL_INSTALLMENTS | 3                 | MONTHS                | 1              | MONTHS                 | 3                  | 0                       | 0                      | 0                    | ADVANCED_PAYMENT_ALLOCATION |
+    And Admin successfully approves the loan on "21 January 2026" with "480" amount and expected disbursement date on "21 January 2026"
+    When Admin successfully disburse the loan on "21 January 2026" with "480" EUR transaction amount
+    Then Loan has 360.0 outstanding amount
+    Then Loan Repayment schedule has 4 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 |
+      |    |      | 21 January 2026  |                 | 480.0           |               |          | 0.0  |           | 0.0   | 0.0   |            |      |             |
+      | 1  | 0    | 21 January 2026  | 21 January 2026 | 360.0           | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 120.0 | 0.0        | 0.0  | 0.0         |
+      | 2  | 31   | 21 February 2026 |                 | 240.0           | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 0.0   | 0.0        | 0.0  | 120.0       |
+      | 3  | 28   | 21 March 2026    |                 | 120.0           | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 0.0   | 0.0        | 0.0  | 120.0       |
+      | 4  | 31   | 21 April 2026    |                 | 0.0             | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 0.0   | 0.0        | 0.0  | 120.0       |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late | Outstanding |
+      | 480.0         | 0.0      | 0.0  | 0.0       | 480.0 | 120.0 | 0.0        | 0.0  | 360.0       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
+      | 21 January 2026  | Disbursement     | 480.0  | 0.0       | 0.0      | 0.0  | 0.0       | 480.0        | false    |
+      | 21 January 2026  | Down Payment     | 120.0  | 120.0     | 0.0      | 0.0  | 0.0       | 360.0        | false    |
+    # --- Step 1: Reschedule (1 month payment holiday: push 21 Feb installment to 21 Mar) ---
+    When Admin sets the business date to "23 January 2026"
+    When Admin creates and approves Loan reschedule with the following data:
+      | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate |
+      | 21 February 2026   | 23 January 2026 | 21 March 2026   |                  |                 |            |                 |
+    Then Loan has 360.0 outstanding amount
+    And Loan Repayment schedule has 4 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 |
+      |    |      | 21 January 2026 |                 | 480.0           |               |          | 0.0  |           | 0.0   | 0.0   |            |      |             |
+      | 1  | 0    | 21 January 2026 | 21 January 2026 | 360.0           | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 120.0 | 0.0        | 0.0  | 0.0         |
+      | 2  | 59   | 21 March 2026   |                 | 240.0           | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 0.0   | 0.0        | 0.0  | 120.0       |
+      | 3  | 31   | 21 April 2026   |                 | 120.0           | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 0.0   | 0.0        | 0.0  | 120.0       |
+      | 4  | 30   | 21 May 2026     |                 | 0.0             | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 0.0   | 0.0        | 0.0  | 120.0       |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late | Outstanding |
+      | 480.0         | 0.0      | 0.0  | 0.0       | 480.0 | 120.0 | 0.0        | 0.0  | 360.0       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
+      | 21 January 2026  | Disbursement     | 480.0  | 0.0       | 0.0      | 0.0  | 0.0       | 480.0        | false    |
+      | 21 January 2026  | Down Payment     | 120.0  | 120.0     | 0.0      | 0.0  | 0.0       | 360.0        | false    |
+    # --- Step 2: ReAge for 15 monthly installments starting 21 March 2026 ---
+    When Admin creates a Loan re-aging transaction with the following data:
+      | frequencyNumber | frequencyType | startDate     | numberOfInstallments | reAgeInterestHandling |
+      | 1               | MONTHS        | 21 March 2026 | 15                   | DEFAULT               |
+    Then Loan has 360.0 outstanding amount
+    And Loan Repayment schedule has 17 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 |
+      |    |      | 21 January 2026   |                 | 480.0           |               |          | 0.0  |           | 0.0   | 0.0   |            |      |             |
+      | 1  | 0    | 21 January 2026   | 21 January 2026 | 360.0           | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 120.0 | 0.0        | 0.0  | 0.0         |
+      | 2  | 2    | 23 January 2026   | 23 January 2026 | 360.0           | 0.0           | 0.0      | 0.0  | 0.0       | 0.0   | 0.0   | 0.0        | 0.0  | 0.0         |
+      | 3  | 57   | 21 March 2026     |                 | 336.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 4  | 31   | 21 April 2026     |                 | 312.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 5  | 30   | 21 May 2026       |                 | 288.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 6  | 31   | 21 June 2026      |                 | 264.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 7  | 30   | 21 July 2026      |                 | 240.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 8  | 31   | 21 August 2026    |                 | 216.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 9  | 31   | 21 September 2026 |                 | 192.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 10 | 30   | 21 October 2026   |                 | 168.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 11 | 31   | 21 November 2026  |                 | 144.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 12 | 30   | 21 December 2026  |                 | 120.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 13 | 31   | 21 January 2027   |                 | 96.0            | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 14 | 31   | 21 February 2027  |                 | 72.0            | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 15 | 28   | 21 March 2027     |                 | 48.0            | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 16 | 31   | 21 April 2027     |                 | 24.0            | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 17 | 30   | 21 May 2027       |                 | 0.0             | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late | Outstanding |
+      | 480.0         | 0.0      | 0.0  | 0.0       | 480.0 | 120.0 | 0.0        | 0.0  | 360.0       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
+      | 21 January 2026  | Disbursement     | 480.0  | 0.0       | 0.0      | 0.0  | 0.0       | 480.0        | false    |
+      | 21 January 2026  | Down Payment     | 120.0  | 120.0     | 0.0      | 0.0  | 0.0       | 360.0        | false    |
+      | 23 January 2026  | Re-age           | 360.0  | 360.0     | 0.0      | 0.0  | 0.0       | 0.0          | false    |
+    # --- Step 3: BUG TRIGGER: Reschedule again (push schedule 2 more months) ---
+    When Admin sets the business date to "28 January 2026"
+    When Admin creates and approves Loan reschedule with the following data:
+      | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate |
+      | 21 March 2026      | 28 January 2026 | 21 May 2026     |                  |                 |            |                 |
+    # After reschedule 2 the 15 ReAge installments must cascade by 2 months: first reAge installment
+    # moves from 21 March 2026 to 21 May 2026 and the last one moves from 21 May 2027 to 21 July 2027.
+    # The bug : the second reschedule silently leaves the schedule unchanged - i.e. 21 July 2027
+    # does not exist in the schedule.
+    Then Loan has 360.0 outstanding amount
+    Then Loan Repayment schedule has 17 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 |
+      |    |      | 21 January 2026   |                 | 480.0           |               |          | 0.0  |           | 0.0   | 0.0   |            |      |             |
+      | 1  | 0    | 21 January 2026   | 21 January 2026 | 360.0           | 120.0         | 0.0      | 0.0  | 0.0       | 120.0 | 120.0 | 0.0        | 0.0  | 0.0         |
+      | 2  | 2    | 23 January 2026   | 23 January 2026 | 360.0           | 0.0           | 0.0      | 0.0  | 0.0       | 0.0   | 0.0   | 0.0        | 0.0  | 0.0         |
+      | 3  | 118  | 21 May 2026       |                 | 336.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 4  | 31   | 21 June 2026      |                 | 312.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 5  | 30   | 21 July 2026      |                 | 288.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 6  | 31   | 21 August 2026    |                 | 264.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 7  | 31   | 21 September 2026 |                 | 240.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 8  | 30   | 21 October 2026   |                 | 216.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 9  | 31   | 21 November 2026  |                 | 192.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 10 | 30   | 21 December 2026  |                 | 168.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 11 | 31   | 21 January 2027   |                 | 144.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 12 | 31   | 21 February 2027  |                 | 120.0           | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 13 | 28   | 21 March 2027     |                 | 96.0            | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 14 | 31   | 21 April 2027     |                 | 72.0            | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 15 | 30   | 21 May 2027       |                 | 48.0            | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 16 | 31   | 21 June 2027      |                 | 24.0            | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+      | 17 | 30   | 21 July 2027      |                 | 0.0             | 24.0          | 0.0      | 0.0  | 0.0       | 24.0  | 0.0   | 0.0        | 0.0  | 24.0        |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late | Outstanding |
+      | 480.0         | 0.0      | 0.0  | 0.0       | 480.0 | 120.0 | 0.0        | 0.0  | 360.0       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
+      | 21 January 2026  | Disbursement     | 480.0  | 0.0       | 0.0      | 0.0  | 0.0       | 480.0        | false    |
+      | 21 January 2026  | Down Payment     | 120.0  | 120.0     | 0.0      | 0.0  | 0.0       | 360.0        | false    |
+      | 23 January 2026  | Re-age           | 360.0  | 360.0     | 0.0      | 0.0  | 0.0       | 0.0          | false    |
+
+  @TestRailId:C78850
+  Scenario: Verify that reschedule after ReAge produces correct schedule and balance for non-interest bearing single-installment product
+    When Admin sets the business date to "21 January 2026"
+    When Admin creates a client with random data
+    When Admin set "LP1_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
+    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            |
+      | LP1_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 21 January 2026   | 150            | 0                      | FLAT          | SAME_AS_REPAYMENT_PERIOD    | EQUAL_INSTALLMENTS | 30                | DAYS                  | 30             | DAYS                   | 1                  | 0                       | 0                      | 0                    | ADVANCED_PAYMENT_ALLOCATION |
+    And Admin successfully approves the loan on "21 January 2026" with "150" amount and expected disbursement date on "21 January 2026"
+    When Admin successfully disburse the loan on "21 January 2026" with "150" EUR transaction amount
+    Then Loan has 150.0 outstanding amount
+    Then Loan Repayment schedule has 1 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 |
+      |    |      | 21 January 2026  |           | 150.0           |               |          | 0.0  |           | 0.0   | 0.0  |            |      |             |
+      | 1  | 30   | 20 February 2026 |           | 0.0             | 150.0         | 0.0      | 0.0  | 0.0       | 150.0 | 0.0  | 0.0        | 0.0  | 150.0       |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid | In advance | Late | Outstanding |
+      | 150.0         | 0.0      | 0.0  | 0.0       | 150.0 | 0.0  | 0.0        | 0.0  | 150.0       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
+      | 21 January 2026  | Disbursement     | 150.0  | 0.0       | 0.0      | 0.0  | 0.0       | 150.0        | false    |
+    # --- Step 1: Reschedule (push 20 Feb installment to 22 Mar) ---
+    When Admin sets the business date to "23 January 2026"
+    When Admin creates and approves Loan reschedule with the following data:
+      | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate |
+      | 20 February 2026   | 23 January 2026 | 22 March 2026   |                  |                 |            |                 |
+    Then Loan has 150.0 outstanding amount
+    And Loan Repayment schedule has 1 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 |
+      |    |      | 21 January 2026 |           | 150.0           |               |          | 0.0  |           | 0.0   | 0.0  |            |      |             |
+      | 1  | 60   | 22 March 2026   |           | 0.0             | 150.0         | 0.0      | 0.0  | 0.0       | 150.0 | 0.0  | 0.0        | 0.0  | 150.0       |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid | In advance | Late | Outstanding |
+      | 150.0         | 0.0      | 0.0  | 0.0       | 150.0 | 0.0  | 0.0        | 0.0  | 150.0       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
+      | 21 January 2026  | Disbursement     | 150.0  | 0.0       | 0.0      | 0.0  | 0.0       | 150.0        | false    |
+    # --- Step 2: ReAge for 15 monthly installments starting 22 March 2026 ---
+    When Admin creates a Loan re-aging transaction with the following data:
+      | frequencyNumber | frequencyType | startDate     | numberOfInstallments | reAgeInterestHandling |
+      | 1               | MONTHS        | 22 March 2026 | 15                   | DEFAULT               |
+    Then Loan has 150.0 outstanding amount
+    And Loan Repayment schedule has 16 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 |
+      |    |      | 21 January 2026   |                 | 150.0           |               |          | 0.0  |           | 0.0  | 0.0  |            |      |             |
+      | 1  | 2    | 23 January 2026   | 23 January 2026 | 150.0           | 0.0           | 0.0      | 0.0  | 0.0       | 0.0  | 0.0  | 0.0        | 0.0  | 0.0         |
+      | 2  | 58   | 22 March 2026     |                 | 140.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 3  | 31   | 22 April 2026     |                 | 130.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 4  | 30   | 22 May 2026       |                 | 120.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 5  | 31   | 22 June 2026      |                 | 110.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 6  | 30   | 22 July 2026      |                 | 100.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 7  | 31   | 22 August 2026    |                 | 90.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 8  | 31   | 22 September 2026 |                 | 80.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 9  | 30   | 22 October 2026   |                 | 70.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 10 | 31   | 22 November 2026  |                 | 60.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 11 | 30   | 22 December 2026  |                 | 50.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 12 | 31   | 22 January 2027   |                 | 40.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 13 | 31   | 22 February 2027  |                 | 30.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 14 | 28   | 22 March 2027     |                 | 20.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 15 | 31   | 22 April 2027     |                 | 10.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 16 | 30   | 22 May 2027       |                 | 0.0             | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid | In advance | Late | Outstanding |
+      | 150.0         | 0.0      | 0.0  | 0.0       | 150.0 | 0.0  | 0.0        | 0.0  | 150.0       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
+      | 21 January 2026  | Disbursement     | 150.0  | 0.0       | 0.0      | 0.0  | 0.0       | 150.0        | false    |
+      | 23 January 2026  | Re-age           | 150.0  | 150.0     | 0.0      | 0.0  | 0.0       | 0.0          | false    |
+    # --- Step 3: BUG TRIGGER: Reschedule again (push schedule 2 more months: 22 Mar -> 22 May) ---
+    When Admin sets the business date to "28 January 2026"
+    When Admin creates and approves Loan reschedule with the following data:
+      | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate |
+      | 22 March 2026      | 28 January 2026 | 22 May 2026     |                  |                 |            |                 |
+    # After reschedule 2 the 15 ReAge installments must each shift by +61 days (22 Mar 2026 -> 22 May 2026).
+    # Note: fixed-day offset means the 22nd-of-month alignment drifts in months with different lengths.
+    # Bug today: schedule unchanged - 22 July 2027 is missing because the second reschedule did not shift
+    # the schedule, identical defect to scenario C78849
+    Then Loan has 150.0 outstanding amount
+    Then Loan Repayment schedule has 16 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 |
+      |    |      | 21 January 2026   |                 | 150.0           |               |          | 0.0  |           | 0.0  | 0.0  |            |      |             |
+      | 1  | 2    | 23 January 2026   | 23 January 2026 | 150.0           | 0.0           | 0.0      | 0.0  | 0.0       | 0.0  | 0.0  | 0.0        | 0.0  | 0.0         |
+      | 2  | 119  | 22 May 2026       |                 | 140.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 3  | 31   | 22 June 2026      |                 | 130.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 4  | 30   | 22 July 2026      |                 | 120.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 5  | 31   | 22 August 2026    |                 | 110.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 6  | 30   | 21 September 2026 |                 | 100.0           | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 7  | 31   | 22 October 2026   |                 | 90.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 8  | 31   | 22 November 2026  |                 | 80.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 9  | 30   | 22 December 2026  |                 | 70.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 10 | 31   | 22 January 2027   |                 | 60.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 11 | 30   | 21 February 2027  |                 | 50.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 12 | 31   | 24 March 2027     |                 | 40.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 13 | 31   | 24 April 2027     |                 | 30.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 14 | 28   | 22 May 2027       |                 | 20.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 15 | 31   | 22 June 2027      |                 | 10.0            | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+      | 16 | 30   | 22 July 2027      |                 | 0.0             | 10.0          | 0.0      | 0.0  | 0.0       | 10.0 | 0.0  | 0.0        | 0.0  | 10.0        |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid | In advance | Late | Outstanding |
+      | 150.0         | 0.0      | 0.0  | 0.0       | 150.0 | 0.0  | 0.0        | 0.0  | 150.0       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
+      | 21 January 2026  | Disbursement     | 150.0  | 0.0       | 0.0      | 0.0  | 0.0       | 150.0        | false    |
+      | 23 January 2026  | Re-age           | 150.0  | 150.0     | 0.0      | 0.0  | 0.0       | 0.0          | false    |
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 cd47b80..417c76a 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
@@ -321,27 +321,49 @@
             case INTEREST_RATE_FROM_INSTALLMENT -> handleChangeInterestRate(installments, termVariationsData, scheduleModel);
             case EXTEND_REPAYMENT_PERIOD ->
                 handleExtraRepaymentPeriod(installments, termVariationsData, scheduleModel, ctx.getAlreadyProcessedTransactions());
-            case DUE_DATE -> handleDueDateChangeOnRepaymentPeriod(installments, termVariationsData, scheduleModel);
+            case DUE_DATE -> handleDueDateChangeOnRepaymentPeriod(installments, termVariationsData, scheduleModel,
+                    ctx.getAlreadyProcessedTransactions());
             default -> throw new IllegalStateException("Unhandled LoanTermVariationType.");
         }
     }
 
     private void handleDueDateChangeOnRepaymentPeriod(final List<LoanRepaymentScheduleInstallment> installments,
-            final LoanTermVariationsData termVariationsData, final ProgressiveLoanInterestScheduleModel scheduleModel) {
+            final LoanTermVariationsData termVariationsData, final ProgressiveLoanInterestScheduleModel scheduleModel,
+            final List<LoanTransaction> alreadyProcessedTransactions) {
         final LocalDate targetRepaymentPeriodDueDate = termVariationsData.getTermVariationApplicableFrom();
         final LocalDate newDueDate = termVariationsData.getDateValue();
         final Loan loan = installments.getFirst().getLoan();
-        final LoanApplicationTerms loanApplicationTerms = new LoanApplicationTerms.Builder() //
-                .currency(loan.getCurrency().toData()) //
-                .repaymentEvery(loan.getLoanProductRelatedDetail().getRepayEvery()) //
-                .repaymentPeriodFrequencyType(loan.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType()) //
-                .fixedLength(loan.getLoanProductRelatedDetail().getFixedLength()) //
-                .seedDate(newDueDate) //
-                .build();
-        emiCalculator.changeDueDate(scheduleModel, loanApplicationTerms, targetRepaymentPeriodDueDate, newDueDate);
+
+        // Check if the target due date exists in the scheduleModel.
+        final boolean targetExistsInScheduleModel = scheduleModel.repaymentPeriods().stream()
+                .anyMatch(rp -> rp.getDueDate().equals(targetRepaymentPeriodDueDate));
+
+        // Determine if the target installment is re-aged. After a ReAge, base installments were zeroed
+        // by liftOutstandingBalances and re-aged installments carry the redistributed principal.
+        // A due-date variation that targets a non-re-aged base installment AFTER a ReAge was processed
+        // is stale — applying the scheduleModel's principal/interest would restore zeroed amounts.
+        final Optional<LoanRepaymentScheduleInstallment> targetInstallment = installments.stream()
+                .filter(inst -> inst.getDueDate().equals(targetRepaymentPeriodDueDate)).findFirst();
+        final boolean targetIsReAged = targetInstallment.map(LoanRepaymentScheduleInstallment::isReAged).orElse(false);
+        final boolean reAgeAlreadyProcessed = alreadyProcessedTransactions.stream().anyMatch(t -> t.isReAge() && t.isNotReversed());
+        final boolean isStalePreReAgeVariation = !targetIsReAged && reAgeAlreadyProcessed;
+
+        if (targetExistsInScheduleModel && !isStalePreReAgeVariation) {
+            final LoanApplicationTerms loanApplicationTerms = new LoanApplicationTerms.Builder() //
+                    .currency(loan.getCurrency().toData()) //
+                    .repaymentEvery(loan.getLoanProductRelatedDetail().getRepayEvery()) //
+                    .repaymentPeriodFrequencyType(loan.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType()) //
+                    .fixedLength(loan.getLoanProductRelatedDetail().getFixedLength()) //
+                    .seedDate(newDueDate) //
+                    .build();
+            emiCalculator.changeDueDate(scheduleModel, loanApplicationTerms, targetRepaymentPeriodDueDate, newDueDate);
+        }
+
+        final boolean dateShiftOnly = isStalePreReAgeVariation || !targetExistsInScheduleModel;
 
         IntStream.range(0, installments.size()).filter(i -> installments.get(i).getDueDate().equals(targetRepaymentPeriodDueDate))
                 .findFirst().ifPresent(targetInstallmentIndex -> {
+                    final long dateOffsetDays = ChronoUnit.DAYS.between(targetRepaymentPeriodDueDate, newDueDate);
                     long scheduleModelStartIndex = installments.subList(0, targetInstallmentIndex).stream()
                             .filter(inst -> !inst.isDownPayment() && !inst.isAdditional()).count();
 
@@ -350,8 +372,12 @@
                         if (installment.isDownPayment() || installment.isAdditional()) {
                             continue;
                         }
-                        if (scheduleModelStartIndex >= scheduleModel.repaymentPeriods().size()) {
-                            break;
+                        if (dateShiftOnly || scheduleModelStartIndex >= scheduleModel.repaymentPeriods().size()) {
+                            if (isNotObligationsMet(installment)) {
+                                installment.updateFromDate(installment.getFromDate().plusDays(dateOffsetDays));
+                                installment.updateDueDate(installment.getDueDate().plusDays(dateOffsetDays));
+                            }
+                            continue;
                         }
 
                         final RepaymentPeriod repaymentPeriod = scheduleModel.repaymentPeriods().get((int) scheduleModelStartIndex);
@@ -367,7 +393,15 @@
                     }
                 });
 
-        mergeAdditionalInstallmentsBeforeMaturityDate(installments, scheduleModel, loan);
+        // When the target date was already consumed by generate() and a ReAge was processed,
+        // the re-aged installments still carry their original dates. Shift them to apply the reschedule.
+        if (targetInstallment.isEmpty() && reAgeAlreadyProcessed) {
+            shiftReAgedInstallmentsAfterReschedule(installments, newDueDate, loan);
+        }
+
+        if (!dateShiftOnly) {
+            mergeAdditionalInstallmentsBeforeMaturityDate(installments, scheduleModel, loan);
+        }
 
         installments.sort(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate));
         int installmentNumber = 1;
@@ -376,6 +410,40 @@
         }
     }
 
+    private void shiftReAgedInstallmentsAfterReschedule(final List<LoanRepaymentScheduleInstallment> installments,
+            final LocalDate newDueDate, final Loan loan) {
+        final Optional<LoanRepaymentScheduleInstallment> firstUnmetReAged = installments.stream()
+                .filter(inst -> inst.isReAged() && isNotObligationsMet(inst))
+                .min(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate));
+
+        if (firstUnmetReAged.isEmpty() || !newDueDate.isAfter(firstUnmetReAged.get().getDueDate())) {
+            return;
+        }
+
+        final LocalDate firstReAgedDueDate = firstUnmetReAged.get().getDueDate();
+        final PeriodFrequencyType frequencyType = loan.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType();
+
+        for (final LoanRepaymentScheduleInstallment installment : installments) {
+            if (!installment.isReAged() || !isNotObligationsMet(installment)) {
+                continue;
+            }
+            final LocalDate shiftedDueDate = shiftDateByFrequency(installment.getDueDate(), firstReAgedDueDate, newDueDate, frequencyType);
+            installment.updateDueDate(shiftedDueDate);
+        }
+        reprocessInstallments(installments);
+    }
+
+    private LocalDate shiftDateByFrequency(final LocalDate dateToShift, final LocalDate fromDate, final LocalDate toDate,
+            final PeriodFrequencyType frequencyType) {
+        return switch (frequencyType) {
+            case DAYS -> dateToShift.plusDays(ChronoUnit.DAYS.between(fromDate, toDate));
+            case WEEKS -> dateToShift.plusWeeks(ChronoUnit.WEEKS.between(fromDate, toDate));
+            case MONTHS -> dateToShift.plusMonths(ChronoUnit.MONTHS.between(fromDate, toDate));
+            case YEARS -> dateToShift.plusYears(ChronoUnit.YEARS.between(fromDate, toDate));
+            default -> dateToShift.plusDays(ChronoUnit.DAYS.between(fromDate, toDate));
+        };
+    }
+
     private void mergeAdditionalInstallmentsBeforeMaturityDate(final List<LoanRepaymentScheduleInstallment> installments,
             final ProgressiveLoanInterestScheduleModel scheduleModel, final Loan loan) {
         final LocalDate newMaturityDate = scheduleModel.repaymentPeriods().getLast().getDueDate();
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java
index 48923fc..91f8dc8 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java
@@ -24,10 +24,12 @@
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
 import org.apache.fineract.client.models.GetLoansLoanIdStatus;
 import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTemplateResponse;
+import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
 import org.apache.fineract.client.models.PostLoanProductsRequest;
 import org.apache.fineract.client.models.PostLoansLoanIdRequest;
 import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
 import org.apache.fineract.client.models.PostLoansRequest;
+import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest;
 import org.apache.fineract.integrationtests.client.FeignIntegrationTest;
 import org.apache.fineract.integrationtests.client.feign.helpers.FeignAccountHelper;
 import org.apache.fineract.integrationtests.client.feign.helpers.FeignBusinessDateHelper;
@@ -195,6 +197,20 @@
         return loanId;
     }
 
+    protected Long createApproveAndDisburseProgressiveLoan(Long clientId, Long productId, String date, Double principal,
+            Integer numberOfRepayments) {
+        PostLoansRequest applyRequest = LoanRequestBuilders.applyProgressiveLoan(clientId, productId, date, principal, numberOfRepayments);
+        Long loanId = applyForLoan(applyRequest);
+
+        PostLoansLoanIdRequest approveRequest = LoanRequestBuilders.approveLoan(principal, date);
+        approveLoan(loanId, approveRequest);
+
+        PostLoansLoanIdRequest disburseRequest = LoanRequestBuilders.disburseLoan(principal, date);
+        disburseLoan(loanId, disburseRequest);
+
+        return loanId;
+    }
+
     protected Long createApprovedLoan(Long clientId, Long productId, String date, Double principal, Integer numberOfRepayments) {
         PostLoansRequest applyRequest = LoanRequestBuilders.applyLoan(clientId, productId, date, principal, numberOfRepayments);
         Long loanId = applyForLoan(applyRequest);
@@ -232,4 +248,27 @@
     protected GetLoansLoanIdTransactionsTemplateResponse getPrepaymentAmount(Long loanId, String transactionDate, String dateFormat) {
         return transactionHelper.getPrepaymentAmount(loanId, transactionDate, dateFormat);
     }
+
+    protected Long createRescheduleRequest(PostCreateRescheduleLoansRequest request) {
+        return loanHelper.createRescheduleRequest(request);
+    }
+
+    protected Long approveRescheduleRequest(Long scheduleId, PostUpdateRescheduleLoansRequest request) {
+        return loanHelper.approveRescheduleRequest(scheduleId, request);
+    }
+
+    protected void createAndApproveReschedule(Long loanId, String submittedOnDate, String rescheduleFromDate, String adjustedDueDate) {
+        loanHelper.createAndApproveRescheduleRequest(
+                LoanRequestBuilders.rescheduleRequest(loanId, submittedOnDate, rescheduleFromDate, adjustedDueDate),
+                LoanRequestBuilders.approveReschedule(submittedOnDate));
+    }
+
+    protected Long reAge(Long loanId, PostLoansLoanIdTransactionsRequest request) {
+        return transactionHelper.reAge(loanId, request);
+    }
+
+    protected PostLoansLoanIdTransactionsRequest reAge(String startDate, String frequencyType, Integer frequencyNumber,
+            Integer numberOfInstallments) {
+        return LoanRequestBuilders.reAge(startDate, frequencyType, frequencyNumber, numberOfInstallments);
+    }
 }
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java
index 62da207..15650e1 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java
@@ -27,6 +27,8 @@
 import org.apache.fineract.client.feign.FineractFeignClient;
 import org.apache.fineract.client.feign.util.CallFailedRuntimeException;
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
+import org.apache.fineract.client.models.PostCreateRescheduleLoansResponse;
 import org.apache.fineract.client.models.PostLoanProductsRequest;
 import org.apache.fineract.client.models.PostLoanProductsResponse;
 import org.apache.fineract.client.models.PostLoansLoanIdRequest;
@@ -34,6 +36,8 @@
 import org.apache.fineract.client.models.PostLoansOriginatorData;
 import org.apache.fineract.client.models.PostLoansRequest;
 import org.apache.fineract.client.models.PostLoansResponse;
+import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest;
+import org.apache.fineract.client.models.PostUpdateRescheduleLoansResponse;
 import org.apache.fineract.integrationtests.common.Utils;
 
 public class FeignLoanHelper {
@@ -201,6 +205,23 @@
         return buildSubmittedLoanRequest(clientId, createSimpleLoanProduct());
     }
 
+    public Long createRescheduleRequest(PostCreateRescheduleLoansRequest request) {
+        PostCreateRescheduleLoansResponse response = ok(() -> fineractClient.rescheduleLoans().createLoanRescheduleRequest(request));
+        return response.getResourceId();
+    }
+
+    public Long approveRescheduleRequest(Long scheduleId, PostUpdateRescheduleLoansRequest request) {
+        PostUpdateRescheduleLoansResponse response = ok(
+                () -> fineractClient.rescheduleLoans().updateLoanRescheduleRequest(scheduleId, request, "approve"));
+        return response.getResourceId();
+    }
+
+    public void createAndApproveRescheduleRequest(PostCreateRescheduleLoansRequest createRequest,
+            PostUpdateRescheduleLoansRequest approveRequest) {
+        Long scheduleId = createRescheduleRequest(createRequest);
+        approveRescheduleRequest(scheduleId, approveRequest);
+    }
+
     private PostLoansRequest buildSubmittedLoanRequest(Long clientId, Long productId) {
         String todayDate = org.apache.fineract.integrationtests.common.Utils.dateFormatter
                 .format(org.apache.fineract.integrationtests.common.Utils.getLocalDateOfTenant());
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignTransactionHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignTransactionHelper.java
index 7fbfe4c..b52124c 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignTransactionHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignTransactionHelper.java
@@ -77,6 +77,18 @@
         return response.getResourceId();
     }
 
+    public Long reAge(Long loanId, PostLoansLoanIdTransactionsRequest request) {
+        PostLoansLoanIdTransactionsResponse response = ok(
+                () -> fineractClient.loanTransactions().executeLoanTransaction(loanId, request, Map.of("command", "reAge")));
+        return response.getResourceId();
+    }
+
+    public Long undoReAge(Long loanId, PostLoansLoanIdTransactionsRequest request) {
+        PostLoansLoanIdTransactionsResponse response = ok(
+                () -> fineractClient.loanTransactions().executeLoanTransaction(loanId, request, Map.of("command", "undoReAge")));
+        return response.getResourceId();
+    }
+
     public void undoRepayment(Long loanId, Long transactionId, String transactionDate) {
         PostLoansLoanIdTransactionsTransactionIdRequest request = new PostLoansLoanIdTransactionsTransactionIdRequest();
         request.setTransactionDate(transactionDate);
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanProductTemplates.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanProductTemplates.java
index 41ef8f5..b34ab56 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanProductTemplates.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanProductTemplates.java
@@ -31,6 +31,7 @@
 import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.InterestType;
 import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.RepaymentFrequencyType;
 import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.RescheduleStrategyMethod;
+import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.TransactionProcessingStrategyCode;
 import org.apache.fineract.integrationtests.common.Utils;
 import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
@@ -139,6 +140,17 @@
                 .rescheduleStrategyMethod(RescheduleStrategyMethod.ADJUST_LAST_UNPAID_PERIOD);
     }
 
+    /**
+     * Progressive loan product with advanced-payment-allocation-strategy and default payment allocation. Use this
+     * instead of {@link #fourInstallmentsProgressive()} when the product needs to actually create loans (PROGRESSIVE
+     * schedule type requires advanced-payment-allocation-strategy with explicit payment allocation configuration).
+     */
+    default PostLoanProductsRequest fourInstallmentsProgressiveWithAdvancedAllocation() {
+        return fourInstallmentsProgressive()//
+                .transactionProcessingStrategyCode(TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
+                .paymentAllocation(List.of(LoanRequestBuilders.defaultPaymentAllocation()));
+    }
+
     default PostLoanProductsRequest fourInstallmentsProgressiveWithCapitalizedIncome() {
         return fourInstallmentsProgressive().enableIncomeCapitalization(true)//
                 .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)//
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java
index 683f8a3..926c54b 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java
@@ -19,9 +19,16 @@
 package org.apache.fineract.integrationtests.client.feign.modules;
 
 import java.math.BigDecimal;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import org.apache.fineract.client.models.AdvancedPaymentData;
+import org.apache.fineract.client.models.PaymentAllocationOrder;
+import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
 import org.apache.fineract.client.models.PostLoansLoanIdRequest;
 import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
 import org.apache.fineract.client.models.PostLoansRequest;
+import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest;
 
 public final class LoanRequestBuilders {
 
@@ -75,7 +82,14 @@
 
     public static PostLoansRequest applyProgressiveLoan(Long clientId, Long productId, String submittedOnDate, Double principal,
             Integer numberOfRepayments, Double interestRate) {
-        return applyCumulativeLoan(clientId, productId, submittedOnDate, principal, numberOfRepayments, interestRate);
+        return applyCumulativeLoan(clientId, productId, submittedOnDate, principal, numberOfRepayments, interestRate)
+                .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION_STRATEGY);
+    }
+
+    public static PostLoansRequest applyProgressiveLoan(Long clientId, Long productId, String submittedOnDate, Double principal,
+            Integer numberOfRepayments) {
+        return applyLoan(clientId, productId, submittedOnDate, principal, numberOfRepayments)
+                .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION_STRATEGY);
     }
 
     public static PostLoansLoanIdRequest approveLoan(Double approvedAmount, String approvedOnDate) {
@@ -132,4 +146,91 @@
     public static PostLoansLoanIdTransactionsRequest waiveInterest(Double amount, String transactionDate) {
         return makeWaiver(amount, transactionDate);
     }
+
+    /**
+     * Creates a reschedule request that shifts a due date. Uses rescheduleReasonId=1 (default seed data).
+     */
+    public static PostCreateRescheduleLoansRequest rescheduleRequest(Long loanId, String submittedOnDate, String rescheduleFromDate,
+            String adjustedDueDate) {
+        return rescheduleRequest(loanId, submittedOnDate, rescheduleFromDate, adjustedDueDate, 1L);
+    }
+
+    public static PostCreateRescheduleLoansRequest rescheduleRequest(Long loanId, String submittedOnDate, String rescheduleFromDate,
+            String adjustedDueDate, Long rescheduleReasonId) {
+        return new PostCreateRescheduleLoansRequest()//
+                .loanId(loanId)//
+                .submittedOnDate(submittedOnDate)//
+                .rescheduleFromDate(rescheduleFromDate)//
+                .adjustedDueDate(adjustedDueDate)//
+                .rescheduleReasonId(rescheduleReasonId)//
+                .locale(LoanTestData.LOCALE)//
+                .dateFormat(LoanTestData.DATETIME_PATTERN);
+    }
+
+    public static PostUpdateRescheduleLoansRequest approveReschedule(String approvedOnDate) {
+        return new PostUpdateRescheduleLoansRequest()//
+                .approvedOnDate(approvedOnDate)//
+                .locale(LoanTestData.LOCALE)//
+                .dateFormat(LoanTestData.DATETIME_PATTERN);
+    }
+
+    /**
+     * Creates a reAge request for non-interest-bearing loans (no interest handling needed).
+     */
+    public static PostLoansLoanIdTransactionsRequest reAge(String startDate, String frequencyType, Integer frequencyNumber,
+            Integer numberOfInstallments) {
+        return reAge(startDate, frequencyType, frequencyNumber, numberOfInstallments, null);
+    }
+
+    /**
+     * Creates a reAge request with explicit interest handling.
+     *
+     * @param reAgeInterestHandling
+     *            e.g. "EQUAL_AMORTIZATION_PAYABLE_INTEREST", "EQUAL_AMORTIZATION_FULL_INTEREST", or null for
+     *            non-interest-bearing loans
+     */
+    public static PostLoansLoanIdTransactionsRequest reAge(String startDate, String frequencyType, Integer frequencyNumber,
+            Integer numberOfInstallments, String reAgeInterestHandling) {
+        PostLoansLoanIdTransactionsRequest request = new PostLoansLoanIdTransactionsRequest();
+        request.setStartDate(startDate);
+        request.setFrequencyType(frequencyType);
+        request.setFrequencyNumber(frequencyNumber);
+        request.setNumberOfInstallments(numberOfInstallments);
+        if (reAgeInterestHandling != null) {
+            request.setReAgeInterestHandling(reAgeInterestHandling);
+        }
+        request.setLocale(LoanTestData.LOCALE);
+        request.setDateFormat(LoanTestData.DATETIME_PATTERN);
+        return request;
+    }
+
+    /**
+     * Creates a DEFAULT payment allocation with NEXT_INSTALLMENT future rule. Suitable for most progressive loan
+     * products using advanced-payment-allocation-strategy.
+     */
+    public static AdvancedPaymentData defaultPaymentAllocation() {
+        return paymentAllocation("DEFAULT", "NEXT_INSTALLMENT");
+    }
+
+    /**
+     * Creates a payment allocation for a specific transaction type and future installment allocation rule.
+     *
+     * @param transactionType
+     *            e.g. "DEFAULT", "REPAYMENT", "DOWN_PAYMENT", "MERCHANT_ISSUED_REFUND"
+     * @param futureInstallmentAllocationRule
+     *            e.g. "NEXT_INSTALLMENT", "LAST_INSTALLMENT", "NEXT_LAST_INSTALLMENT"
+     */
+    public static AdvancedPaymentData paymentAllocation(String transactionType, String futureInstallmentAllocationRule) {
+        AdvancedPaymentData data = new AdvancedPaymentData();
+        data.setTransactionType(transactionType);
+        data.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule);
+        AtomicInteger order = new AtomicInteger(1);
+        List<PaymentAllocationOrder> orders = Stream
+                .of("PAST_DUE_PENALTY", "PAST_DUE_FEE", "PAST_DUE_PRINCIPAL", "PAST_DUE_INTEREST", "DUE_PENALTY", "DUE_FEE",
+                        "DUE_PRINCIPAL", "DUE_INTEREST", "IN_ADVANCE_PENALTY", "IN_ADVANCE_FEE", "IN_ADVANCE_PRINCIPAL",
+                        "IN_ADVANCE_INTEREST")
+                .map(rule -> new PaymentAllocationOrder().paymentAllocationRule(rule).order(order.getAndIncrement())).toList();
+        data.setPaymentAllocationOrder(orders);
+        return data;
+    }
 }
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignLoanRescheduleAfterReAgeTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignLoanRescheduleAfterReAgeTest.java
new file mode 100644
index 0000000..9dcb001
--- /dev/null
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignLoanRescheduleAfterReAgeTest.java
@@ -0,0 +1,165 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.integrationtests.client.feign.tests;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.List;
+import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.GetLoansLoanIdStatus;
+import org.apache.fineract.client.models.PostLoanProductsRequest;
+import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase;
+import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData;
+import org.apache.fineract.integrationtests.common.Utils;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Verifies that the sequence Reschedule -> ReAge -> Reschedule produces a correct repayment schedule.
+ */
+public class FeignLoanRescheduleAfterReAgeTest extends FeignLoanTestBase {
+
+    @Test
+    void testRescheduleAfterReAgeWithDownpayment() {
+        runAt("2026-04-21", () -> {
+            Long clientId = createClient("21 April 2026");
+            Long productId = createLoanProduct(createProgressiveNoInterestWithDownpayment());
+
+            Long loanId = createApproveAndDisburseProgressiveLoan(clientId, productId, "21 April 2026", 540.0, 2);
+
+            GetLoansLoanIdResponse loan = getLoanDetails(loanId);
+            verifyLoanStatus(loan, GetLoansLoanIdStatus::getActive);
+            assertEquals(360.0, Utils.getDoubleValue(loan.getSummary().getTotalOutstanding()));
+
+            createAndApproveReschedule(loanId, "21 April 2026", "21 May 2026", "21 June 2026");
+
+            reAge(loanId, reAge("23 May 2026", LoanTestData.RepaymentFrequencyType.MONTHS_STRING, 1, 15));
+
+            loan = getLoanDetails(loanId);
+            assertEquals(360.0, Utils.getDoubleValue(loan.getSummary().getTotalOutstanding()));
+
+            createAndApproveReschedule(loanId, "21 April 2026", "23 May 2026", "23 July 2026");
+
+            loan = getLoanDetails(loanId);
+            verifyLoanStatus(loan, GetLoansLoanIdStatus::getActive);
+
+            double totalOutstanding = Utils.getDoubleValue(loan.getSummary().getTotalOutstanding());
+            assertEquals(360.0, totalOutstanding, "Outstanding balance should equal principal minus downpayment");
+
+            double totalPrincipalDue = loan.getRepaymentSchedule().getPeriods().stream()//
+                    .filter(p -> p.getPeriod() != null)//
+                    .mapToDouble(p -> Utils.getDoubleValue(p.getPrincipalDue()))//
+                    .sum();
+            assertEquals(540.0, totalPrincipalDue, "Total principal due must equal loan amount");
+
+            List<GetLoansLoanIdRepaymentPeriod> periods = loan.getRepaymentSchedule().getPeriods();
+            for (GetLoansLoanIdRepaymentPeriod period : periods) {
+                if (period.getPrincipalLoanBalanceOutstanding() != null) {
+                    assertTrue(Utils.getDoubleValue(period.getPrincipalLoanBalanceOutstanding()) >= 0,
+                            "Balance should not be negative for period " + period.getPeriod());
+                }
+            }
+
+            GetLoansLoanIdRepaymentPeriod firstUnpaid = periods.stream()//
+                    .filter(p -> p.getPeriod() != null && Utils.getDoubleValue(p.getPrincipalOutstanding()) > 0)//
+                    .findFirst().orElseThrow(() -> new AssertionError("Expected at least one unpaid installment"));
+            assertEquals(2026, firstUnpaid.getDueDate().getYear());
+            assertEquals(7, firstUnpaid.getDueDate().getMonthValue(), "First unpaid installment should be in July (shifted by 2 months)");
+        });
+    }
+
+    @Test
+    void testRescheduleAfterReAgeWithoutDownpayment() {
+        runAt("2026-04-20", () -> {
+            Long clientId = createClient("20 April 2026");
+            Long productId = createLoanProduct(createProgressiveNoInterestNoDownpayment());
+
+            Long loanId = createApproveAndDisburseProgressiveLoan(clientId, productId, "20 April 2026", 600.0, 1);
+
+            GetLoansLoanIdResponse loan = getLoanDetails(loanId);
+            verifyLoanStatus(loan, GetLoansLoanIdStatus::getActive);
+            assertEquals(600.0, Utils.getDoubleValue(loan.getSummary().getTotalOutstanding()));
+
+            createAndApproveReschedule(loanId, "20 April 2026", "20 May 2026", "18 August 2026");
+
+            reAge(loanId, reAge("04 June 2026", LoanTestData.RepaymentFrequencyType.DAYS_STRING, 30, 20));
+
+            loan = getLoanDetails(loanId);
+            assertEquals(600.0, Utils.getDoubleValue(loan.getSummary().getTotalOutstanding()));
+
+            createAndApproveReschedule(loanId, "20 April 2026", "04 July 2026", "02 October 2026");
+
+            loan = getLoanDetails(loanId);
+            verifyLoanStatus(loan, GetLoansLoanIdStatus::getActive);
+
+            double totalOutstanding = Utils.getDoubleValue(loan.getSummary().getTotalOutstanding());
+            assertEquals(600.0, totalOutstanding, "Outstanding balance should be 600");
+
+            double totalPrincipalDue = loan.getRepaymentSchedule().getPeriods().stream()//
+                    .filter(p -> p.getPeriod() != null)//
+                    .mapToDouble(p -> Utils.getDoubleValue(p.getPrincipalDue()))//
+                    .sum();
+            assertEquals(600.0, totalPrincipalDue, "Total principal due must equal loan amount");
+
+            List<GetLoansLoanIdRepaymentPeriod> periods = loan.getRepaymentSchedule().getPeriods();
+            for (GetLoansLoanIdRepaymentPeriod period : periods) {
+                if (period.getPrincipalLoanBalanceOutstanding() != null) {
+                    assertTrue(Utils.getDoubleValue(period.getPrincipalLoanBalanceOutstanding()) >= 0,
+                            "Balance should not be negative for period " + period.getPeriod());
+                }
+            }
+
+            boolean hasOctoberInstallment = periods.stream()//
+                    .filter(p -> p.getPeriod() != null)//
+                    .anyMatch(p -> p.getDueDate().getMonthValue() == 10 && p.getDueDate().getYear() == 2026);
+            assertTrue(hasOctoberInstallment, "Should have an installment shifted to October 2026");
+
+            boolean hasJulyFourthInstallment = periods.stream()//
+                    .filter(p -> p.getPeriod() != null)//
+                    .anyMatch(p -> p.getDueDate().getMonthValue() == 7 && p.getDueDate().getDayOfMonth() == 4
+                            && p.getDueDate().getYear() == 2026);
+            assertFalse(hasJulyFourthInstallment, "Jul 4 installment should have been shifted");
+        });
+    }
+
+    private PostLoanProductsRequest createProgressiveNoInterestWithDownpayment() {
+        return customizeProduct(fourInstallmentsProgressiveWithAdvancedAllocation(), p -> p//
+                .numberOfRepayments(2)//
+                .interestRatePerPeriod(0.0)//
+                .repaymentEvery(1)//
+                .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS_L)//
+                .enableDownPayment(true)//
+                .disbursedAmountPercentageForDownPayment(BigDecimal.valueOf(33.333333))//
+                .enableAutoRepaymentForDownPayment(true)//
+                .currencyCode("GBP"));
+    }
+
+    private PostLoanProductsRequest createProgressiveNoInterestNoDownpayment() {
+        return customizeProduct(fourInstallmentsProgressiveWithAdvancedAllocation(), p -> p//
+                .numberOfRepayments(1)//
+                .interestRatePerPeriod(0.0)//
+                .repaymentEvery(30)//
+                .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS_L)//
+                .enableDownPayment(false));
+    }
+
+}