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 157a492bc FINERACT-1981: fix progressive accruals on late repayment
157a492bc is described below
commit 157a492bcc59dd93327f60e787a2cf7b924ef570
Author: adam.magyari <[email protected]>
AuthorDate: Mon Feb 3 15:42:58 2025 +0100
FINERACT-1981: fix progressive accruals on late repayment
---
.../infrastructure/core/service/MathUtil.java | 4 +
.../test/resources/features/EMICalculation.feature | 125 +++++++++++++++++++++
.../domain/LoanRepaymentScheduleInstallment.java | 12 ++
.../loanaccount/data/AccrualBalances.java | 32 ++++++
.../service/LoanAccrualsProcessingServiceImpl.java | 54 +++++++--
5 files changed, 220 insertions(+), 7 deletions(-)
diff --git
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java
index 9eab9a85e..a60b7e736 100644
---
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java
+++
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java
@@ -217,6 +217,10 @@ public final class MathUtil {
return nullToZero(first).compareTo(nullToZero(second)) < 0;
}
+ public static boolean isLessThanOrEqualTo(BigDecimal first, BigDecimal
second) {
+ return nullToZero(first).compareTo(second) <= 0;
+ }
+
public static boolean isGreaterThanOrEqualTo(BigDecimal first, BigDecimal
second) {
return nullToZero(first).compareTo(nullToZero(second)) >= 0;
}
diff --git
a/fineract-e2e-tests-runner/src/test/resources/features/EMICalculation.feature
b/fineract-e2e-tests-runner/src/test/resources/features/EMICalculation.feature
index 131e769c5..e9ae211db 100644
---
a/fineract-e2e-tests-runner/src/test/resources/features/EMICalculation.feature
+++
b/fineract-e2e-tests-runner/src/test/resources/features/EMICalculation.feature
@@ -5335,3 +5335,128 @@ Feature: EMI calculation and repayment schedule checks
for interest bearing loan
| 22 January 2021 | Accrual | 5.7 | 0.0 | 5.7
| 0.0 | 0.0 | 0.0 | false | false |
Then In Loan Transactions the "2"th Transaction has Transaction
type="Merchant Issued Refund" and is reverted
Then In Loan Transactions the "3"th Transaction has Transaction
type="Interest Refund" and is reverted
+
+ @TestRailId:C3313
+ Scenario: Verify that due date charges after maturity date is recognized on
repayment schedule
+ When Global config "charge-accrual-date" value set to "submitted-date"
+ When Admin sets the business date to "01 January 2024"
+ And Admin creates a client with random data
+ And Admin set
"LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE"
loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future
installment allocation rule
+ 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_RECALCULATION_DAILY_TILL_PRECLOSE
| 01 January 2024 | 100 | 7 |
DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 4
| MONTHS | 1 | MONTHS | 4
| 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 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 | | 100.0 |
| | 0.0 | | 0.0 | 0.0 | | |
|
+ | 1 | 31 | 01 February 2024 | | 75.21 | 24.79
| 0.58 | 0.0 | 0.0 | 25.37 | 0.0 | 0.0 | 0.0 | 25.37
|
+ | 2 | 29 | 01 March 2024 | | 50.28 | 24.93
| 0.44 | 0.0 | 0.0 | 25.37 | 0.0 | 0.0 | 0.0 | 25.37
|
+ | 3 | 31 | 01 April 2024 | | 25.2 | 25.08
| 0.29 | 0.0 | 0.0 | 25.37 | 0.0 | 0.0 | 0.0 | 25.37
|
+ | 4 | 30 | 01 May 2024 | | 0.0 | 25.2
| 0.15 | 0.0 | 0.0 | 25.35 | 0.0 | 0.0 | 0.0 | 25.35
|
+ And Loan Repayment schedule has the following data in Total row:
+ | Principal due | Interest | Fees | Penalties | Due | Paid | In
advance | Late | Outstanding |
+ | 100.0 | 1.46 | 0.0 | 0.0 | 101.46 | 0.0 | 0.0
| 0.0 | 101.46 |
+ 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 |
+ When Admin sets the business date to "1 May 2024"
+ And Admin runs inline COB job for Loan
+ And Admin adds "LOAN_NSF_FEE" due date charge with "15 May 2024" due date
and 10 EUR transaction amount
+ Then Loan Repayment schedule has 5 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 | | 75.21 | 24.79
| 0.58 | 0.0 | 0.0 | 25.37 | 0.0 | 0.0 | 0.0 | 25.37
|
+ | 2 | 29 | 01 March 2024 | | 50.42 | 24.79
| 0.58 | 0.0 | 0.0 | 25.37 | 0.0 | 0.0 | 0.0 | 25.37
|
+ | 3 | 31 | 01 April 2024 | | 25.63 | 24.79
| 0.58 | 0.0 | 0.0 | 25.37 | 0.0 | 0.0 | 0.0 | 25.37
|
+ | 4 | 30 | 01 May 2024 | | 0.0 | 25.63
| 0.58 | 0.0 | 0.0 | 26.21 | 0.0 | 0.0 | 0.0 | 26.21
|
+ | 5 | 14 | 15 May 2024 | | 0.0 | 0.0
| 0.0 | 0.0 | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.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.32 | 0.0 | 10.0 | 112.32 | 0.0 | 0.0
| 0.0 | 112.32 |
+ 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 |
+ | 30 April 2024 | Accrual | 1.87 | 0.0 | 1.87 |
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 |
+ | NSF fee | true | Specified due date | 15 May 2024 | Flat
| 10.0 | 0.0 | 0.0 | 10.0 |
+ When Admin sets the business date to "02 May 2024"
+ And Admin runs inline COB job for Loan
+ 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 |
+ | 30 April 2024 | Accrual | 1.87 | 0.0 | 1.87 |
0.0 | 0.0 | 0.0 | false | false |
+ | 01 May 2024 | Accrual | 10.45 | 0.0 | 0.45 |
0.0 | 10.0 | 0.0 | false | false |
+
+ @TestRailId:C3333
+ Scenario: Verify that due date charges after maturity date with inline COB
run is recognized on repayment schedule
+ When Admin sets the business date to "01 January 2024"
+ And Admin creates a client with random data
+ And Admin set
"LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE"
loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future
installment allocation rule
+ 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_RECALCULATION_DAILY_TILL_PRECLOSE
| 01 January 2024 | 100 | 7 |
DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 1
| MONTHS | 1 | MONTHS | 1
| 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
+ And Admin runs inline COB job for Loan
+ 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 |
+ | | | 01 January 2024 | | 100.0 |
| | 0.0 | | 0.0 | 0.0 | | |
|
+ | 1 | 31 | 01 February 2024 | | 0.0 | 100.0
| 0.58 | 0.0 | 0.0 | 100.58 | 0.0 | 0.0 | 0.0 | 100.58
|
+ And Loan Repayment schedule has the following data in Total row:
+ | Principal due | Interest | Fees | Penalties | Due | Paid | In
advance | Late | Outstanding |
+ | 100.0 | 0.58 | 0.0 | 0.0 | 100.58 | 0.0 | 0.0
| 0.0 | 100.58 |
+ 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 |
+ When Admin sets the business date to "15 February 2024"
+ And Admin adds "LOAN_NSF_FEE" due date charge with "15 February 2024" due
date and 10 EUR transaction amount
+ When Admin sets the business date to "16 February 2024"
+ And Admin runs inline COB job for Loan
+ 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 |
+ | | | 01 January 2024 | | 100.0 |
| | 0.0 | | 0.0 | 0.0 | | |
|
+ | 1 | 31 | 01 February 2024 | | 0.0 | 100.0
| 0.58 | 0.0 | 0.0 | 100.58 | 0.0 | 0.0 | 0.0 | 100.58
|
+ | 2 | 14 | 15 February 2024 | | 0.0 | 0.0
| 0.0 | 0.0 | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.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 | 0.58 | 0.0 | 10.0 | 110.58 | 0.0 | 0.0
| 0.0 | 110.58 |
+ 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 |
+ | 02 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 03 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 04 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 05 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 06 January 2024 | Accrual | 0.01 | 0.0 | 0.01 |
0.0 | 0.0 | 0.0 | false | false |
+ | 07 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 08 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 09 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 10 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 11 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 12 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 13 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 14 January 2024 | Accrual | 0.01 | 0.0 | 0.01 |
0.0 | 0.0 | 0.0 | false | false |
+ | 15 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 16 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 17 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 18 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 19 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 20 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 21 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 22 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 23 January 2024 | Accrual | 0.01 | 0.0 | 0.01 |
0.0 | 0.0 | 0.0 | false | false |
+ | 24 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 25 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 26 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 27 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 28 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 29 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 30 January 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 31 January 2024 | Accrual | 0.01 | 0.0 | 0.01 |
0.0 | 0.0 | 0.0 | false | false |
+ | 01 February 2024 | Accrual | 0.02 | 0.0 | 0.02 |
0.0 | 0.0 | 0.0 | false | false |
+ | 15 February 2024 | Accrual | 10.0 | 0.0 | 0.0 |
0.0 | 10.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 |
+ | NSF fee | true | Specified due date | 15 February 2024 | Flat
| 10.0 | 0.0 | 0.0 | 10.0 |
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
index 00e2687e7..76d223337 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
@@ -721,6 +721,18 @@ public class LoanRepaymentScheduleInstallment extends
AbstractAuditableWithUTCDa
this.penaltyAccrued =
MathUtil.zeroToNull(MathUtil.toBigDecimal(penalityCharges));
}
+ public void setInterestAccrued(BigDecimal interestAccrued) {
+ this.interestAccrued = interestAccrued;
+ }
+
+ public void setFeeAccrued(BigDecimal feeAccrued) {
+ this.feeAccrued = feeAccrued;
+ }
+
+ public void setPenaltyAccrued(BigDecimal penaltyAccrued) {
+ this.penaltyAccrued = penaltyAccrued;
+ }
+
public void updateObligationsMet(final MonetaryCurrency currency, final
LocalDate transactionDate) {
if (!this.obligationsMet && getTotalOutstanding(currency).isZero()) {
this.obligationsMet = true;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/AccrualBalances.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/AccrualBalances.java
new file mode 100644
index 000000000..52b9e7cb0
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/AccrualBalances.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.data;
+
+import java.math.BigDecimal;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AccrualBalances {
+
+ private BigDecimal interestPortion = BigDecimal.ZERO;
+ private BigDecimal feePortion = BigDecimal.ZERO;
+ private BigDecimal penaltyPortion = BigDecimal.ZERO;
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
index b33a17f11..c07eccad4 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
@@ -56,6 +56,7 @@ import
org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.portfolio.loanaccount.data.AccrualBalances;
import org.apache.fineract.portfolio.loanaccount.data.AccrualChargeData;
import org.apache.fineract.portfolio.loanaccount.data.AccrualPeriodData;
import org.apache.fineract.portfolio.loanaccount.data.AccrualPeriodsData;
@@ -698,13 +699,52 @@ public class LoanAccrualsProcessingServiceImpl implements
LoanAccrualsProcessing
LoanRepaymentScheduleInstallment lastInstallment =
loan.getLastLoanRepaymentScheduleInstallment();
LocalDate lastDueDate = lastInstallment.getDueDate();
if (isProgressiveAccrual(loan)) {
- AccrualPeriodsData accrualPeriods = calculateAccrualAmounts(loan,
lastDueDate, true);
- for (AccrualPeriodData period : accrualPeriods.getPeriods()) {
- Money interestAccrued = period.getTransactionAccrued();
- Money feeAccrued = period.getFeeTransactionAccrued();
- Money penaltyAccrued = period.getPenaltyTransactionAccrued();
- LoanRepaymentScheduleInstallment installment =
loan.fetchRepaymentScheduleInstallment(period.getInstallmentNumber());
- installment.updateAccrualPortion(interestAccrued, feeAccrued,
penaltyAccrued);
+ AccrualBalances accrualBalances = new AccrualBalances();
+ accrualTransactions.forEach(lt -> {
+ switch (lt.getTypeOf()) {
+ case ACCRUAL -> {
+
accrualBalances.setFeePortion(MathUtil.add(accrualBalances.getFeePortion(),
lt.getFeeChargesPortion()));
+
accrualBalances.setPenaltyPortion(MathUtil.add(accrualBalances.getPenaltyPortion(),
lt.getPenaltyChargesPortion()));
+
accrualBalances.setInterestPortion(MathUtil.add(accrualBalances.getInterestPortion(),
lt.getInterestPortion()));
+ }
+ case ACCRUAL_ADJUSTMENT -> {
+
accrualBalances.setFeePortion(MathUtil.subtract(accrualBalances.getFeePortion(),
lt.getFeeChargesPortion()));
+ accrualBalances
+
.setPenaltyPortion(MathUtil.subtract(accrualBalances.getPenaltyPortion(),
lt.getPenaltyChargesPortion()));
+ accrualBalances
+
.setInterestPortion(MathUtil.subtract(accrualBalances.getInterestPortion(),
lt.getInterestPortion()));
+ }
+ default -> throw new IllegalStateException("Unexpected
value: " + lt.getTypeOf());
+ }
+ });
+ for (LoanRepaymentScheduleInstallment installment :
loan.getRepaymentScheduleInstallments()) {
+ BigDecimal maximumAccruableInterest =
MathUtil.nullToZero(installment.getInterestCharged());
+ BigDecimal maximumAccruableFee =
MathUtil.nullToZero(installment.getFeeChargesCharged());
+ BigDecimal maximumAccruablePenalty =
MathUtil.nullToZero(installment.getPenaltyCharges());
+
+ if (MathUtil.isLessThanOrEqualTo(maximumAccruableInterest,
accrualBalances.getInterestPortion())) {
+ installment.setInterestAccrued(maximumAccruableInterest);
+
accrualBalances.setInterestPortion(accrualBalances.getInterestPortion().subtract(maximumAccruableInterest));
+ } else {
+
installment.setInterestAccrued(accrualBalances.getInterestPortion());
+ accrualBalances.setInterestPortion(BigDecimal.ZERO);
+ }
+
+ if (MathUtil.isLessThanOrEqualTo(maximumAccruableFee,
accrualBalances.getFeePortion())) {
+ installment.setFeeAccrued(maximumAccruableFee);
+
accrualBalances.setFeePortion(accrualBalances.getFeePortion().subtract(maximumAccruableFee));
+ } else {
+ installment.setFeeAccrued(accrualBalances.getFeePortion());
+ accrualBalances.setFeePortion(BigDecimal.ZERO);
+ }
+
+ if (MathUtil.isLessThanOrEqualTo(maximumAccruablePenalty,
accrualBalances.getPenaltyPortion())) {
+ installment.setPenaltyAccrued(maximumAccruablePenalty);
+
accrualBalances.setPenaltyPortion(accrualBalances.getPenaltyPortion().subtract(maximumAccruablePenalty));
+ } else {
+
installment.setPenaltyAccrued(accrualBalances.getPenaltyPortion());
+ accrualBalances.setPenaltyPortion(BigDecimal.ZERO);
+ }
}
} else {
List<LoanRepaymentScheduleInstallment> installments =
loan.getRepaymentScheduleInstallments();