This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 3687391148 FINERACT-2221: Add immediate charge accrual post maturity
for progressive loans
3687391148 is described below
commit 36873911485e6f6dad0d7565d89d20527e886989
Author: Oleksii Novikov <[email protected]>
AuthorDate: Mon Apr 21 14:04:52 2025 +0300
FINERACT-2221: Add immediate charge accrual post maturity for progressive
loans
---
.../src/test/resources/features/LoanCharge.feature | 50 ++++++++++++++++++++--
.../portfolio/loanaccount/domain/Loan.java | 5 +++
.../LoanChargeWritePlatformServiceImpl.java | 10 +++--
.../LoanChargeWritePlatformServiceImplTest.java | 1 +
.../LoanChargeProgressiveTest.java | 2 +-
5 files changed, 61 insertions(+), 7 deletions(-)
diff --git
a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
index 9e33a7a89d..2886bb482d 100644
--- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
+++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
@@ -2292,8 +2292,9 @@ Feature: LoanCharge
Then Loan Transactions tab has the following data:
| Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance |
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 |
0.0 | 0.0 | 1000.0 |
+ | 05 February 2024 | Accrual | 25.0 | 0.0 | 0.0 |
0.0 | 25.0 | 0.0 |
Given Global configuration "enable-immediate-charge-accrual-post-maturity"
is disabled
- Then LoanAccrualTransactionCreatedBusinessEvent is not raised on "05
February 2024"
+ Then LoanAccrualTransactionCreatedBusinessEvent is raised on "05 February
2024"
@TestRailId:C3320
Scenario: Verify enhance the existing implementation to create accruals as
part of Charge Creation post maturity with immediate charge accrual and zero
interest rate
@@ -2331,8 +2332,9 @@ Feature: LoanCharge
Then Loan Transactions tab has the following data:
| Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance |
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 |
0.0 | 0.0 | 1000.0 |
+ | 05 February 2024 | Accrual | 25.0 | 0.0 | 0.0 |
0.0 | 25.0 | 0.0 |
Given Global configuration "enable-immediate-charge-accrual-post-maturity"
is disabled
- Then LoanAccrualTransactionCreatedBusinessEvent is not raised on "05
February 2024"
+ Then LoanAccrualTransactionCreatedBusinessEvent is raised on "05 February
2024"
@TestRailId:ะก3335
Scenario: Verify enhance the existing implementation to create accruals as
part of Charge Creation post maturity with inline COB run and non-zero interest
rate
@@ -2454,7 +2456,8 @@ Feature: LoanCharge
Then Loan Transactions tab has the following data:
| Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance |
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 |
0.0 | 0.0 | 1000.0 |
- | 05 February 2024 | Accrual | 30.83 | 0.0 | 5.83 |
0.0 | 25.0 | 0.0 |
+ | 05 February 2024 | Accrual | 25.0 | 0.0 | 0.0 |
0.0 | 25.0 | 0.0 |
+ | 05 February 2024 | Accrual | 5.83 | 0.0 | 5.83 |
0.0 | 0.0 | 0.0 |
Given Global configuration "enable-immediate-charge-accrual-post-maturity"
is disabled
Then LoanAccrualTransactionCreatedBusinessEvent is raised on "05 February
2024"
@@ -4750,3 +4753,44 @@ Feature: LoanCharge
| 01 January 2024 | Repayment (at time of disbursement) | 1.0 | 0.0
| 0.0 | 1.0 | 0.0 | 100.0 | false | false |
| 01 February 2024 | Repayment | 17.01 |
16.43 | 0.58 | 0.0 | 0.0 | 83.57 | true | false |
| 01 March 2024 | Repayment | 17.01 |
16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | true |
+
+ @TestRailId:C3613
+ Scenario: Verify immediate charge accrual post maturity for Progressive loans
+ Given Global configuration "enable-immediate-charge-accrual-post-maturity"
is enabled
+ When Admin sets the business date to "25 February 2025"
+ 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_ACTUAL_ACTUAL | 25 February 2025 |
1000 | 0 | DECLINING_BALANCE | DAILY
| EQUAL_INSTALLMENTS | 1 | MONTHS | 1
| MONTHS | 1 | 0
| 0 | 0 |
ADVANCED_PAYMENT_ALLOCATION |
+ And Admin successfully approves the loan on "25 February 2025" with "1000"
amount and expected disbursement date on "25 February 2025"
+ When Admin successfully disburse the loan on "25 February 2025" with
"1000" EUR transaction amount
+ Then Loan Repayment schedule has 1 periods, with the following data for
periods:
+ | Nr | Days | Date | Paid date | Balance of loan | Principal
due | Interest | Fees | Penalties | Due | Paid | In advance | Late |
Outstanding |
+ | | | 25 February 2025 | | 1000.0 |
| | 0.0 | | 0.0 | 0.0 | | |
|
+ | 1 | 28 | 25 March 2025 | | 0.0 | 1000.0
| 0.0 | 0.0 | 0.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0
|
+ Then Loan Repayment schedule has the following data in Total row:
+ | Principal due | Interest | Fees | Penalties | Due | Paid | In
advance | Late | Outstanding |
+ | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | 0.0 | 0.0
| 0.0 | 1000.0 |
+ Then Loan Transactions tab has the following data:
+ | Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance |
+ | 25 February 2025 | Disbursement | 1000.0 | 0.0 | 0.0 |
0.0 | 0.0 | 1000.0 |
+ When Admin sets the business date to "28 March 2025"
+ And Admin runs inline COB job for Loan
+ When Admin adds "LOAN_SNOOZE_FEE" due date charge with "28 March 2025" due
date and 25 EUR transaction amount
+ Then 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 | 28 March 2025 | Flat
| 25.0 | 0.0 | 0.0 | 25.0 |
+ Then Loan Repayment schedule has 2 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 |
+ | | | 25 February 2025 | | 1000.0 |
| | 0.0 | | 0.0 | 0.0 | | |
|
+ | 1 | 28 | 25 March 2025 | | 0.0 | 1000.0
| 0.0 | 0.0 | 0.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0
|
+ | 2 | 3 | 28 March 2025 | | 0.0 | 0.0
| 0.0 | 25.0 | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0
|
+ Then Loan Repayment schedule has the following data in Total row:
+ | Principal due | Interest | Fees | Penalties | Due | Paid | In
advance | Late | Outstanding |
+ | 1000.0 | 0.0 | 25.0 | 0.0 | 1025.0 | 0.0 | 0.0
| 0.0 | 1025.0 |
+ Then Loan Transactions tab has the following data:
+ | Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance |
+ | 25 February 2025 | Disbursement | 1000.0 | 0.0 | 0.0 |
0.0 | 0.0 | 1000.0 |
+ | 28 March 2025 | Accrual | 25.0 | 0.0 | 0.0 |
25.0 | 0.0 | 0.0 |
+ Then LoanAccrualTransactionCreatedBusinessEvent is raised on "28 March
2025"
+ Given Global configuration "enable-immediate-charge-accrual-post-maturity"
is disabled
\ No newline at end of file
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 5f970c3b8b..fe77571ca0 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -644,6 +644,11 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
if (isProgressiveSchedule()) {
return null;
}
+
+ return createChargeAppliedTransaction(loanCharge,
suppliedTransactionDate);
+ }
+
+ public LoanTransaction createChargeAppliedTransaction(final LoanCharge
loanCharge, final LocalDate suppliedTransactionDate) {
final Money chargeAmount = loanCharge.getAmount(getCurrency());
Money feeCharges = chargeAmount;
Money penaltyCharges = Money.zero(getCurrency());
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
index 03c39763f0..c47752d877 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
@@ -1114,16 +1114,20 @@ public class LoanChargeWritePlatformServiceImpl
implements LoanChargeWritePlatfo
// we want to apply charge transactions only for those loans charges
that are applied when a loan is active and
// the loan product uses Upfront Accruals, or only when the loan are
closed too,
if ((loan.getStatus().isActive() &&
loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct())
- || loan.getStatus().isOverpaid() ||
loan.getStatus().isClosedObligationsMet()
- ||
(configurationDomainService.isImmediateChargeAccrualPostMaturityEnabled()
- &&
DateUtils.getBusinessLocalDate().isAfter(loan.getMaturityDate()))) {
+ || loan.getStatus().isOverpaid() ||
loan.getStatus().isClosedObligationsMet()) {
final LoanTransaction applyLoanChargeTransaction =
loan.handleChargeAppliedTransaction(loanCharge, null);
if (applyLoanChargeTransaction != null) {
this.loanTransactionRepository.saveAndFlush(applyLoanChargeTransaction);
businessEventNotifierService
.notifyPostBusinessEvent(new
LoanAccrualTransactionCreatedBusinessEvent(applyLoanChargeTransaction));
}
+ } else if
(configurationDomainService.isImmediateChargeAccrualPostMaturityEnabled()
+ &&
DateUtils.getBusinessLocalDate().isAfter(loan.getMaturityDate())) {
+ final LoanTransaction loanTransaction =
loan.createChargeAppliedTransaction(loanCharge, null);
+ this.loanTransactionRepository.saveAndFlush(loanTransaction);
+ businessEventNotifierService.notifyPostBusinessEvent(new
LoanAccrualTransactionCreatedBusinessEvent(loanTransaction));
}
+
return DateUtils.isBeforeBusinessDate(loanCharge.getDueLocalDate());
}
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImplTest.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImplTest.java
index 8b3309da17..f53cabc10f 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImplTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImplTest.java
@@ -220,6 +220,7 @@ class LoanChargeWritePlatformServiceImplTest {
when(configurationDomainService.isImmediateChargeAccrualPostMaturityEnabled()).thenReturn(isAccrualEnabled);
when(loan.getMaturityDate()).thenReturn(maturityDate);
when(loan.handleChargeAppliedTransaction(loanCharge,
null)).thenReturn(loanTransaction);
+ when(loan.createChargeAppliedTransaction(loanCharge,
null)).thenReturn(loanTransaction);
if (isAccrualExpected) {
when(loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()).thenReturn(true);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeProgressiveTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeProgressiveTest.java
index a217e704b9..f84fdbcf30 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeProgressiveTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeProgressiveTest.java
@@ -79,7 +79,7 @@ public class LoanChargeProgressiveTest extends
BaseLoanIntegrationTest {
addLoanCharge(loanId, chargeResponse.getResourceId(), "03 October
2024", 20.0d);
final GetLoansLoanIdResponse loanDetails =
loanTransactionHelper.getLoanDetails(loanId);
Assertions.assertTrue(
- loanDetails.getTransactions().stream().noneMatch(t ->
t.getType().getAccrual() && t.getAmount().equals(20.0d)));
+ loanDetails.getTransactions().stream().anyMatch(t ->
t.getType().getAccrual() && t.getAmount().equals(20.0d)));
});
runAt("04 October 2024", () -> {
globalConfigurationHelper.manageConfigurations(GlobalConfigurationConstants.ENABLE_IMMEDIATE_CHARGE_ACCRUAL_POST_MATURITY,