FINERACT-2413: Improve re-amortization undo validation

This commit is contained in:
Oleksii Novikov
2025-12-23 11:12:41 +01:00
committed by Arnold Gálovics
parent b457b2aa93
commit 2858316c71
5 changed files with 182 additions and 79 deletions
@@ -93,7 +93,7 @@ public class LoanReAmortizationStepDef extends AbstractStepDef {
testContext().set(TestContextKey.LOAN_REAMORTIZATION_RESPONSE, response);
}
@When("When Admin undo Loan re-amortization transaction on current business date")
@When("Admin undo Loan re-amortization transaction on current business date")
public void undoLoanReAmortization() {
PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
long loanId = loanResponse.getLoanId();
@@ -113,7 +113,7 @@ Feature: LoanReAmortization
| 01 January 2024 | Down Payment | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 375.0 | false |
| 25 January 2024 | Re-amortize | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 0.0 | false |
When Admin sets the business date to "26 January 2024"
When When Admin undo Loan re-amortization transaction on current business date
When Admin undo Loan re-amortization transaction on current business date
Then Loan Repayment schedule has 4 periods, with the following data for periods:
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| | | 01 January 2024 | | 500.0 | | | 0.0 | | 0.0 | 0.0 | | | |
@@ -673,7 +673,7 @@ Feature: LoanReAmortization
| 21 February 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 675.0 | true | false |
# --- Undo re-amortization ---
When Admin sets the business date to "23 February 2024"
And When Admin undo Loan re-amortization transaction on current business date
And Admin undo 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 | | 800.0 | | | 0.0 | | 0.0 | 0.0 | | | |
@@ -2002,4 +2002,169 @@ Feature: LoanReAmortization
| 15 March 2024 | Re-amortize | 4.02 | 3.61 | 0.41 | 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
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
Scenario: Verify Re-amortization reversal on interest bearing loan - Interest calculation: Default Behavior - UC8
When Admin sets the business date to "01 January 2024"
When Admin creates a client with random data
When Admin creates a fully customized loan with the following data:
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
| LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_NO_CALC_ON_PAST_DUE_TILL_PRECLOSE | 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"
And 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 Admin sets the business date to "1 April 2024"
When Admin undo 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 | | 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 |
| 15 March 2024 | Re-amortize | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 0.0 | true | 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 Re-amortization reversal on interest bearing loan - Interest handling: EQUAL_AMORTIZATION_INTEREST_SPLIT - UC8
When Admin sets the business date to "01 January 2024"
And Admin creates a client with random data
And Admin creates a fully customized loan with the following data:
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
| LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_NO_CALC_ON_PAST_DUE_TILL_PRECLOSE | 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"
And 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 |
And 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 |
And 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 |
# --- Repayment on due date ---
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 |
And 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 |
And 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 |
# --- Re-amortization transaction ---
When Admin sets the business date to "15 March 2024"
And Admin creates a Loan re-amortization transaction on current business date with reAmortizationInterestHandling "EQUAL_AMORTIZATION_INTEREST_SPLIT"
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 | | 62.86 | 20.71 | 0.61 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 |
| 4 | 30 | 01 May 2024 | | 42.03 | 20.83 | 0.49 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 |
| 5 | 31 | 01 June 2024 | | 21.08 | 20.95 | 0.37 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 |
| 6 | 30 | 01 July 2024 | | 0.0 | 21.08 | 0.24 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 |
And Loan Repayment schedule has the following data in Total row:
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| 100.0 | 2.29 | 0.0 | 0.0 | 102.29 | 17.01 | 0.0 | 0.0 | 85.28 |
And 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 Admin sets the business date to "1 April 2024"
When Admin undo 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 | | 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 |
And 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 |
| 15 March 2024 | Re-amortize | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 0.0 | true | false |
@@ -115,16 +115,12 @@ public class LoanReAmortizationService {
public CommandProcessingResult undoReAmortize(Long loanId, JsonCommand command) {
Loan loan = loanAssembler.assembleFrom(loanId);
reAmortizationValidator.validateUndoReAmortize(loan, command);
final LoanTransaction reAmortizeTransaction = reAmortizationValidator.findAndValidateReAmortizeTransactionForUndo(loan);
Map<String, Object> changes = new LinkedHashMap<>();
changes.put(LoanReAmortizationApiConstants.localeParameterName, command.locale());
changes.put(LoanReAmortizationApiConstants.dateFormatParameterName, command.dateFormat());
LoanTransaction reAmortizeTransaction = findLatestNonReversedReAmortizeTransaction(loan);
if (reAmortizeTransaction == null) {
// TODO: when validations implemented; throw exception if there isn't a reamortize transaction available
}
if (loan.isProgressiveSchedule()) {
loanScheduleService.regenerateRepaymentSchedule(loan);
}
@@ -185,14 +181,6 @@ public class LoanReAmortizationService {
reprocessLoanTransactionsService.reprocessTransactions(loan);
}
private LoanTransaction findLatestNonReversedReAmortizeTransaction(Loan loan) {
return loan.getLoanTransactions().stream() //
.filter(LoanTransaction::isNotReversed) //
.filter(LoanTransaction::isReAmortize) //
.max(Comparator.comparing(LoanTransaction::getTransactionDate)) //
.orElse(null);
}
private LoanTransaction createReAmortizeTransaction(Loan loan, JsonCommand command) {
ExternalId txExternalId = externalIdFactory.createFromCommand(command, LoanReAmortizationApiConstants.externalIdParameterName);
@@ -21,7 +21,6 @@ package org.apache.fineract.portfolio.loanaccount.service.reamortization;
import static org.apache.fineract.infrastructure.core.service.DateUtils.getBusinessLocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
@@ -39,7 +38,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationInterestHandlingType;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.ChangeOperation;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.springframework.stereotype.Component;
@@ -123,26 +121,18 @@ public class LoanReAmortizationValidator {
}
}
public void validateUndoReAmortize(Loan loan, JsonCommand command) {
validateUndoReAmortizeBusinessRules(loan);
}
private void validateUndoReAmortizeBusinessRules(Loan loan) {
// validate if there's a reamortization transaction already
Optional<LoanTransaction> optionalReAmortizationTx = loan.getLoanTransactions().stream().filter(tx -> tx.getTypeOf().isReAmortize())
.min(Comparator.comparing(LoanTransaction::getTransactionDate));
public LoanTransaction findAndValidateReAmortizeTransactionForUndo(Loan loan) {
// validate if there's a non-reversed reamortization transaction already
final Optional<LoanTransaction> optionalReAmortizationTx = loan.getLoanTransactions().stream() //
.filter(LoanTransaction::isNotReversed) //
.filter(tx -> tx.getTypeOf().isReAmortize()) //
.findAny();
if (optionalReAmortizationTx.isEmpty()) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.reamortize.reamortization.transaction.missing",
"Undoing a reamortization can only be done if there was a reamortization already", loan.getId());
"Undoing a reamortization can only be done if there was a non-reversed reamortization already", loan.getId());
}
// validate if there's no payment between the reamortization and today
boolean repaymentExistsAfterReAmortization = loan.getLoanTransactions().stream().anyMatch(tx -> tx.getTypeOf().isRepaymentType()
&& !tx.isReversed() && transactionHappenedAfterOther(tx, optionalReAmortizationTx.get()));
if (repaymentExistsAfterReAmortization) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.reamortize.repayment.exists.after.reamortization",
"Undoing a reamortization can only be done if there hasn't been any repayment afterwards", loan.getId());
}
return optionalReAmortizationTx.get();
}
private void throwExceptionIfValidationErrorsExist(List<ApiParameterError> dataValidationErrors) {
@@ -152,7 +142,4 @@ public class LoanReAmortizationValidator {
}
}
private boolean transactionHappenedAfterOther(LoanTransaction transaction, LoanTransaction otherTransaction) {
return new ChangeOperation(transaction).compareTo(new ChangeOperation(otherTransaction)) > 0;
}
}
@@ -185,53 +185,16 @@ class LoanReAmortizationValidatorTest {
List<LoanTransaction> transactions = List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, actualDate.minusDays(3)));
Loan loan = loan();
given(loan.getLoanTransactions()).willReturn(transactions);
JsonCommand command = jsonCommand();
// when
GeneralPlatformDomainRuleException result = assertThrows(GeneralPlatformDomainRuleException.class,
() -> underTest.validateUndoReAmortize(loan, command));
() -> underTest.findAndValidateReAmortizeTransactionForUndo(loan));
// then
assertThat(result).isNotNull();
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.reamortization.transaction.missing");
}
@Test
public void testValidateUndoReAmortize_ShouldThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization() {
// given
List<LoanTransaction> transactions = List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, actualDate.minusDays(3)),
loanTransaction(LoanTransactionType.REAMORTIZE, actualDate.minusDays(2)),
loanTransaction(LoanTransactionType.REPAYMENT, actualDate.minusDays(1)));
Loan loan = loan();
given(loan.getLoanTransactions()).willReturn(transactions);
JsonCommand command = jsonCommand();
// when
GeneralPlatformDomainRuleException result = assertThrows(GeneralPlatformDomainRuleException.class,
() -> underTest.validateUndoReAmortize(loan, command));
// then
assertThat(result).isNotNull();
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.repayment.exists.after.reamortization");
}
@Test
public void testValidateUndoReAmortize_ShouldThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization_SameDay() {
// given
List<LoanTransaction> transactions = List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, actualDate.minusDays(2)),
loanTransaction(LoanTransactionType.REAMORTIZE, actualDate.minusDays(1),
OffsetDateTime.of(actualDate, LocalTime.of(10, 0), ZoneOffset.UTC)),
loanTransaction(LoanTransactionType.REPAYMENT, actualDate.minusDays(1),
OffsetDateTime.of(actualDate, LocalTime.of(11, 0), ZoneOffset.UTC)));
Loan loan = loan();
given(loan.getLoanTransactions()).willReturn(transactions);
JsonCommand command = jsonCommand();
// when
GeneralPlatformDomainRuleException result = assertThrows(GeneralPlatformDomainRuleException.class,
() -> underTest.validateUndoReAmortize(loan, command));
// then
assertThat(result).isNotNull();
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.repayment.exists.after.reamortization");
}
@Test
public void testValidateUndoReAmortize_ShouldNotThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization_SameDay_RepaymentBeforeReAmortization() {
public void testValidateUndoReAmortize_ShouldNotThrowException() {
// given
List<LoanTransaction> transactions = List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, actualDate.minusDays(2)),
loanTransaction(LoanTransactionType.REAMORTIZE, actualDate.minusDays(1),
@@ -240,9 +203,8 @@ class LoanReAmortizationValidatorTest {
OffsetDateTime.of(actualDate, LocalTime.of(9, 0), ZoneOffset.UTC)));
Loan loan = loan();
given(loan.getLoanTransactions()).willReturn(transactions);
JsonCommand command = jsonCommand();
// when
underTest.validateUndoReAmortize(loan, command);
underTest.findAndValidateReAmortizeTransactionForUndo(loan);
// then no exception thrown
}
@@ -271,6 +233,7 @@ class LoanReAmortizationValidatorTest {
given(loanTransaction.getTypeOf()).willReturn(type);
given(loanTransaction.getTransactionDate()).willReturn(txDate);
given(loanTransaction.getSubmittedOnDate()).willReturn(txDate);
given(loanTransaction.isNotReversed()).willReturn(true);
return loanTransaction;
}