This is an automated email from the ASF dual-hosted git repository. arnold pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract.git
commit 8610368a18c9bedb5593a3fb28a2928a7d0e38ec Author: Oleksii Novikov <[email protected]> AuthorDate: Thu Dec 18 14:24:47 2025 +0200 FINERACT-2181: Improve validation for reschedule fromDate parameter --- .../test/data/LoanRescheduleErrorMessage.java | 2 ++ .../test/resources/features/LoanReschedule.feature | 24 +++++++++++++++++++++- ...gressiveLoanRescheduleRequestDataValidator.java | 6 ++++-- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanRescheduleErrorMessage.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanRescheduleErrorMessage.java index f14725ce58..67da5f5125 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanRescheduleErrorMessage.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanRescheduleErrorMessage.java @@ -22,6 +22,8 @@ public enum LoanRescheduleErrorMessage { LOAN_CHARGED_OFF("Loan: %s reschedule installment is not allowed. Loan Account is Charged-off"), // LOAN_RESCHEDULE_DATE_NOT_IN_FUTURE("Loan Reschedule From date (%s) for Loan: %s should be in the future."), // + LOAN_RESCHEDULE_FROM_DATE_INSTALLMENT_NOT_FOUND( + "Validation errors: [rescheduleFromDate] Failed data validation due to: repayment.schedule.installment.does.not.exist."), // LOAN_LOCKED_BY_COB("Loan is locked by the COB job. Loan ID: %s"), // LOAN_RESCHEDULE_NOT_ALLOWED_FROM_ZERO_TO_NEW_INTEREST_RATE("Failed data validation due to: newInterestRate."), // LOAN_RESCHEDULE_NOT_ALLOWED_FROM_CURRENT_INTEREST_RATE_TO_ZERO("The parameter `newInterestRate` must be greater than 0."), // diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature index eb8a5e45fa..0454408d7e 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature @@ -1432,4 +1432,26 @@ Feature: LoanReschedule | 3 | 43 | 15 March 2024 | | 45.56 | 14.67 | 0.69 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | | 4 | 31 | 15 April 2024 | | 30.56 | 15.0 | 0.36 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | | 5 | 30 | 15 May 2024 | | 15.44 | 15.12 | 0.24 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | - | 6 | 31 | 15 June 2024 | | 0.0 | 15.44 | 0.12 | 0.0 | 0.0 | 15.56 | 0.0 | 0.0 | 0.0 | 15.56 | \ No newline at end of file + | 6 | 31 | 15 June 2024 | | 0.0 | 15.44 | 0.12 | 0.0 | 0.0 | 15.56 | 0.0 | 0.0 | 0.0 | 15.56 | + + Scenario: Verify Progressive Loan reschedule with non-existing installment due date results in validation error + 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" + 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 | + When Admin sets the business date to "02 April 2024" + Then Loan reschedule with the following data results a 400 error and "LOAN_RESCHEDULE_FROM_DATE_INSTALLMENT_NOT_FOUND" error message + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 01 August 2024 | 02 April 2024 | | | | 2 | | \ No newline at end of file diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/ProgressiveLoanRescheduleRequestDataValidator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/ProgressiveLoanRescheduleRequestDataValidator.java index 33c5d216c0..20f14807e1 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/ProgressiveLoanRescheduleRequestDataValidator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/ProgressiveLoanRescheduleRequestDataValidator.java @@ -94,7 +94,7 @@ public class ProgressiveLoanRescheduleRequestDataValidator implements LoanResche } if (hasExtraTermsChange) { - validateExtraTerms(dataValidatorBuilder, loan); + validateExtraTerms(dataValidatorBuilder, loan, rescheduleFromDate); } else if (hasAdjustDueDateChange) { validateAdjustDueDateChange(dataValidatorBuilder, loan, rescheduleFromDate); } else if (hasInterestRateChange) { @@ -124,8 +124,10 @@ public class ProgressiveLoanRescheduleRequestDataValidator implements LoanResche validateForOverdueCharges(dataValidatorBuilder, loan, installment); } - private void validateExtraTerms(DataValidatorBuilder dataValidatorBuilder, Loan loan) { + private void validateExtraTerms(DataValidatorBuilder dataValidatorBuilder, Loan loan, LocalDate rescheduleFromDate) { validateLoanIsActive(loan, dataValidatorBuilder); + final LoanRepaymentScheduleInstallment installment = loan.getRelatedRepaymentScheduleInstallment(rescheduleFromDate); + validateReschedulingInstallment(dataValidatorBuilder, installment); } private Integer validateExtraTermsParam(FromJsonHelper fromJsonHelper, JsonElement jsonElement,
