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
commit 71a4d08849aed6a25191b99a078b9b152c670cbc Author: mariiaKraievska <[email protected]> AuthorDate: Tue Jun 3 13:37:42 2025 +0300 FINERACT-2553: Fix repayment schedule during accelerate maturity date charge off/contract termination when full backdated repayment occurs after it --- .../test/resources/features/LoanChargeOff.feature | 225 +++++++++++++++++++++ .../features/LoanContractTermination.feature | 224 +++++++++++++++++++- .../portfolio/loanaccount/domain/Loan.java | 6 + ...dvancedPaymentScheduleTransactionProcessor.java | 163 +++++++++------ .../impl/ProgressiveTransactionCtx.java | 2 + ...InterestScheduleModelRepositoryWrapperImpl.java | 1 + .../loanproduct/calc/data/RepaymentPeriod.java | 5 + .../service/LoanAccrualsProcessingServiceImpl.java | 4 +- .../LoanTransactionProcessingServiceImpl.java | 1 + 9 files changed, 569 insertions(+), 62 deletions(-) diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanChargeOff.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanChargeOff.feature index 4cff176733..e2f294c572 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanChargeOff.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanChargeOff.feature @@ -5890,6 +5890,228 @@ Feature: Charge-off | 29 February 2024 | Accrual | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | false | false | | 29 February 2024 | Charge-off | 66.98 | 66.8 | 0.18 | 0.0 | 0.0 | 0.0 | false | false | + @TestRailId:C3727 + Scenario: As a user I want to perform accelerate maturity to charge-off date with interest recalculation when backdated full repayment occurs after - S12 + Given Global configuration "is-principal-compounding-disabled-for-overdue-loans" is enabled + 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_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR | 01 January 2024 | 100 | 7 | 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 "100" 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.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + 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 | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + When Admin sets the business date to "31 March 2024" + And Admin does charge-off the loan on "31 March 2024" + Then Loan Repayment schedule has 3 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.05 | 0.47 | 0.0 | 0.0 | 67.52 | 0.0 | 0.0 | 0.0 | 67.52 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 17.01 | 0.0 | 0.0 | 84.53 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 31 March 2024 | Accrual | 1.54 | 0.0 | 1.54 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Charge-off | 84.53 | 83.57 | 0.96 | 0.0 | 0.0 | 0.0 | false | false | + And Customer makes "AUTOPAY" repayment on "01 March 2024" with 84.06 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 01 March 2024 | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | 01 March 2024 | 50.04 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | 17.01 | 17.01 | 0.0 | 0.0 | + | 4 | 30 | 01 May 2024 | 01 March 2024 | 33.03 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | 17.01 | 17.01 | 0.0 | 0.0 | + | 5 | 31 | 01 June 2024 | 01 March 2024 | 16.02 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | 17.01 | 17.01 | 0.0 | 0.0 | + | 6 | 30 | 01 July 2024 | 01 March 2024 | 0.0 | 16.02 | 0.0 | 0.0 | 0.0 | 16.02 | 16.02 | 16.02 | 0.0 | 0.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.07 | 0.0 | 0.0 | 101.07 | 101.07 | 67.05 | 0.0 | 0.0 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 March 2024 | Repayment | 84.06 | 83.57 | 0.49 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Accrual | 1.54 | 0.0 | 1.54 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Accrual Adjustment | 0.47 | 0.0 | 0.47 | 0.0 | 0.0 | 0.0 | false | false | + And Global configuration "is-principal-compounding-disabled-for-overdue-loans" is disabled + + @TestRailId:C3728 + Scenario: As a user I want to perform accelerate maturity to charge-off date with interest recalculation when backdated repayment with excess amount occurs after - S13 + Given Global configuration "is-principal-compounding-disabled-for-overdue-loans" is enabled + 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_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR | 01 January 2024 | 100 | 7 | 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 "100" 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.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + 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 | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + When Admin sets the business date to "31 March 2024" + And Admin does charge-off the loan on "31 March 2024" + Then Loan Repayment schedule has 3 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.05 | 0.47 | 0.0 | 0.0 | 67.52 | 0.0 | 0.0 | 0.0 | 67.52 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 17.01 | 0.0 | 0.0 | 84.53 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 31 March 2024 | Accrual | 1.54 | 0.0 | 1.54 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Charge-off | 84.53 | 83.57 | 0.96 | 0.0 | 0.0 | 0.0 | false | false | + And Customer makes "AUTOPAY" repayment on "01 March 2024" with 27.01 EUR transaction amount + Then Loan Repayment schedule has 3 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 01 March 2024 | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.05 | 0.32 | 0.0 | 0.0 | 67.37 | 10.0 | 10.0 | 0.0 | 57.37 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.39 | 0.0 | 0.0 | 101.39 | 44.02 | 10.0 | 0.0 | 57.37 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 March 2024 | Repayment | 27.01 | 26.52 | 0.49 | 0.0 | 0.0 | 57.05 | false | false | + | 31 March 2024 | Accrual | 1.54 | 0.0 | 1.54 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Accrual Adjustment | 0.15 | 0.0 | 0.15 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Charge-off | 57.37 | 57.05 | 0.32 | 0.0 | 0.0 | 0.0 | false | true | + And Global configuration "is-principal-compounding-disabled-for-overdue-loans" is disabled + + @TestRailId:C3729 + Scenario: As a user I want to perform accelerate maturity to charge-off date with interest recalculation when backdated first repayment with excess amount occurs after + Given Global configuration "is-principal-compounding-disabled-for-overdue-loans" is enabled + 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_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR | 01 January 2024 | 100 | 7 | 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 "100" 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.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + 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 | + When Admin sets the business date to "31 March 2024" + And Admin does charge-off the loan on "31 March 2024" + Then Loan Repayment schedule has 3 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.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.14 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.14 | 0.56 | 0.0 | 0.0 | 67.7 | 0.0 | 0.0 | 0.0 | 67.7 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.72 | 0.0 | 0.0 | 101.72 | 0.0 | 0.0 | 0.0 | 101.72 | + 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 | + | 31 March 2024 | Accrual | 1.72 | 0.0 | 1.72 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Charge-off | 101.72 | 100.0 | 1.72 | 0.0 | 0.0 | 0.0 | false | false | + And Customer makes "AUTOPAY" repayment on "01 March 2024" with 70.00 EUR transaction amount + Then Loan Repayment schedule has 3 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 | 01 March 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 17.01 | 0.0 | + | 2 | 29 | 01 March 2024 | 01 March 2024 | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.05 | 0.08 | 0.0 | 0.0 | 67.13 | 35.98 | 35.98 | 0.0 | 31.15 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.15 | 0.0 | 0.0 | 101.15 | 70.0 | 35.98 | 17.01 | 31.15 | + 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 March 2024 | Repayment | 70.0 | 68.93 | 1.07 | 0.0 | 0.0 | 31.07 | false | false | + | 31 March 2024 | Accrual | 1.72 | 0.0 | 1.72 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Accrual Adjustment | 0.57 | 0.0 | 0.57 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Charge-off | 31.15 | 31.07 | 0.08 | 0.0 | 0.0 | 0.0 | false | true | + And Global configuration "is-principal-compounding-disabled-for-overdue-loans" is disabled + @TestRailId:C3499 @AdvancedPaymentAllocation Scenario: Verify accelerate maturity to charge-off date when interest recalculation is disabled - case when charge-off occurs with adjustment to last installment When Admin sets the business date to "01 January 2024" @@ -8298,6 +8520,7 @@ Feature: Charge-off | 13 April 2025 | Merchant Issued Refund | 500.0 | 9.81 | 0.5 | 0.0 | 0.0 | 0.0 | false | false | | 14 April 2025 | Accrual | 3.21 | 0.0 | 3.21 | 0.0 | 0.0 | 0.0 | false | false | | 14 April 2025 | Accrual Adjustment | 0.24 | 0.0 | 0.24 | 0.0 | 0.0 | 0.0 | false | false | + | 14 April 2025 | Accrual | 7.34 | 0.0 | 7.34 | 0.0 | 0.0 | 0.0 | false | false | When Customer makes "GOODWILL_CREDIT" transaction with "AUTOPAY" payment type on "13 April 2025" with 500 EUR transaction amount and system-generated Idempotency key 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 | Waived | Outstanding | @@ -8319,6 +8542,7 @@ Feature: Charge-off | 13 April 2025 | Goodwill Credit | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | | 14 April 2025 | Accrual | 3.21 | 0.0 | 3.21 | 0.0 | 0.0 | 0.0 | false | false | | 14 April 2025 | Accrual Adjustment | 0.24 | 0.0 | 0.24 | 0.0 | 0.0 | 0.0 | false | false | + | 14 April 2025 | Accrual | 7.34 | 0.0 | 7.34 | 0.0 | 0.0 | 0.0 | false | false | @TestRailId:C3612 Scenario: As a user I want to verify that backdated transactions are allowed after charge-off and backdated full repayment, interestRecalculation = true @@ -9172,6 +9396,7 @@ Feature: Charge-off | 13 April 2025 | Merchant Issued Refund | 500.0 | 9.81 | 0.5 | 0.0 | 0.0 | 0.0 | false | false | | 14 April 2025 | Accrual | 3.21 | 0.0 | 3.21 | 0.0 | 0.0 | 0.0 | false | false | | 14 April 2025 | Accrual Adjustment | 0.24 | 0.0 | 0.24 | 0.0 | 0.0 | 0.0 | false | false | + | 14 April 2025 | Accrual | 7.34 | 0.0 | 7.34 | 0.0 | 0.0 | 0.0 | false | false | @TestRailId:C3644 Scenario: As a user I want to verify that charge-off transaction if the amount balance becomes zero is reversed after backdated full repayment and MIR, interestRecalculation = true diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanContractTermination.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanContractTermination.feature index b160d6a8fb..531db393e9 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanContractTermination.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanContractTermination.feature @@ -825,4 +825,226 @@ Feature: Contract Termination | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | | 15 February 2024 | Repayment | 17.01 | 16.77 | 0.24 | 0.0 | 0.0 | 66.8 | false | true | | 29 February 2024 | Accrual | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | false | false | - | 29 February 2024 | Contract Termination | 66.98 | 66.8 | 0.18 | 0.0 | 0.0 | 0.0 | false | false | \ No newline at end of file + | 29 February 2024 | Contract Termination | 66.98 | 66.8 | 0.18 | 0.0 | 0.0 | 0.0 | false | false | + + @TestRailId:C3724 + Scenario: As a user I want to perform contract termination to a progressive loan with interest recalculation when backdated full repayment occurs after - S12 + Given Global configuration "is-principal-compounding-disabled-for-overdue-loans" is enabled + 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_INTEREST_RECALCULATION_CONTRACT_TERMINATION | 01 January 2024 | 100 | 7 | 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 "100" 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.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + 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 | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + When Admin sets the business date to "31 March 2024" + And Admin successfully terminates loan contract + Then Loan Repayment schedule has 3 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.05 | 0.47 | 0.0 | 0.0 | 67.52 | 0.0 | 0.0 | 0.0 | 67.52 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 17.01 | 0.0 | 0.0 | 84.53 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 31 March 2024 | Accrual | 1.54 | 0.0 | 1.54 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Contract Termination | 84.53 | 83.57 | 0.96 | 0.0 | 0.0 | 0.0 | false | false | + And Customer makes "AUTOPAY" repayment on "01 March 2024" with 84.06 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 01 March 2024 | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | 01 March 2024 | 50.04 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | 17.01 | 17.01 | 0.0 | 0.0 | + | 4 | 30 | 01 May 2024 | 01 March 2024 | 33.03 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | 17.01 | 17.01 | 0.0 | 0.0 | + | 5 | 31 | 01 June 2024 | 01 March 2024 | 16.02 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | 17.01 | 17.01 | 0.0 | 0.0 | + | 6 | 30 | 01 July 2024 | 01 March 2024 | 0.0 | 16.02 | 0.0 | 0.0 | 0.0 | 16.02 | 16.02 | 16.02 | 0.0 | 0.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.07 | 0.0 | 0.0 | 101.07 | 101.07 | 67.05 | 0.0 | 0.0 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 March 2024 | Repayment | 84.06 | 83.57 | 0.49 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Accrual | 1.54 | 0.0 | 1.54 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Accrual Adjustment | 0.47 | 0.0 | 0.47 | 0.0 | 0.0 | 0.0 | false | false | + And Global configuration "is-principal-compounding-disabled-for-overdue-loans" is disabled + + @TestRailId:C3725 + Scenario: As a user I want to perform contract termination to a progressive loan with interest recalculation when backdated repayment with excess amount occurs after - S13 + Given Global configuration "is-principal-compounding-disabled-for-overdue-loans" is enabled + 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_INTEREST_RECALCULATION_CONTRACT_TERMINATION | 01 January 2024 | 100 | 7 | 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 "100" 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.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + 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 | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + When Admin sets the business date to "31 March 2024" + And Admin successfully terminates loan contract + Then Loan Repayment schedule has 3 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.05 | 0.47 | 0.0 | 0.0 | 67.52 | 0.0 | 0.0 | 0.0 | 67.52 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 17.01 | 0.0 | 0.0 | 84.53 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 31 March 2024 | Accrual | 1.54 | 0.0 | 1.54 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Contract Termination | 84.53 | 83.57 | 0.96 | 0.0 | 0.0 | 0.0 | false | false | + And Customer makes "AUTOPAY" repayment on "01 March 2024" with 27.01 EUR transaction amount + Then Loan Repayment schedule has 3 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 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 01 March 2024 | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.05 | 0.32 | 0.0 | 0.0 | 67.37 | 10.0 | 10.0 | 0.0 | 57.37 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.39 | 0.0 | 0.0 | 101.39 | 44.02 | 10.0 | 0.0 | 57.37 | + 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 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 March 2024 | Repayment | 27.01 | 26.52 | 0.49 | 0.0 | 0.0 | 57.05 | false | false | + | 31 March 2024 | Accrual | 1.54 | 0.0 | 1.54 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Accrual Adjustment | 0.15 | 0.0 | 0.15 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Contract Termination | 57.37 | 57.05 | 0.32 | 0.0 | 0.0 | 0.0 | false | true | + And Global configuration "is-principal-compounding-disabled-for-overdue-loans" is disabled + + @TestRailId:C3726 + Scenario: As a user I want to perform contract termination to a progressive loan with interest recalculation when backdated first repayment with excess amount occurs after + Given Global configuration "is-principal-compounding-disabled-for-overdue-loans" is enabled + 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_INTEREST_RECALCULATION_CONTRACT_TERMINATION | 01 January 2024 | 100 | 7 | 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 "100" 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.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + 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.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + 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 | + When Admin sets the business date to "31 March 2024" + And Admin successfully terminates loan contract + Then Loan Repayment schedule has 3 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.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.14 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.14 | 0.56 | 0.0 | 0.0 | 67.7 | 0.0 | 0.0 | 0.0 | 67.7 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.72 | 0.0 | 0.0 | 101.72 | 0.0 | 0.0 | 0.0 | 101.72 | + 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 | + | 31 March 2024 | Accrual | 1.72 | 0.0 | 1.72 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Contract Termination | 101.72 | 100.0 | 1.72 | 0.0 | 0.0 | 0.0 | false | false | + And Customer makes "AUTOPAY" repayment on "01 March 2024" with 70.00 EUR transaction amount + Then Loan Repayment schedule has 3 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 | 01 March 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 17.01 | 0.0 | + | 2 | 29 | 01 March 2024 | 01 March 2024 | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 3 | 30 | 31 March 2024 | | 0.0 | 67.05 | 0.08 | 0.0 | 0.0 | 67.13 | 35.98 | 35.98 | 0.0 | 31.15 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.15 | 0.0 | 0.0 | 101.15 | 70.0 | 35.98 | 17.01 | 31.15 | + 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 March 2024 | Repayment | 70.0 | 68.93 | 1.07 | 0.0 | 0.0 | 31.07 | false | false | + | 31 March 2024 | Accrual | 1.72 | 0.0 | 1.72 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Accrual Adjustment | 0.57 | 0.0 | 0.57 | 0.0 | 0.0 | 0.0 | false | false | + | 31 March 2024 | Contract Termination | 31.15 | 31.07 | 0.08 | 0.0 | 0.0 | 0.0 | false | true | + And Global configuration "is-principal-compounding-disabled-for-overdue-loans" is disabled \ No newline at end of file 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 6c980b863d..f3c76d0572 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 @@ -1655,6 +1655,12 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> { return false; } + public void liftContractTerminationSubStatus() { + if (this.loanSubStatus.isContractTermination()) { + this.loanSubStatus = null; + } + } + public List<LoanTermVariations> getActiveLoanTermVariations() { if (this.loanTermVariations == null) { return new ArrayList<>(); 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 1a85d74822..bd36229754 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 @@ -353,32 +353,47 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } private void handleContractTermination(final LoanTransaction loanTransaction, final TransactionCtx transactionCtx) { - handleAccelerateMaturityDate(loanTransaction, transactionCtx); - - final BigDecimal newInterest = getInterestTillChargeOffForPeriod(loanTransaction.getLoan(), loanTransaction.getTransactionDate(), - transactionCtx); - createMissingAccrualTransactionDuringChargeOffIfNeeded(newInterest, loanTransaction, loanTransaction.getTransactionDate(), - transactionCtx); - - loanTransaction.resetDerivedComponents(); - // determine how much is outstanding total and breakdown for principal, interest and charges Money principalPortion = Money.zero(transactionCtx.getCurrency()); Money interestPortion = Money.zero(transactionCtx.getCurrency()); Money feeChargesPortion = Money.zero(transactionCtx.getCurrency()); Money penaltyChargesPortion = Money.zero(transactionCtx.getCurrency()); - for (final LoanRepaymentScheduleInstallment currentInstallment : transactionCtx.getInstallments()) { - principalPortion = principalPortion.plus(currentInstallment.getPrincipalOutstanding(transactionCtx.getCurrency())); - interestPortion = interestPortion.plus(currentInstallment.getInterestOutstanding(transactionCtx.getCurrency())); - feeChargesPortion = feeChargesPortion.plus(currentInstallment.getFeeChargesOutstanding(transactionCtx.getCurrency())); - penaltyChargesPortion = penaltyChargesPortion - .plus(currentInstallment.getPenaltyChargesOutstanding(transactionCtx.getCurrency())); + + if (transactionCtx.getInstallments().stream().anyMatch(this::isNotObligationsMet)) { + handleAccelerateMaturityDate(loanTransaction, transactionCtx); + + final BigDecimal newInterest = getInterestTillChargeOffForPeriod(loanTransaction.getLoan(), + loanTransaction.getTransactionDate(), transactionCtx); + createMissingAccrualTransactionDuringChargeOffIfNeeded(newInterest, loanTransaction, loanTransaction.getTransactionDate(), + transactionCtx); + + loanTransaction.resetDerivedComponents(); + // determine how much is outstanding total and breakdown for principal, interest and charges + for (final LoanRepaymentScheduleInstallment currentInstallment : transactionCtx.getInstallments()) { + principalPortion = principalPortion.plus(currentInstallment.getPrincipalOutstanding(transactionCtx.getCurrency())); + interestPortion = interestPortion.plus(currentInstallment.getInterestOutstanding(transactionCtx.getCurrency())); + feeChargesPortion = feeChargesPortion.plus(currentInstallment.getFeeChargesOutstanding(transactionCtx.getCurrency())); + penaltyChargesPortion = penaltyChargesPortion + .plus(currentInstallment.getPenaltyChargesOutstanding(transactionCtx.getCurrency())); + } + + loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion); + } else { + loanTransaction.resetDerivedComponents(); + loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion); } - loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion); + if (transactionCtx instanceof ProgressiveTransactionCtx progressiveTransactionCtx) { + progressiveTransactionCtx.setContractTerminated(true); + } if (isAllComponentsZero(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion) && loanTransaction.isNotReversed()) { loanTransaction.reverse(); + loanTransaction.getLoan().liftContractTerminationSubStatus(); + + if (transactionCtx instanceof ProgressiveTransactionCtx progressiveCtx) { + progressiveCtx.setContractTerminated(false); + } } } @@ -1381,7 +1396,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep public void recalculateInterestForDate(LocalDate targetDate, ProgressiveTransactionCtx ctx) { if (ctx.getInstallments() != null && !ctx.getInstallments().isEmpty()) { Loan loan = ctx.getInstallments().get(0).getLoan(); - if (loan.isInterestBearingAndInterestRecalculationEnabled() && !loan.isNpa() && !ctx.isChargedOff()) { + if (loan.isInterestBearingAndInterestRecalculationEnabled() && !loan.isNpa() && !ctx.isChargedOff() + && !ctx.isContractTerminated()) { List<LoanRepaymentScheduleInstallment> overdueInstallmentsSortedByInstallmentNumber = findOverdueInstallmentsBeforeDateSortedByInstallmentNumber( targetDate, ctx); @@ -1572,36 +1588,42 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } private void handleChargeOff(final LoanTransaction loanTransaction, final TransactionCtx transactionCtx) { - if (loanTransaction.getLoan().isProgressiveSchedule()) { - if (LoanChargeOffBehaviour.ZERO_INTEREST - .equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getChargeOffBehaviour())) { - handleZeroInterestChargeOff(loanTransaction, transactionCtx); - } else if (LoanChargeOffBehaviour.ACCELERATE_MATURITY - .equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getChargeOffBehaviour())) { - handleAccelerateMaturityDate(loanTransaction, transactionCtx); - } - } - - final BigDecimal newInterest = getInterestTillChargeOffForPeriod(loanTransaction.getLoan(), loanTransaction.getTransactionDate(), - transactionCtx); - createMissingAccrualTransactionDuringChargeOffIfNeeded(newInterest, loanTransaction, loanTransaction.getTransactionDate(), - transactionCtx); - - loanTransaction.resetDerivedComponents(); - // determine how much is outstanding total and breakdown for principal, interest and charges Money principalPortion = Money.zero(transactionCtx.getCurrency()); Money interestPortion = Money.zero(transactionCtx.getCurrency()); Money feeChargesPortion = Money.zero(transactionCtx.getCurrency()); Money penaltyChargesPortion = Money.zero(transactionCtx.getCurrency()); - for (final LoanRepaymentScheduleInstallment currentInstallment : transactionCtx.getInstallments()) { - principalPortion = principalPortion.plus(currentInstallment.getPrincipalOutstanding(transactionCtx.getCurrency())); - interestPortion = interestPortion.plus(currentInstallment.getInterestOutstanding(transactionCtx.getCurrency())); - feeChargesPortion = feeChargesPortion.plus(currentInstallment.getFeeChargesOutstanding(transactionCtx.getCurrency())); - penaltyChargesPortion = penaltyChargesPortion - .plus(currentInstallment.getPenaltyChargesOutstanding(transactionCtx.getCurrency())); - } - loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion); + if (transactionCtx.getInstallments().stream().anyMatch(this::isNotObligationsMet)) { + if (loanTransaction.getLoan().isProgressiveSchedule()) { + if (LoanChargeOffBehaviour.ZERO_INTEREST + .equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getChargeOffBehaviour())) { + handleZeroInterestChargeOff(loanTransaction, transactionCtx); + } else if (LoanChargeOffBehaviour.ACCELERATE_MATURITY + .equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getChargeOffBehaviour())) { + handleAccelerateMaturityDate(loanTransaction, transactionCtx); + } + } + + final BigDecimal newInterest = getInterestTillChargeOffForPeriod(loanTransaction.getLoan(), + loanTransaction.getTransactionDate(), transactionCtx); + createMissingAccrualTransactionDuringChargeOffIfNeeded(newInterest, loanTransaction, loanTransaction.getTransactionDate(), + transactionCtx); + + loanTransaction.resetDerivedComponents(); + // determine how much is outstanding total and breakdown for principal, interest and charges + for (final LoanRepaymentScheduleInstallment currentInstallment : transactionCtx.getInstallments()) { + principalPortion = principalPortion.plus(currentInstallment.getPrincipalOutstanding(transactionCtx.getCurrency())); + interestPortion = interestPortion.plus(currentInstallment.getInterestOutstanding(transactionCtx.getCurrency())); + feeChargesPortion = feeChargesPortion.plus(currentInstallment.getFeeChargesOutstanding(transactionCtx.getCurrency())); + penaltyChargesPortion = penaltyChargesPortion + .plus(currentInstallment.getPenaltyChargesOutstanding(transactionCtx.getCurrency())); + } + + loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion); + } else { + loanTransaction.resetDerivedComponents(); + loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion); + } if (transactionCtx instanceof ProgressiveTransactionCtx progressiveTransactionCtx) { progressiveTransactionCtx.setChargedOff(true); @@ -1610,6 +1632,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep if (isAllComponentsZero(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion) && loanTransaction.isNotReversed()) { loanTransaction.reverse(); + loanTransaction.getLoan().liftChargeOff(); if (transactionCtx instanceof ProgressiveTransactionCtx progressiveCtx) { progressiveCtx.setChargedOff(false); @@ -1671,11 +1694,13 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep .filter(installment -> transactionDate.isAfter(installment.getFromDate())) .collect(Collectors.toCollection(ArrayList::new)); - final List<LoanTransaction> transactionsToBeReprocessed = installments.stream() - .filter(installment -> transactionDate.isBefore(installment.getFromDate()) - && !installment.getLoanTransactionToRepaymentScheduleMappings().isEmpty()) - .flatMap(installment -> installment.getLoanTransactionToRepaymentScheduleMappings().stream()) - .map(LoanTransactionToRepaymentScheduleMapping::getLoanTransaction).toList(); + final List<LoanTransaction> transactionsToBeReprocessed = loan.getLoanTransactions().stream() + .filter(transaction -> transaction.getTransactionDate().isBefore(transactionDate)) + .filter(transaction -> transaction.getLoanTransactionToRepaymentScheduleMappings().stream().anyMatch(mapping -> { + final LoanRepaymentScheduleInstallment installment = mapping.getInstallment(); + return transactionDate.isBefore(installment.getFromDate()) + && installments.stream().anyMatch(i -> i.getInstallmentNumber().equals(installment.getInstallmentNumber())); + })).toList(); if (futureFee.compareTo(BigDecimal.ZERO) > 0 || futurePenalty.compareTo(BigDecimal.ZERO) > 0) { final Optional<LocalDate> latestDueDate = loan.getCharges().stream() @@ -1693,6 +1718,12 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } } + transactionCtx.getInstallments().stream().filter(installment -> installment.getFromDate().isBefore(transactionDate)) + .filter(installment -> transactionsToBeReprocessed.stream() + .anyMatch(transaction -> transaction.getLoanTransactionToRepaymentScheduleMappings().stream().anyMatch( + mapping -> mapping.getInstallment().getInstallmentNumber().equals(installment.getInstallmentNumber())))) + .forEach(LoanRepaymentScheduleInstallment::resetDerivedComponents); + loanSchedule.updateLoanSchedule(loan, installmentsUpToTransactionDate); if (transactionCtx instanceof ProgressiveTransactionCtx progressiveTransactionCtx && loan.isInterestRecalculationEnabled()) { @@ -2209,7 +2240,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep Loan loan = context.getLoanTransaction().getLoan(); if (context.getCtx() instanceof ProgressiveTransactionCtx progressiveTransactionCtx && loan.isInterestBearingAndInterestRecalculationEnabled() - && !progressiveTransactionCtx.isChargedOff()) { + && !progressiveTransactionCtx.isChargedOff() + && !progressiveTransactionCtx.isContractTerminated()) { context.setAllocatedAmount( handlingPaymentAllocationForInterestBearingProgressiveLoan(context.getLoanTransaction(), context.getTransactionAmountUnprocessed(), context.getBalances(), @@ -2237,7 +2269,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep Loan loan = context.getLoanTransaction().getLoan(); if (context.getCtx() instanceof ProgressiveTransactionCtx progressiveTransactionCtx && loan.isInterestBearingAndInterestRecalculationEnabled() - && !progressiveTransactionCtx.isChargedOff()) { + && !progressiveTransactionCtx.isChargedOff() + && !progressiveTransactionCtx.isContractTerminated()) { context.setAllocatedAmount(handlingPaymentAllocationForInterestBearingProgressiveLoan( context.getLoanTransaction(), context.getTransactionAmountUnprocessed(), context.getBalances(), paymentAllocationType, dueInstallment, progressiveTransactionCtx, @@ -2290,7 +2323,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } if (context.getCtx() instanceof ProgressiveTransactionCtx progressiveTransactionCtx && loan.isInterestBearingAndInterestRecalculationEnabled() - && !progressiveTransactionCtx.isChargedOff()) { + && !progressiveTransactionCtx.isChargedOff() + && !progressiveTransactionCtx.isContractTerminated()) { context.setAllocatedAmount(handlingPaymentAllocationForInterestBearingProgressiveLoan( context.getLoanTransaction(), evenPortion, context.getBalances(), paymentAllocationType, inAdvanceInstallment, progressiveTransactionCtx, @@ -2650,27 +2684,33 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } private void updateRepaymentPeriodsAfterAccelerateMaturityDate(final ProgressiveTransactionCtx transactionCtx, - final LocalDate chargeOffDate, final List<LoanTransaction> transactionsToBeReprocessed) { + final LocalDate transactionDate, final List<LoanTransaction> transactionsToBeReprocessed) { + final List<LoanRepaymentScheduleInstallment> previousInstallmentsMapping = new ArrayList<>(); + transactionsToBeReprocessed.forEach(t -> { + previousInstallmentsMapping.addAll(t.getLoanTransactionToRepaymentScheduleMappings().stream() + .map(LoanTransactionToRepaymentScheduleMapping::getInstallment).toList()); + t.getLoanTransactionToRepaymentScheduleMappings().clear(); + }); final List<RepaymentPeriod> repaymentPeriods = transactionCtx.getModel().repaymentPeriods(); if (repaymentPeriods.isEmpty()) { return; } - final List<RepaymentPeriod> periodsBeforeChargeOff = repaymentPeriods.stream() - .filter(rp -> rp.getFromDate().isBefore(chargeOffDate)).toList(); + final List<RepaymentPeriod> periodsBeforeAccelerateMaturity = repaymentPeriods.stream() + .filter(rp -> rp.getFromDate().isBefore(transactionDate)).toList(); - if (periodsBeforeChargeOff.isEmpty()) { + if (periodsBeforeAccelerateMaturity.isEmpty()) { return; } - final RepaymentPeriod lastPeriod = periodsBeforeChargeOff.get(periodsBeforeChargeOff.size() - 1); + final RepaymentPeriod lastPeriod = periodsBeforeAccelerateMaturity.getLast(); - final List<RepaymentPeriod> periodsToRemove = repaymentPeriods.stream().filter(rp -> rp.getFromDate().isAfter(chargeOffDate)) + final List<RepaymentPeriod> periodsToRemove = repaymentPeriods.stream().filter(rp -> rp.getFromDate().isAfter(transactionDate)) .toList(); - lastPeriod.setDueDate(chargeOffDate); - lastPeriod.getInterestPeriods().removeIf(interestPeriod -> !interestPeriod.getFromDate().isBefore(chargeOffDate)); + lastPeriod.setDueDate(transactionDate); + lastPeriod.getInterestPeriods().removeIf(interestPeriod -> !interestPeriod.getFromDate().isBefore(transactionDate)); transactionCtx.getModel().repaymentPeriods().removeAll(periodsToRemove); @@ -2678,7 +2718,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep BigDecimal::add); final BigDecimal newInterest = emiCalculator - .getPeriodInterestTillDate(transactionCtx.getModel(), lastPeriod.getDueDate(), chargeOffDate, false).getAmount(); + .getPeriodInterestTillDate(transactionCtx.getModel(), lastPeriod.getDueDate(), transactionDate, false).getAmount(); lastPeriod.setEmi(lastPeriod.getDuePrincipal().add(totalPrincipal).add(newInterest)); @@ -2686,6 +2726,11 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep transactionCtx.getModel().disableEMIRecalculation(); for (LoanTransaction processTransaction : transactionsToBeReprocessed) { + transactionCtx.getModel().repaymentPeriods().stream() + .filter(repaymentPeriod -> repaymentPeriod.getFromDate().isBefore(transactionDate)) + .filter(repaymentPeriod -> previousInstallmentsMapping.stream() + .anyMatch(installment -> installment.getFromDate().equals(repaymentPeriod.getFromDate()))) + .forEach(RepaymentPeriod::resetDerivedComponents); emiCalculator.addBalanceCorrection(transactionCtx.getModel(), processTransaction.getTransactionDate(), processTransaction.getPrincipalPortion(transactionCtx.getCurrency())); processSingleTransaction(processTransaction, transactionCtx); diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ProgressiveTransactionCtx.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ProgressiveTransactionCtx.java index 8b1ad8d98d..25ce2f80d1 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ProgressiveTransactionCtx.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ProgressiveTransactionCtx.java @@ -42,6 +42,8 @@ public class ProgressiveTransactionCtx extends TransactionCtx { private Money sumOfInterestRefundAmount; @Setter private boolean isChargedOff = false; + @Setter + private boolean isContractTerminated = false; private List<LoanRepaymentScheduleInstallment> skipRepaymentScheduleInstallments = new ArrayList<>(); public ProgressiveTransactionCtx(MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments, diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelRepositoryWrapperImpl.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelRepositoryWrapperImpl.java index a485544a46..261e5d25d6 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelRepositoryWrapperImpl.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelRepositoryWrapperImpl.java @@ -103,6 +103,7 @@ public class InterestScheduleModelRepositoryWrapperImpl implements InterestSched ProgressiveTransactionCtx ctx = new ProgressiveTransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), Set.of(), new MoneyHolder(loan.getTotalOverpaidAsMoney()), new ChangedTransactionDetail(), savedModel.get()); ctx.setChargedOff(loan.isChargedOff()); + ctx.setContractTerminated(loan.isContractTermination()); advancedPaymentScheduleTransactionProcessor.recalculateInterestForDate(businessDate, ctx); } } else { diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java index 6382e361ca..26e9e2a9d2 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java @@ -351,4 +351,9 @@ public final class RepaymentPeriod { public Money getOutstandingPrincipal() { return MathUtil.negativeToZero(getDuePrincipal().minus(getPaidPrincipal()), mc); } + + public void resetDerivedComponents() { + this.paidInterest = paidInterest.zero(); + this.paidPrincipal = paidPrincipal.zero(); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java index e38eae466c..d3289ed6d5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java @@ -335,8 +335,8 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing private void addAccruals(@NotNull final Loan loan, @NotNull LocalDate tillDate, final boolean periodic, final boolean isFinal, final boolean addJournal, final boolean chargeOnDueDate) { - if ((!isFinal && !loan.isOpen()) || loan.isNpa() || loan.isChargedOff() - || !loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) { + if ((!isFinal && !loan.isOpen()) || loan.isNpa() || loan.isChargedOff() || !loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() + || loan.isContractTermination()) { return; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanTransactionProcessingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanTransactionProcessingServiceImpl.java index 1da92d4a30..d9d53a6ca7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanTransactionProcessingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanTransactionProcessingServiceImpl.java @@ -90,6 +90,7 @@ public class LoanTransactionProcessingServiceImpl implements LoanTransactionProc new ChangedTransactionDetail(), savedModel.orElse(null), getTotalRefundInterestAmount(loan)); progressiveContext.getAlreadyProcessedTransactions().addAll(loanTransactionService.retrieveListOfTransactionsForReprocessing(loan)); progressiveContext.setChargedOff(loan.isChargedOff()); + progressiveContext.setContractTerminated(loan.isContractTermination()); ChangedTransactionDetail result = advancedProcessor.processLatestTransaction(loanTransaction, progressiveContext); if (savedModel.isPresent() && !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { modelRepository.writeInterestScheduleModel(loan, savedModel.get());
