From 880580f73693c89bb3bb24e44cceb57c63c36e85 Mon Sep 17 00:00:00 2001 From: "adam.magyari" Date: Thu, 10 Jul 2025 11:42:57 +0200 Subject: [PATCH] FINERACT-2311: Buy down fee - final amortization - early repayment - write off - charge-off --- .../features/LoanBuyDownFees.feature | 46 +++++-- .../portfolio/loanaccount/domain/Loan.java | 5 +- .../loanaccount/domain/LoanTransaction.java | 16 +++ ...yDownFeeAmortizationProcessingService.java | 7 + ...oanBuyDownFeeAmortizationEventService.java | 121 +++++++++++++++++ ...nFeeAmortizationProcessingServiceImpl.java | 128 ++++++++++++++++++ ...talizedIncomeAmortizationEventService.java | 2 +- .../starter/LoanAccountConfiguration.java | 9 ++ 8 files changed, 319 insertions(+), 15 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationEventService.java diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature index ac6ef6ccd..cd538a2d4 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature @@ -327,12 +327,17 @@ Feature:Feature: Buy Down Fees When Loan Pay-off is made on "1 March 2024" Then Loan's all installments have obligations met 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 | - | 01 January 2024 | Buy Down Fee | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | - | 01 February 2024 | Repayment | 33.72 | 33.14 | 0.58 | 0.0 | 0.0 | 66.86 | false | - | 01 March 2024 | Repayment | 67.25 | 66.86 | 0.39 | 0.0 | 0.0 | 0.0 | false | - | 01 March 2024 | Accrual | 0.97 | 0.0 | 0.97 | 0.0 | 0.0 | 0.0 | false | + | 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 | + | 01 January 2024 | Buy Down Fee | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 February 2024 | Repayment | 33.72 | 33.14 | 0.58 | 0.0 | 0.0 | 66.86 | false | + | 01 March 2024 | Repayment | 67.25 | 66.86 | 0.39 | 0.0 | 0.0 | 0.0 | false | + | 01 March 2024 | Accrual | 0.97 | 0.0 | 0.97 | 0.0 | 0.0 | 0.0 | false | + | 01 March 2024 | Buy Down Fee Amortization | 50.0 | 0.0 | 50.0 | 0.0 | 0.0 | 0.0 | false | + And Loan Transactions tab has a "BUY_DOWN_FEE_AMORTIZATION" transaction with date "01 March 2024" which has the following Journal entries: + | Type | Account code | Account name | Debit | Credit | + | INCOME | 450281 | Income From Buy Down | | 50.0 | + | LIABILITY | 145024 | Deferred Capitalized Income | 50.0 | | @TestRailId:C3828 Scenario: Verify loan with Buy Down fees and early payoff and daily amortization - UC2.2 @@ -508,6 +513,11 @@ Feature:Feature: Buy Down Fees | 01 March 2024 | Repayment | 67.25 | 66.86 | 0.39 | 0.0 | 0.0 | 0.0 | false | | 01 March 2024 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | + | 01 March 2024 | Buy Down Fee Amortization | 17.03 | 0.0 | 17.03 | 0.0 | 0.0 | 0.0 | false | + And Loan Transactions tab has a "BUY_DOWN_FEE_AMORTIZATION" transaction with date "01 March 2024" which has the following Journal entries: + | Type | Account code | Account name | Debit | Credit | + | INCOME | 450281 | Income From Buy Down | | 17.03 | + | LIABILITY | 145024 | Deferred Capitalized Income | 17.03 | | @TestRailId:C3772 Scenario: Verify loan with Buy Down fees and charge-off - UC3.1 @@ -556,12 +566,18 @@ Feature:Feature: Buy Down Fees | EXPENSE | 744007 | Credit Loss/Bad Debt | 66.86 | | | INCOME | 404001 | Interest Income Charge Off | 0.59 | | 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 | - | 01 January 2024 | Buy Down Fee | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | - | 01 February 2024 | Repayment | 33.72 | 33.14 | 0.58 | 0.0 | 0.0 | 66.86 | false | - | 01 March 2024 | Accrual | 0.97 | 0.0 | 0.97 | 0.0 | 0.0 | 0.0 | false | - | 01 March 2024 | Charge-off | 67.45 | 66.86 | 0.59 | 0.0 | 0.0 | 0.0 | false | + | 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 | + | 01 January 2024 | Buy Down Fee | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 February 2024 | Repayment | 33.72 | 33.14 | 0.58 | 0.0 | 0.0 | 66.86 | false | + | 01 March 2024 | Buy Down Fee Amortization | 33.52 | 0.0 | 33.52 | 0.0 | 0.0 | 0.0 | false | + | 01 March 2024 | Accrual | 0.97 | 0.0 | 0.97 | 0.0 | 0.0 | 0.0 | false | + | 01 March 2024 | Charge-off | 67.45 | 66.86 | 0.59 | 0.0 | 0.0 | 0.0 | false | + | 01 March 2024 | Buy Down Fee Amortization | 16.48 | 0.0 | 16.48 | 0.0 | 0.0 | 0.0 | false | + And Loan Transactions tab has a "BUY_DOWN_FEE_AMORTIZATION" transaction with date "01 March 2024" which has the following Journal entries: + | Type | Account code | Account name | Debit | Credit | + | EXPENSE | 744007 | Credit Loss/Bad Debt | | 16.48 | + | LIABILITY | 145024 | Deferred Capitalized Income | 16.48 | | When Loan Pay-off is made on "1 March 2024" Then Loan's all installments have obligations met @@ -745,8 +761,14 @@ Feature:Feature: Buy Down Fees | 29 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | | 29 February 2024 | Buy Down Fee Amortization | 0.55 | 0.0 | 0.55 | 0.0 | 0.0 | 0.0 | false | + | 01 March 2024 | Buy Down Fee Amortization | 0.55 | 0.0 | 0.55 | 0.0 | 0.0 | 0.0 | false | | 01 March 2024 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | | 01 March 2024 | Charge-off | 67.45 | 66.86 | 0.59 | 0.0 | 0.0 | 0.0 | false | + | 01 March 2024 | Buy Down Fee Amortization | 16.48 | 0.0 | 16.48 | 0.0 | 0.0 | 0.0 | false | + And Loan Transactions tab has a "BUY_DOWN_FEE_AMORTIZATION" transaction with date "01 March 2024" which has the following Journal entries: + | Type | Account code | Account name | Debit | Credit | + | EXPENSE | 744007 | Credit Loss/Bad Debt | | 16.48 | + | LIABILITY | 145024 | Deferred Capitalized Income | 16.48 | | When Loan Pay-off is made on "1 March 2024" Then Loan's all installments have obligations met 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 337b3fd47..07cc2744c 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 @@ -1755,8 +1755,9 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public LoanTransaction getLastUserTransaction() { return getLoanTransactions().stream() // - .filter(t -> t.isNotReversed() - && !(t.isAccrual() || t.isAccrualAdjustment() || t.isIncomePosting() || t.isCapitalizedIncomeAmortization())) // + .filter(t -> t.isNotReversed() && !(t.isAccrual() || t.isAccrualAdjustment() || t.isIncomePosting() + || t.isCapitalizedIncomeAmortization() || t.isCapitalizedIncomeAmortizationAdjustment() + || t.isBuyDownFeeAmortization() || t.isBuyDownFeeAmortizationAdjustment())) // .reduce((first, second) -> second) // .orElse(null); } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java index 62c49d807..d8dc5940b 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java @@ -706,6 +706,10 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom { + + @Override + public void onBusinessEvent(final LoanCloseBusinessEvent event) { + final Loan loan = event.get(); + final LoanStatus status = loan.getStatus(); + if (loan.getLoanProductRelatedDetail().isEnableBuyDownFee() + && (status.isClosedObligationsMet() || status.isClosedWrittenOff() || status.isOverpaid())) { + log.debug("Loan closure on buy down fee amortization for loan {}", loan.getId()); + loanBuyDownFeeAmortizationProcessingService.processBuyDownFeeAmortizationOnLoanClosure(loan, false); + } + } + } + + private final class LoanBalanceChangedListener implements BusinessEventListener { + + @Override + public void onBusinessEvent(final LoanBalanceChangedBusinessEvent event) { + final Loan loan = event.get(); + final LoanStatus status = loan.getStatus(); + if (loan.getLoanProductRelatedDetail().isEnableBuyDownFee() + && (status.isClosedObligationsMet() || status.isClosedWrittenOff() || status.isOverpaid())) { + log.debug("Loan balance change on buy down fee amortization for loan {}", loan.getId()); + loanBuyDownFeeAmortizationProcessingService.processBuyDownFeeAmortizationOnLoanClosure(loan, true); + } + } + } + + private final class LoanChargeOffEventListener implements BusinessEventListener { + + @Override + public void onBusinessEvent(final LoanChargeOffPostBusinessEvent event) { + final LoanTransaction loanTransaction = event.get(); + final Loan loan = loanTransaction.getLoan(); + if (loan.getLoanProductRelatedDetail().isEnableBuyDownFee() && loan.isChargedOff() && loanTransaction.isChargeOff()) { + log.debug("Loan charge-off on buy down fee amortization for loan {}", loan.getId()); + loanBuyDownFeeAmortizationProcessingService.processBuyDownFeeAmortizationOnLoanChargeOff(loan, loanTransaction); + } + } + } + + private final class LoanChargeOffPreEventListener implements BusinessEventListener { + + @Override + public void onBusinessEvent(final LoanChargeOffPreBusinessEvent event) { + final Loan loan = event.get(); + if (loan.getLoanProductRelatedDetail().isEnableBuyDownFee()) { + log.debug("Loan pre charge-off buy down fee amortization for loan {}", loan.getId()); + loanBuyDownFeeAmortizationProcessingService.processBuyDownFeeAmortizationTillDate(loan, DateUtils.getBusinessLocalDate(), + true); + } + } + } + + private final class LoanUndoChargeOffEventListener implements BusinessEventListener { + + @Override + public void onBusinessEvent(final LoanUndoChargeOffBusinessEvent event) { + final LoanTransaction loanTransaction = event.get(); + final Loan loan = loanTransaction.getLoan(); + final LoanStatus status = loan.getStatus(); + if (loan.getLoanProductRelatedDetail().isEnableBuyDownFee() && loanTransaction.getTypeOf().isChargeOff() + && !(loan.isChargedOff() || status.isClosedObligationsMet() || status.isClosedWrittenOff() || status.isOverpaid())) { + log.debug("Loan undo charge-off on buy down fee amortization for loan {}", loan.getId()); + loanBuyDownFeeAmortizationProcessingService.processBuyDownFeeAmortizationOnLoanUndoChargeOff(loanTransaction); + } + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java index c186d4281..4e3f6d0a7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java @@ -20,11 +20,16 @@ package org.apache.fineract.portfolio.loanaccount.service; import java.math.BigDecimal; import java.time.LocalDate; +import java.util.Collections; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.core.domain.ExternalId; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.core.service.MathUtil; import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; @@ -32,6 +37,8 @@ import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeBalance; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository; import org.apache.fineract.portfolio.loanaccount.repository.LoanBuyDownFeeBalanceRepository; import org.apache.fineract.portfolio.loanaccount.util.BuyDownFeeAmortizationUtil; @@ -102,6 +109,127 @@ public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyD } } + @Override + @Transactional + public void processBuyDownFeeAmortizationOnLoanClosure(@NonNull final Loan loan, final boolean addJournal) { + List existingTransactionIds = Collections.emptyList(); + List existingReversedTransactionIds = Collections.emptyList(); + if (addJournal) { + existingTransactionIds = loanTransactionRepository.findTransactionIdsByLoan(loan); + existingReversedTransactionIds = loanTransactionRepository.findReversedTransactionIdsByLoan(loan); + } + + final LocalDate transactionDate = getFinalBuyDownFeeAmortizationTransactionDate(loan); + final Optional amortizationTransaction = createBuyDownFeeAmortizationTransaction(loan, transactionDate, false, + null); + amortizationTransaction.ifPresent(loanTransaction -> { + if (loanTransaction.isBuyDownFeeAmortization()) { + businessEventNotifierService + .notifyPostBusinessEvent(new LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent(loanTransaction)); + } else { + businessEventNotifierService + .notifyPostBusinessEvent(new LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent(loanTransaction)); + } + }); + + if (addJournal) { + journalEntryPoster.postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); + } + } + + @Override + @Transactional + public void processBuyDownFeeAmortizationOnLoanChargeOff(@NonNull final Loan loan, + @NonNull final LoanTransaction chargeOffTransaction) { + final List existingTransactionIds = loanTransactionRepository.findTransactionIdsByLoan(loan); + final List existingReversedTransactionIds = loanTransactionRepository.findReversedTransactionIdsByLoan(loan); + + LocalDate transactionDate = loan.getChargedOffOnDate(); + if (transactionDate == null) { + transactionDate = DateUtils.getBusinessLocalDate(); + } + + final Optional amortizationTransaction = createBuyDownFeeAmortizationTransaction(loan, transactionDate, true, + chargeOffTransaction); + if (amortizationTransaction.isPresent()) { + journalEntryPoster.postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); + if (amortizationTransaction.get().isBuyDownFeeAmortization()) { + businessEventNotifierService.notifyPostBusinessEvent( + new LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent(amortizationTransaction.get())); + } else { + businessEventNotifierService.notifyPostBusinessEvent( + new LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent(amortizationTransaction.get())); + } + } + } + + @Override + @Transactional + public void processBuyDownFeeAmortizationOnLoanUndoChargeOff(@NonNull final LoanTransaction loanTransaction) { + final Loan loan = loanTransaction.getLoan(); + final List existingTransactionIds = loanTransactionRepository.findTransactionIdsByLoan(loan); + final List existingReversedTransactionIds = loanTransactionRepository.findReversedTransactionIdsByLoan(loan); + + loan.getLoanTransactions().stream().filter(LoanTransaction::isBuyDownFeeAmortization) + .filter(transaction -> transaction.getTransactionDate().equals(loanTransaction.getTransactionDate()) + && transaction.getLoanTransactionRelations().stream() + .anyMatch(rel -> LoanTransactionRelationTypeEnum.RELATED.equals(rel.getRelationType()) + && rel.getToTransaction().equals(loanTransaction))) + .forEach(transaction -> { + transaction.reverse(); + final LoanAdjustTransactionBusinessEvent.Data data = new LoanAdjustTransactionBusinessEvent.Data(transaction); + businessEventNotifierService.notifyPostBusinessEvent(new LoanAdjustTransactionBusinessEvent(data)); + + }); + + for (LoanBuyDownFeeBalance balance : loanBuyDownFeeBalanceRepository.findAllByLoanId(loan.getId())) { + balance.setUnrecognizedAmount(balance.getChargedOffAmount()); + balance.setChargedOffAmount(BigDecimal.ZERO); + } + + journalEntryPoster.postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); + } + + private Optional createBuyDownFeeAmortizationTransaction(final Loan loan, final LocalDate transactionDate, + final boolean isChargeOff, final LoanTransaction chargeOffTransaction) { + ExternalId externalId = externalIdFactory.create(); + + final List balances = loanBuyDownFeeBalanceRepository.findAllByLoanId(loan.getId()); + + BigDecimal totalAmortizationAmount = BigDecimal.ZERO; + for (LoanBuyDownFeeBalance balance : balances) { + List adjustments = loanTransactionRepository.findAdjustments(balance.getLoanTransaction()); + LocalDate maturityDate = loan.getMaturityDate() != null ? loan.getMaturityDate() : transactionDate; + final Money amortizationTillDate = BuyDownFeeAmortizationUtil.calculateTotalAmortizationTillDate(balance, adjustments, + maturityDate, loan.getLoanProductRelatedDetail().getBuyDownFeeStrategy(), maturityDate, loan.getCurrency()); + totalAmortizationAmount = totalAmortizationAmount.add(amortizationTillDate.getAmount()); + if (isChargeOff) { + balance.setChargedOffAmount(balance.getUnrecognizedAmount()); + } + balance.setUnrecognizedAmount(BigDecimal.ZERO); + } + + BigDecimal amortizedAmount = loanTransactionRepository.getAmortizedAmountBuyDownFee(loan); + BigDecimal totalUnrecognizedAmount = totalAmortizationAmount.subtract(amortizedAmount); + if (MathUtil.isZero(totalUnrecognizedAmount)) { + return Optional.empty(); + } + + final LoanTransaction amortizationTransaction = MathUtil.isGreaterThanZero(totalUnrecognizedAmount) + ? LoanTransaction.buyDownFeeAmortization(loan, loan.getOffice(), transactionDate, totalUnrecognizedAmount, externalId) + : LoanTransaction.buyDownFeeAmortizationAdjustment(loan, + Money.of(loan.getCurrency(), MathUtil.negate(totalUnrecognizedAmount)), transactionDate, externalId); + if (isChargeOff) { + amortizationTransaction.getLoanTransactionRelations().add(LoanTransactionRelation.linkToTransaction(amortizationTransaction, + chargeOffTransaction, LoanTransactionRelationTypeEnum.RELATED)); + } + + loan.addLoanTransaction(amortizationTransaction); + loanTransactionRepository.saveAndFlush(amortizationTransaction); + + return Optional.of(amortizationTransaction); + } + private LocalDate getFinalBuyDownFeeAmortizationTransactionDate(final Loan loan) { return switch (loan.getStatus()) { case CLOSED_OBLIGATIONS_MET -> loan.getClosedOnDate(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCapitalizedIncomeAmortizationEventService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCapitalizedIncomeAmortizationEventService.java index 0036e1ba8..dcdbebcf6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCapitalizedIncomeAmortizationEventService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCapitalizedIncomeAmortizationEventService.java @@ -100,7 +100,7 @@ public class LoanCapitalizedIncomeAmortizationEventService { if (loan.getLoanProductRelatedDetail().isEnableIncomeCapitalization()) { log.debug("Loan pre charge-off capitalized income amortization for loan {}", loan.getId()); loanCapitalizedIncomeAmortizationProcessingService.processCapitalizedIncomeAmortizationTillDate(loan, - DateUtils.getBusinessLocalDate(), false); + DateUtils.getBusinessLocalDate(), true); } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java index 60358ea5f..23731b0b6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java @@ -123,6 +123,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanArrearsAgingService import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler; import org.apache.fineract.portfolio.loanaccount.service.LoanAssemblerImpl; import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService; +import org.apache.fineract.portfolio.loanaccount.service.LoanBuyDownFeeAmortizationEventService; import org.apache.fineract.portfolio.loanaccount.service.LoanBuyDownFeeAmortizationProcessingService; import org.apache.fineract.portfolio.loanaccount.service.LoanBuyDownFeeAmortizationProcessingServiceImpl; import org.apache.fineract.portfolio.loanaccount.service.LoanCalculateRepaymentPastDueService; @@ -573,4 +574,12 @@ public class LoanAccountConfiguration { return new LoanBuyDownFeeAmortizationProcessingServiceImpl(loanTransactionRepository, loanBuyDownFeeBalanceRepository, businessEventNotifierService, journalEntryPoster, externalIdFactory); } + + @Bean + @ConditionalOnMissingBean(LoanBuyDownFeeAmortizationEventService.class) + public LoanBuyDownFeeAmortizationEventService loanBuyDownFeeAmortizationEventService( + BusinessEventNotifierService businessEventNotifierService, + LoanBuyDownFeeAmortizationProcessingService loanBuyDownFeeAmortizationProcessingService) { + return new LoanBuyDownFeeAmortizationEventService(businessEventNotifierService, loanBuyDownFeeAmortizationProcessingService); + } }