From 3c4d8da1c8815565c293a2b916666a566c05e950 Mon Sep 17 00:00:00 2001 From: mariiaKraievska Date: Wed, 3 Dec 2025 11:32:38 +0200 Subject: [PATCH] FINERACT-2398: Re-amortization:- Interest handling-Default behavior --- .../features/LoanReAmortization.feature | 406 ++++++++++++++++++ ...edPaymentScheduleTransactionProcessor.java | 79 +++- .../loanproduct/calc/EMICalculator.java | 2 + .../calc/ProgressiveEMICalculator.java | 30 +- .../calc/data/RepaymentPeriod.java | 9 +- .../LoanReAmortizationCommandHandler.java | 4 +- .../LoanUndoReAmortizationCommandHandler.java | 4 +- ...pl.java => LoanReAmortizationService.java} | 44 +- 8 files changed, 532 insertions(+), 46 deletions(-) rename fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/{LoanReAmortizationServiceImpl.java => LoanReAmortizationService.java} (87%) diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature index 8dc6428ab..21046ed4b 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature @@ -696,3 +696,409 @@ Feature: LoanReAmortization | 21 February 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 700.0 | false | false | | 21 February 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 675.0 | true | false | + Scenario: Verify allowing Re-amortization on interest bearing loan - Interest calculation: Default Behavior - UC1 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 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 | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 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 "15 March 2024" + When When Admin creates a Loan re-amortization transaction on current business date + 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 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 63.23 | 20.34 | 0.98 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 4 | 30 | 01 May 2024 | | 42.28 | 20.95 | 0.37 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 5 | 31 | 01 June 2024 | | 21.21 | 21.07 | 0.25 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 6 | 30 | 01 July 2024 | | 0.0 | 21.21 | 0.12 | 0.0 | 0.0 | 21.33 | 0.0 | 0.0 | 0.0 | 21.33 | + 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.3 | 0.0 | 0.0 | 102.3 | 17.01 | 0.0 | 0.0 | 85.29 | + 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 | + | 15 March 2024 | Re-amortize | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify allowing Re-amortization on interest bearing loan - Interest calculation: Default Behavior - Principal and interest and Fees - UC2 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 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 | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 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 + When Admin sets the business date to "15 February 2024" + When Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 February 2024" due date and 10 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 | 10.0 | 0.0 | 27.01 | 0.0 | 0.0 | 0.0 | 27.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 | 10.0 | 0.0 | 112.05 | 17.01 | 0.0 | 0.0 | 95.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 | + And Loan Charges tab has the following data: + | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | + | Snooze fee | false | Specified due date | 15 February 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + When Admin sets the business date to "15 March 2024" + When When Admin creates a Loan re-amortization transaction on current business date + 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 | | 83.57 | 0.0 | 0.0 | 10.0 | 0.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 | + | 3 | 31 | 01 April 2024 | | 63.23 | 20.34 | 0.98 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 4 | 30 | 01 May 2024 | | 42.28 | 20.95 | 0.37 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 5 | 31 | 01 June 2024 | | 21.21 | 21.07 | 0.25 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 6 | 30 | 01 July 2024 | | 0.0 | 21.21 | 0.12 | 0.0 | 0.0 | 21.33 | 0.0 | 0.0 | 0.0 | 21.33 | + 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.3 | 10.0 | 0.0 | 112.3 | 17.01 | 0.0 | 0.0 | 95.29 | + 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 | + | 15 March 2024 | Re-amortize | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 0.0 | false | false | + And Loan Charges tab has the following data: + | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | + | Snooze fee | false | Specified due date | 15 February 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify allowing Re-amortization on interest bearing loan - Interest calculation: Default Behavior - N+1 Scenario - UC3 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 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 | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 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 + When Admin sets the business date to "15 July 2024" + When Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 July 2024" due date and 10 EUR transaction amount + Then Loan Repayment schedule has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 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 | + | 7 | 14 | 15 July 2024 | | 0.0 | 0.0 | 0.0 | 10.0 | 0.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.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 | 10.0 | 0.0 | 112.05 | 17.01 | 0.0 | 0.0 | 95.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | + When Admin sets the business date to "15 March 2024" + When When Admin creates a Loan re-amortization transaction on current business date + Then Loan Repayment schedule has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 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 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 63.23 | 20.34 | 0.98 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 4 | 30 | 01 May 2024 | | 42.28 | 20.95 | 0.37 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 5 | 31 | 01 June 2024 | | 21.21 | 21.07 | 0.25 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 6 | 30 | 01 July 2024 | | 0.0 | 21.21 | 0.12 | 0.0 | 0.0 | 21.33 | 0.0 | 0.0 | 0.0 | 21.33 | + | 7 | 14 | 15 July 2024 | | 0.0 | 0.0 | 0.0 | 10.0 | 0.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.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.3 | 10.0 | 0.0 | 112.3 | 17.01 | 0.0 | 0.0 | 95.29 | + 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 | + | 15 March 2024 | Re-amortize | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify allowing Re-amortization on interest bearing loan - Interest calculation: Default Behavior - Charge-back before re-aging - UC4 + 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_RECALC_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL | 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 | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 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 + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback 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.14 | 32.86 | 1.16 | 0.0 | 0.0 | 34.02 | 0.0 | 0.0 | 0.0 | 34.02 | + | 3 | 31 | 01 April 2024 | | 50.52 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.8 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.99 | 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.99 | 0.1 | 0.0 | 0.0 | 17.09 | 0.0 | 0.0 | 0.0 | 17.09 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.43 | 2.72 | 0.0 | 0.0 | 119.15 | 17.01 | 0.0 | 0.0 | 102.14 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | + | 01 February 2024 | Chargeback | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 100.0 | false | + When Admin sets the business date to "15 March 2024" + When When Admin creates a Loan re-amortization transaction on current business date + 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 | 15 March 2024 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 76.08 | 23.92 | 1.74 | 0.0 | 0.0 | 25.66 | 0.0 | 0.0 | 0.0 | 25.66 | + | 4 | 30 | 01 May 2024 | | 50.86 | 25.22 | 0.44 | 0.0 | 0.0 | 25.66 | 0.0 | 0.0 | 0.0 | 25.66 | + | 5 | 31 | 01 June 2024 | | 25.5 | 25.36 | 0.3 | 0.0 | 0.0 | 25.66 | 0.0 | 0.0 | 0.0 | 25.66 | + | 6 | 30 | 01 July 2024 | | 0.0 | 25.5 | 0.15 | 0.0 | 0.0 | 25.65 | 0.0 | 0.0 | 0.0 | 25.65 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.43 | 3.21 | 0.0 | 0.0 | 119.64 | 17.01 | 0.0 | 0.0 | 102.63 | + 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 February 2024 | Chargeback | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 100.0 | false | false | + | 15 March 2024 | Re-amortize | 34.02 | 32.86 | 1.16 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify allowing Re-amortization on interest bearing loan - Interest calculation: Default Behavior - Partially paid installment - UC5 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin set "LP2_ADV_CUSTOM_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 | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 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 | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 20.0 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.03 | 16.54 | 0.47 | 0.0 | 0.0 | 17.01 | 2.99 | 2.99 | 0.0 | 14.02 | + | 3 | 31 | 01 April 2024 | | 50.41 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.69 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.88 | 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.88 | 0.1 | 0.0 | 0.0 | 16.98 | 0.0 | 0.0 | 0.0 | 16.98 | + 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.03 | 0.0 | 0.0 | 102.03 | 20.0 | 2.99 | 0.0 | 82.03 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 February 2024 | Repayment | 20.0 | 19.42 | 0.58 | 0.0 | 0.0 | 80.58 | false | + When Admin sets the business date to "15 March 2024" + When When Admin creates a Loan re-amortization transaction on current business date + 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 | 15 March 2024 | 80.58 | 2.99 | 0.0 | 0.0 | 0.0 | 2.99 | 2.99 | 2.99 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 60.96 | 19.62 | 0.94 | 0.0 | 0.0 | 20.56 | 0.0 | 0.0 | 0.0 | 20.56 | + | 4 | 30 | 01 May 2024 | | 40.76 | 20.2 | 0.36 | 0.0 | 0.0 | 20.56 | 0.0 | 0.0 | 0.0 | 20.56 | + | 5 | 31 | 01 June 2024 | | 20.44 | 20.32 | 0.24 | 0.0 | 0.0 | 20.56 | 0.0 | 0.0 | 0.0 | 20.56 | + | 6 | 30 | 01 July 2024 | | 0.0 | 20.44 | 0.12 | 0.0 | 0.0 | 20.56 | 0.0 | 0.0 | 0.0 | 20.56 | + 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.24 | 0.0 | 0.0 | 102.24 | 20.0 | 2.99 | 0.0 | 82.24 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 20.0 | 19.42 | 0.58 | 0.0 | 0.0 | 80.58 | false | false | + | 15 March 2024 | Re-amortize | 14.02 | 13.55 | 0.47 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify allowing Re-amortization on interest bearing loan - Interest calculation: Default Behavior - DownPayment Scenarios - UC6 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin set "LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT" 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_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT | 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 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 3 | 29 | 01 March 2024 | | 50.29 | 12.39 | 0.37 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 4 | 31 | 01 April 2024 | | 37.82 | 12.47 | 0.29 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 5 | 30 | 01 May 2024 | | 25.28 | 12.54 | 0.22 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 6 | 31 | 01 June 2024 | | 12.67 | 12.61 | 0.15 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 7 | 30 | 01 July 2024 | | 0.0 | 12.67 | 0.07 | 0.0 | 0.0 | 12.74 | 0.0 | 0.0 | 0.0 | 12.74 | + 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 | 25.0 | 0.0 | 0.0 | 76.54 | + 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 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 12.76 EUR transaction amount + Then Loan Repayment schedule has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024| 01 February 2024 | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 12.76 | 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | | 50.29 | 12.39 | 0.37 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 4 | 31 | 01 April 2024 | | 37.82 | 12.47 | 0.29 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 5 | 30 | 01 May 2024 | | 25.28 | 12.54 | 0.22 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 6 | 31 | 01 June 2024 | | 12.67 | 12.61 | 0.15 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 7 | 30 | 01 July 2024 | | 0.0 | 12.67 | 0.07 | 0.0 | 0.0 | 12.74 | 0.0 | 0.0 | 0.0 | 12.74 | + 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 | 37.76 | 0.0 | 0.0 | 63.78 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + | 01 February 2024 | Repayment | 12.76 | 12.32 | 0.44 | 0.0 | 0.0 | 62.68 | false | false | + When Admin sets the business date to "15 March 2024" + When When Admin creates a Loan re-amortization transaction on current business date + Then Loan Repayment schedule has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | 01 February 2024 | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 12.76 | 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | 15 March 2024 | 62.68 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 4 | 31 | 01 April 2024 | | 47.43 | 15.25 | 0.74 | 0.0 | 0.0 | 15.99 | 0.0 | 0.0 | 0.0 | 15.99 | + | 5 | 30 | 01 May 2024 | | 31.72 | 15.71 | 0.28 | 0.0 | 0.0 | 15.99 | 0.0 | 0.0 | 0.0 | 15.99 | + | 6 | 31 | 01 June 2024 | | 15.92 | 15.8 | 0.19 | 0.0 | 0.0 | 15.99 | 0.0 | 0.0 | 0.0 | 15.99 | + | 7 | 30 | 01 July 2024 | | 0.0 | 15.92 | 0.09 | 0.0 | 0.0 | 16.01 | 0.0 | 0.0 | 0.0 | 16.01 | + 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.74 | 0.0 | 0.0 | 101.74 | 37.76 | 0.0 | 0.0 | 63.98 | + 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 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + | 01 February 2024 | Repayment | 12.76 | 12.32 | 0.44 | 0.0 | 0.0 | 62.68 | false | false | + | 15 March 2024 | Re-amortize | 12.76 | 12.39 | 0.37 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met \ No newline at end of file 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 556495036..b7034a255 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 @@ -96,6 +96,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepayme import org.apache.fineract.portfolio.loanaccount.domain.SingleLoanChargeRepaymentScheduleProcessingWrapper; import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeInterestHandlingType; import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter; +import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationParameter; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx; @@ -590,6 +591,42 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } private void handleReAmortization(LoanTransaction loanTransaction, TransactionCtx transactionCtx) { + final Loan loan = loanTransaction.getLoan(); + final LoanReAmortizationParameter loanReAmortizationParameter = loanTransaction.getLoanReAmortizationParameter(); + if (loan.isInterestBearing()) { + switch (loanReAmortizationParameter.getInterestHandlingType()) { + case DEFAULT -> handleReamortizationWithDefaultInterestHandlingType(loanTransaction, transactionCtx); + case WAIVE_INTEREST -> handleReamortizationWithWaiveInterestHandlingType(loanTransaction, transactionCtx); + case EQUAL_AMORTIZATION_INTEREST_SPLIT -> + handleReamortizationWithEqualAmortizationInterestSplitHandlingType(loanTransaction, transactionCtx); + } + } else { + reamortizationOnNonInterestBearingLoan(loanTransaction, transactionCtx); + } + } + + private void handleReamortizationWithEqualAmortizationInterestSplitHandlingType(LoanTransaction loanTransaction, + TransactionCtx transactionCtx) { + throw new UnsupportedOperationException( + "EQUAL_AMORTIZATION_INTEREST_SPLIT interest handling strategy for re-amortization is not implemented"); + } + + private void handleReamortizationWithWaiveInterestHandlingType(LoanTransaction loanTransaction, TransactionCtx transactionCtx) { + throw new UnsupportedOperationException("WAIVE_INTEREST interest handling strategy for re-amortization is not implemented"); + } + + private void handleReamortizationWithDefaultInterestHandlingType(LoanTransaction loanTransaction, TransactionCtx transactionCtx) { + // re-amortization logic for interest-bearing loans + if (transactionCtx instanceof ProgressiveTransactionCtx progressiveTransactionCtx + && loanTransaction.getLoan().isInterestBearingAndInterestRecalculationEnabled()) { + handleReAmortizationWithInterestRecalculationEnabled(loanTransaction, progressiveTransactionCtx); + } + // TODO: implement interestRecalculation = false logic + throw new UnsupportedOperationException( + "Logic for re-amortization when interest bearing loan has interestRecalculation disabled is not implemented"); + } + + private static void reamortizationOnNonInterestBearingLoan(LoanTransaction loanTransaction, TransactionCtx transactionCtx) { LocalDate transactionDate = loanTransaction.getTransactionDate(); List previousInstallments = transactionCtx.getInstallments().stream() // .filter(installment -> !installment.getDueDate().isAfter(transactionDate)) // @@ -634,6 +671,32 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } } + private void handleReAmortizationWithInterestRecalculationEnabled(final LoanTransaction loanTransaction, + final ProgressiveTransactionCtx ctx) { + final LocalDate transactionDate = loanTransaction.getTransactionDate(); + final MonetaryCurrency currency = ctx.getCurrency(); + + final List previousInstallments = ctx.getInstallments().stream() // + .filter(installment -> !installment.getDueDate().isAfter(transactionDate)) // + .toList(); + + Money totalOverDuePrincipal = Money.zero(currency); + for (LoanRepaymentScheduleInstallment installment : previousInstallments) { + final Money principalCompleted = installment.getPrincipalCompleted(currency); + totalOverDuePrincipal = totalOverDuePrincipal.add(installment.getPrincipal(currency).minus(principalCompleted)); + } + + final Money totalOverDueInterest = emiCalculator.getOutstandingInterestTillDate(ctx.getModel(), + previousInstallments.getLast().getDueDate()); + + loanTransaction.resetDerivedComponents(); + loanTransaction.updateComponentsAndTotal(totalOverDuePrincipal, totalOverDueInterest, Money.zero(currency), Money.zero(currency)); + + // Update the existing model with re-amortized periods + emiCalculator.updateModelRepaymentPeriodsDuringReAmortization(ctx.getModel(), transactionDate); + updateInstallmentsByRepaymentPeriods(loanTransaction, ctx); + } + @Override protected void handleChargeback(LoanTransaction loanTransaction, TransactionCtx ctx) { processCreditTransaction(loanTransaction, ctx); @@ -671,12 +734,12 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep if (!currentInstallment.isAdditional() && DateUtils.isAfter(currentInstallment.getDueDate(), transactionDate)) { emiCalculator.creditPrincipal(model, transactionDate, transactionAmount); - updateRepaymentPeriods(loanTransaction, progressiveTransactionCtx); + updateInstallmentsByRepaymentPeriods(loanTransaction, progressiveTransactionCtx); if (repaidAmount.isGreaterThanZero()) { emiCalculator.payPrincipal(model, currentInstallment.getFromDate(), currentInstallment.getDueDate(), transactionDate, repaidAmount); - updateRepaymentPeriods(loanTransaction, progressiveTransactionCtx); + updateInstallmentsByRepaymentPeriods(loanTransaction, progressiveTransactionCtx); currentInstallment.payPrincipalComponent(transactionDate, repaidAmount); transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment, repaidAmount, zeroMoney, zeroMoney, zeroMoney)); @@ -709,12 +772,12 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep LoanRepaymentScheduleInstallment currentInstallment = installmentToBeProcessed.getLast(); emiCalculator.creditPrincipal(model, transactionDate, transactionAmount); - updateRepaymentPeriods(loanTransaction, progressiveTransactionCtx); + updateInstallmentsByRepaymentPeriods(loanTransaction, progressiveTransactionCtx); if (repaidAmount.isGreaterThanZero()) { emiCalculator.payPrincipal(model, currentInstallment.getFromDate(), currentInstallment.getDueDate(), transactionDate, repaidAmount); - updateRepaymentPeriods(loanTransaction, progressiveTransactionCtx); + updateInstallmentsByRepaymentPeriods(loanTransaction, progressiveTransactionCtx); currentInstallment.payPrincipalComponent(transactionDate, repaidAmount); transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment, repaidAmount, zeroMoney, zeroMoney, zeroMoney)); @@ -866,7 +929,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } // update repayment periods until maturity date, for principal and interest portions - updateRepaymentPeriods(loanTransaction, ctx); + updateInstallmentsByRepaymentPeriods(loanTransaction, ctx); // search last instalment if transaction is posted on last installment's due date // otherwise search installment where transaction date is in from date (inclusive) to due date (exclusive) @@ -2589,15 +2652,15 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep if (PRINCIPAL.equals(paymentAllocationType.getAllocationType())) { emiCalculator.payPrincipal(model, installment.getFromDate(), installment.getDueDate(), payDate, paidPortion); - updateRepaymentPeriods(loanTransaction, ctx); + updateInstallmentsByRepaymentPeriods(loanTransaction, ctx); } else if (INTEREST.equals(paymentAllocationType.getAllocationType())) { emiCalculator.payInterest(model, installment.getFromDate(), installment.getDueDate(), payDate, paidPortion); - updateRepaymentPeriods(loanTransaction, ctx); + updateInstallmentsByRepaymentPeriods(loanTransaction, ctx); } return paidPortion; } - private void updateRepaymentPeriods(LoanTransaction loanTransaction, ProgressiveTransactionCtx ctx) { + private void updateInstallmentsByRepaymentPeriods(LoanTransaction loanTransaction, ProgressiveTransactionCtx ctx) { ctx.getModel().repaymentPeriods().forEach(rm -> { LoanRepaymentScheduleInstallment installment = ctx.getInstallments().stream().filter( ri -> ri.getFromDate().equals(rm.getFromDate()) && ri.getDueDate().equals(rm.getDueDate()) && !ri.isDownPayment()) diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java index d35f1c8bb..01e5716e9 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java @@ -170,4 +170,6 @@ public interface EMICalculator { void changeDueDate(ProgressiveLoanInterestScheduleModel scheduleModel, LoanApplicationTerms loanApplicationTerms, LocalDate targetRepaymentPeriodDueDate, LocalDate newDueDate); + + void updateModelRepaymentPeriodsDuringReAmortization(ProgressiveLoanInterestScheduleModel model, LocalDate transactionDate); } diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java index 95593fd9c..21a9af44c 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java @@ -570,7 +570,7 @@ public final class ProgressiveEMICalculator implements EMICalculator { public void updateModelRepaymentPeriodsDuringReAge(final ProgressiveLoanInterestScheduleModel scheduleModel, final LocalDate reAgePeriodStartDate, final LocalDate reAgeFirstDueDate, final LocalDate targetDate, final LoanApplicationTerms loanApplicationTerms, final MathContext mc) { - moveOutstandingAmountsFromPeriodsBeforeReAging(scheduleModel.repaymentPeriods(), targetDate); + moveOutstandingAmountsFromPeriodsBeforeTransactionDate(scheduleModel.repaymentPeriods(), targetDate); // calculate already paid balances from transaction date final OutstandingDetails paidBalancesFromTransactionDate = calculatePaidBalancesAfterDate(scheduleModel, targetDate); @@ -673,6 +673,18 @@ public final class ProgressiveEMICalculator implements EMICalculator { calculateLastUnpaidRepaymentPeriodEMI(scheduleModel, targetRepaymentPeriodDueDate); } + @Override + public void updateModelRepaymentPeriodsDuringReAmortization(final ProgressiveLoanInterestScheduleModel model, + final LocalDate transactionDate) { + moveOutstandingAmountsFromPeriodsBeforeTransactionDate(model.repaymentPeriods(), transactionDate); + final List reAmortizedPeriods = model.repaymentPeriods().stream() + .filter(rp -> rp.getDueDate().isAfter(transactionDate)).toList(); + calculateEMIOnActualModel(reAmortizedPeriods, model); + calculateOutstandingBalance(model); + calculateLastUnpaidRepaymentPeriodEMI(model, transactionDate); + checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(model, reAmortizedPeriods); + } + private LocalDate calculateDateForFixedLength(final ProgressiveLoanInterestScheduleModel scheduleModel, final LoanApplicationTerms loanApplicationTerms, final LocalDate targetRepaymentPeriodDueDate, final LocalDate newDueDate) { final long variationDays = DateUtils.getDifferenceInDays(targetRepaymentPeriodDueDate, newDueDate); @@ -825,16 +837,16 @@ public final class ProgressiveEMICalculator implements EMICalculator { } /** - * * Zeroing out the EMI of the repayment periods, that are before re-aging and not been fully paid. And decreases - * the balance correction amount (added during interest recalculation for the business date) by the amount of the - * principal that was moved. + * * Zeroing out the EMI of the repayment periods, that are before the transaction date and not been fully paid. And + * decreases the balance correction amount (added during interest recalculation for the business date) by the amount + * of the principal that was moved. */ - private static void moveOutstandingAmountsFromPeriodsBeforeReAging(final List existingRepaymentPeriods, + private static void moveOutstandingAmountsFromPeriodsBeforeTransactionDate(final List existingRepaymentPeriods, final LocalDate transactionDate) { - final List periodsBeforeReAging = existingRepaymentPeriods.stream() + final List periodsBeforeTransactionDate = existingRepaymentPeriods.stream() .filter(rp -> !rp.getFromDate().isAfter(transactionDate) && !rp.isFullyPaid()).toList(); - periodsBeforeReAging.forEach(rp -> { + periodsBeforeTransactionDate.forEach(rp -> { rp.getInterestPeriods().stream().filter(ip -> ip.getDueDate().isEqual(transactionDate)).forEach(ip -> { if (!ip.getBalanceCorrectionAmount().isZero()) { ip.addBalanceCorrectionAmount(ip.getBalanceCorrectionAmount().negated()); @@ -845,7 +857,7 @@ public final class ProgressiveEMICalculator implements EMICalculator { lastInterestPeriod.addBalanceCorrectionAmount(rp.getOutstandingPrincipal().negated()); } rp.setEmi(rp.getTotalPaidAmount()); - rp.setOutstandingMovedDueToReAging(true); + rp.setOutstandingMoved(true); }); } @@ -1725,7 +1737,7 @@ public final class ProgressiveEMICalculator implements EMICalculator { rp.getInterestPeriods().getLast() .addCreditedInterestAmount(MathUtil.min(rp.getOutstandingInterest(), rp.getCreditedInterest(), false).negated()); rp.setEmi(rp.getTotalPaidAmount()); - rp.setOutstandingMovedDueToReAging(true); + rp.setOutstandingMoved(true); }); // stop calculate unrecognised interest at this point because all 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 2520cdf67..61b9bb7d6 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 @@ -91,7 +91,7 @@ public class RepaymentPeriod { @Getter @Setter - private boolean isOutstandingMovedDueToReAging = false; + private boolean isOutstandingMoved = false; @Setter @Getter @@ -148,7 +148,7 @@ public class RepaymentPeriod { repaymentPeriod.getPaidPrincipal(), repaymentPeriod.getPaidInterest(), repaymentPeriod.getFutureUnrecognizedInterest(), mc, repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isNoUnrecognisedInterest(), repaymentPeriod.isReAged(), repaymentPeriod.isReAgedEarlyRepaymentHolder(), repaymentPeriod.getReAgedInterest()); - newRepaymentPeriod.setOutstandingMovedDueToReAging(repaymentPeriod.isOutstandingMovedDueToReAging()); + newRepaymentPeriod.setOutstandingMoved(repaymentPeriod.isOutstandingMoved()); // There is always at least 1 interest period, by default with same from-due date as repayment period for (InterestPeriod interestPeriod : repaymentPeriod.getInterestPeriods()) { newRepaymentPeriod.getInterestPeriods().add(InterestPeriod.copy(newRepaymentPeriod, interestPeriod, mc)); @@ -162,7 +162,7 @@ public class RepaymentPeriod { repaymentPeriod.getDueDate(), new ArrayList<>(), repaymentPeriod.getEmi(), repaymentPeriod.getOriginalEmi(), zero, zero, zero, mc, repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isNoUnrecognisedInterest(), repaymentPeriod.isReAged(), repaymentPeriod.isReAgedEarlyRepaymentHolder(), repaymentPeriod.getReAgedInterest()); - newRepaymentPeriod.setOutstandingMovedDueToReAging(repaymentPeriod.isOutstandingMovedDueToReAging()); + newRepaymentPeriod.setOutstandingMoved(repaymentPeriod.isOutstandingMoved()); // There is always at least 1 interest period, by default with same from-due date as repayment period for (InterestPeriod interestPeriod : repaymentPeriod.getInterestPeriods()) { var interestPeriodCopy = InterestPeriod.copy(newRepaymentPeriod, interestPeriod); @@ -311,8 +311,7 @@ public class RepaymentPeriod { * @return */ public Money getTotalCreditedAmount() { - return isOutstandingMovedDueToReAging ? Money.zero(getCurrency(), getMc()) - : getCreditedPrincipal().plus(getCreditedInterest(), getMc()); + return isOutstandingMoved ? Money.zero(getCurrency(), getMc()) : getCreditedPrincipal().plus(getCreditedInterest(), getMc()); } /** diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reamortization/LoanReAmortizationCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reamortization/LoanReAmortizationCommandHandler.java index 50dc537b7..83b0ee6f9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reamortization/LoanReAmortizationCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reamortization/LoanReAmortizationCommandHandler.java @@ -24,7 +24,7 @@ import org.apache.fineract.commands.handler.NewCommandSourceHandler; import org.apache.fineract.infrastructure.DataIntegrityErrorHandler; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.loanaccount.service.reamortization.LoanReAmortizationServiceImpl; +import org.apache.fineract.portfolio.loanaccount.service.reamortization.LoanReAmortizationService; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.jpa.JpaSystemException; import org.springframework.stereotype.Service; @@ -34,7 +34,7 @@ import org.springframework.stereotype.Service; @CommandType(entity = "LOAN", action = "REAMORTIZE") public class LoanReAmortizationCommandHandler implements NewCommandSourceHandler { - private final LoanReAmortizationServiceImpl loanReAmortizationService; + private final LoanReAmortizationService loanReAmortizationService; private final DataIntegrityErrorHandler dataIntegrityErrorHandler; @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reamortization/LoanUndoReAmortizationCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reamortization/LoanUndoReAmortizationCommandHandler.java index 02012e192..d9d94c7ac 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reamortization/LoanUndoReAmortizationCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reamortization/LoanUndoReAmortizationCommandHandler.java @@ -24,7 +24,7 @@ import org.apache.fineract.commands.handler.NewCommandSourceHandler; import org.apache.fineract.infrastructure.DataIntegrityErrorHandler; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.loanaccount.service.reamortization.LoanReAmortizationServiceImpl; +import org.apache.fineract.portfolio.loanaccount.service.reamortization.LoanReAmortizationService; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.jpa.JpaSystemException; import org.springframework.stereotype.Service; @@ -34,7 +34,7 @@ import org.springframework.stereotype.Service; @CommandType(entity = "LOAN", action = "UNDO_REAMORTIZE") public class LoanUndoReAmortizationCommandHandler implements NewCommandSourceHandler { - private final LoanReAmortizationServiceImpl loanReAmortizationService; + private final LoanReAmortizationService loanReAmortizationService; private final DataIntegrityErrorHandler dataIntegrityErrorHandler; @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java similarity index 87% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationServiceImpl.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java index a64e324a7..e405ec119 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java @@ -24,6 +24,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.util.Comparator; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.codes.domain.CodeValue; @@ -43,17 +44,14 @@ import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.api.LoanReAmortizationApiConstants; import org.apache.fineract.portfolio.loanaccount.domain.Loan; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationInterestHandlingType; import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationParameter; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder; -import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx; import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator; import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler; +import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService; import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -61,37 +59,31 @@ import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @Transactional -public class LoanReAmortizationServiceImpl { +public class LoanReAmortizationService { private final LoanAssembler loanAssembler; private final LoanReAmortizationValidator reAmortizationValidator; private final ExternalIdFactory externalIdFactory; private final BusinessEventNotifierService businessEventNotifierService; private final LoanTransactionRepository loanTransactionRepository; - private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; private final LoanChargeValidator loanChargeValidator; private final ReprocessLoanTransactionsService reprocessLoanTransactionsService; private final CodeValueRepository codeValueRepository; + private final LoanScheduleService loanScheduleService; - public CommandProcessingResult reAmortize(Long loanId, JsonCommand command) { - Loan loan = loanAssembler.assembleFrom(loanId); + public CommandProcessingResult reAmortize(final Long loanId, final JsonCommand command) { + final Loan loan = loanAssembler.assembleFrom(loanId); reAmortizationValidator.validateReAmortize(loan, command); - Map changes = new LinkedHashMap<>(); + final LoanTransaction reAmortizeTransaction = createReAmortizeTransaction(loan, command); + reAmortizeTransaction.setLoanReAmortizationParameter(createReAmortizationParameter(reAmortizeTransaction, command)); + processReAmortizationTransaction(loan, reAmortizeTransaction); + loanTransactionRepository.saveAndFlush(reAmortizeTransaction); + + final Map changes = new LinkedHashMap<>(); changes.put(LoanReAmortizationApiConstants.localeParameterName, command.locale()); changes.put(LoanReAmortizationApiConstants.dateFormatParameterName, command.dateFormat()); - LoanTransaction reAmortizeTransaction = createReAmortizeTransaction(loan, command); - - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory - .determineProcessor(loan.transactionProcessingStrategy()); - loanRepaymentScheduleTransactionProcessor.processLatestTransaction(reAmortizeTransaction, new TransactionCtx(loan.getCurrency(), - loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(), new MoneyHolder(loan.getTotalOverpaidAsMoney()), null)); - - reAmortizeTransaction.setLoanReAmortizationParameter(createReAmortizationParameter(reAmortizeTransaction, command)); - - loanTransactionRepository.saveAndFlush(reAmortizeTransaction); - // delinquency recalculation will be triggered by the event in a decoupled way via a listener businessEventNotifierService.notifyPostBusinessEvent(new LoanReAmortizeBusinessEvent(loan)); businessEventNotifierService.notifyPostBusinessEvent(new LoanReAmortizeTransactionBusinessEvent(reAmortizeTransaction)); @@ -118,6 +110,9 @@ public class LoanReAmortizationServiceImpl { if (reAmortizeTransaction == null) { // TODO: when validations implemented; throw exception if there isn't a reamortize transaction available } + if (loan.isProgressiveSchedule()) { + loanScheduleService.regenerateRepaymentSchedule(loan); + } reverseReAmortizeTransaction(reAmortizeTransaction, command); loanTransactionRepository.saveAndFlush(reAmortizeTransaction); @@ -183,4 +178,13 @@ public class LoanReAmortizationServiceImpl { return new LoanReAmortizationParameter(reAmortizationTransaction, reAmortizationInterestHandlingType, reasonCodeValue); } + + private void processReAmortizationTransaction(final Loan loan, final LoanTransaction reAmortizationTransaction) { + if (loan.isInterestBearingAndInterestRecalculationEnabled()) { + loanScheduleService.regenerateRepaymentSchedule(loan); + reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(reAmortizationTransaction)); + } else { + reprocessLoanTransactionsService.processLatestTransaction(reAmortizationTransaction, loan); + } + } }