FINERACT-2225: Save journal entries for accrual transaction created by charge adjustment
This commit is contained in:
committed by
Adam Saghy
parent
510b4853e7
commit
f3606bb2d1
@@ -2722,3 +2722,28 @@ Feature: LoanCharge
|
||||
| 01 March 2024 | Accrual | 1.16 | 0.0 | 1.16 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 01 March 2024 | Charge-off | 107.14 | 100.0 | 2.14 | 5.0 | 0.0 | 0.0 | false | false |
|
||||
| 01 March 2024 | Charge Adjustment | 5.0 | 5.0 | 0.0 | 0.0 | 0.0 | 95.0 | false | false |
|
||||
|
||||
@TestRailId:C3571
|
||||
Scenario: Charge adjustment on account with zero principal balance should not create accrual transactions without journal entries
|
||||
When Admin sets the business date to "25 March 2025"
|
||||
When Admin creates a client with random data
|
||||
And Admin successfully creates a new customised Loan submitted on date: "25 March 2025", with Principal: "800", a loanTermFrequency: 1 months, and numberOfRepayments: 1
|
||||
And Admin successfully approves the loan on "25 March 2025" with "800" amount and expected disbursement date on "25 March 2025"
|
||||
When Admin successfully disburse the loan on "25 March 2025" with "800" EUR transaction amount
|
||||
And Customer makes "AUTOPAY" repayment on "25 March 2025" with 800 EUR transaction amount
|
||||
And Admin adds an NSF fee because of payment bounce with "25 March 2025" transaction date
|
||||
When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "25 March 2025" with 10 EUR transaction amount and externalId ""
|
||||
Then Loan Transactions tab has a "CHARGE_ADJUSTMENT" transaction with date "25 March 2025" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
| ASSET | 112601 | Loans Receivable | | 10.0 |
|
||||
| INCOME | 404007 | Fee Income | 10.0 | |
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 25 March 2025 | Disbursement | 800.0 | 0.0 | 0.0 | 0.0 | 0.0 | 800.0 |
|
||||
| 25 March 2025 | Repayment | 800.0 | 790.0 | 0.0 | 0.0 | 10.0 | 10.0 |
|
||||
| 25 March 2025 | Charge Adjustment | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 25 March 2025 | Accrual | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 | 0.0 |
|
||||
Then Loan Transactions tab has a "ACCRUAL" transaction with date "25 March 2025" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
| ASSET | 112603 | Interest/Fee Receivable | 10.0 | |
|
||||
| INCOME | 404007 | Fee Income | | 10.0 |
|
||||
+2
-1
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.exception.MultiException;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
public interface LoanAccrualsProcessingService {
|
||||
|
||||
@@ -41,7 +42,7 @@ public interface LoanAccrualsProcessingService {
|
||||
|
||||
void processIncomePostingAndAccruals(@NotNull Loan loan);
|
||||
|
||||
void processAccrualsOnLoanClosure(@NotNull Loan loan);
|
||||
void processAccrualsOnLoanClosure(@NonNull Loan loan, boolean addJournal);
|
||||
|
||||
void processAccrualsOnLoanForeClosure(@NotNull Loan loan, @NotNull LocalDate foreClosureDate,
|
||||
@NotNull List<LoanTransaction> newAccrualTransactions);
|
||||
|
||||
+14
-2
@@ -19,6 +19,7 @@
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.util.Objects;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.event.business.BusinessEventListener;
|
||||
@@ -27,6 +28,7 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.LoanCloseBu
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@@ -50,7 +52,7 @@ public class LoanAccrualEventService {
|
||||
LoanStatus status = loan.getStatus();
|
||||
if (status.isClosedObligationsMet() || status.isOverpaid()) {
|
||||
log.debug("Loan closure on accrual for loan {}", loan.getId());
|
||||
loanAccrualsProcessingService.processAccrualsOnLoanClosure(loan);
|
||||
loanAccrualsProcessingService.processAccrualsOnLoanClosure(loan, false);
|
||||
loanAccrualActivityProcessingService.processAccrualActivityForLoanClosure(loan);
|
||||
}
|
||||
}
|
||||
@@ -64,9 +66,19 @@ public class LoanAccrualEventService {
|
||||
LoanStatus status = loan.getStatus();
|
||||
if (status.isClosedObligationsMet() || status.isOverpaid()) {
|
||||
log.debug("Loan balance change on accrual for loan {}", loan.getId());
|
||||
loanAccrualsProcessingService.processAccrualsOnLoanClosure(loan);
|
||||
final boolean hasChargeAdjustment = hasChargeAdjustment(loan);
|
||||
loanAccrualsProcessingService.processAccrualsOnLoanClosure(loan, hasChargeAdjustment);
|
||||
loanAccrualActivityProcessingService.processAccrualActivityForLoanClosure(loan);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasChargeAdjustment(final Loan loan) {
|
||||
return loan.getLoanTransactions().stream()
|
||||
.filter(transaction -> transaction.isChargeAdjustment() && transaction.isNotReversed())
|
||||
.anyMatch(chargeAdjustment -> chargeAdjustment.getLoanTransactionRelations().stream()
|
||||
.anyMatch(relation -> relation.getRelationType() == LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT
|
||||
&& relation.getFromTransaction() != null
|
||||
&& Objects.equals(relation.getFromTransaction().getId(), chargeAdjustment.getId())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -83,6 +83,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanSchedul
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -284,9 +285,9 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
|
||||
* method calculates accruals for loan on loan closure
|
||||
*/
|
||||
@Override
|
||||
public void processAccrualsOnLoanClosure(@NotNull Loan loan) {
|
||||
public void processAccrualsOnLoanClosure(@NonNull final Loan loan, final boolean addJournal) {
|
||||
// check and process accruals for loan WITHOUT interest recalculation details and compounding posted as income
|
||||
addAccruals(loan, loan.getLastLoanRepaymentScheduleInstallment().getDueDate(), false, true, false);
|
||||
addAccruals(loan, loan.getLastLoanRepaymentScheduleInstallment().getDueDate(), false, true, addJournal);
|
||||
if (isProgressiveAccrual(loan)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user