FINERACT-2311: Buy Down fees - External business events
- buy down fee reversal fix - added more listeners for buy down fee amortization on closed loans
This commit is contained in:
+55
@@ -23,8 +23,11 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.event.business.BusinessEventListener;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBalanceChangedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanCloseBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeTransactionCreatedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanChargeOffPostBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanChargeOffPreBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanUndoChargeOffBusinessEvent;
|
||||
@@ -43,6 +46,12 @@ public class LoanBuyDownFeeAmortizationEventService {
|
||||
@PostConstruct
|
||||
public void addListeners() {
|
||||
businessEventNotifierService.addPreBusinessEventListener(LoanCloseBusinessEvent.class, new LoanCloseListener());
|
||||
businessEventNotifierService.addPostBusinessEventListener(LoanBuyDownFeeTransactionCreatedBusinessEvent.class,
|
||||
new LoanBuyDownFeeTransactionListener());
|
||||
businessEventNotifierService.addPostBusinessEventListener(LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent.class,
|
||||
new LoanBuyDownFeeAdjustmentTransactionListener());
|
||||
businessEventNotifierService.addPostBusinessEventListener(LoanAdjustTransactionBusinessEvent.class,
|
||||
new LoanAdjustTransactionListener());
|
||||
businessEventNotifierService.addPostBusinessEventListener(LoanBalanceChangedBusinessEvent.class, new LoanBalanceChangedListener());
|
||||
businessEventNotifierService.addPostBusinessEventListener(LoanChargeOffPostBusinessEvent.class, new LoanChargeOffEventListener());
|
||||
businessEventNotifierService.addPostBusinessEventListener(LoanUndoChargeOffBusinessEvent.class,
|
||||
@@ -78,6 +87,52 @@ public class LoanBuyDownFeeAmortizationEventService {
|
||||
}
|
||||
}
|
||||
|
||||
private final class LoanBuyDownFeeTransactionListener implements BusinessEventListener<LoanBuyDownFeeTransactionCreatedBusinessEvent> {
|
||||
|
||||
@Override
|
||||
public void onBusinessEvent(final LoanBuyDownFeeTransactionCreatedBusinessEvent event) {
|
||||
final Loan loan = event.get().getLoan();
|
||||
final LoanStatus status = loan.getStatus();
|
||||
if (loan.getLoanProductRelatedDetail().isEnableBuyDownFee()
|
||||
&& (status.isClosedObligationsMet() || status.isClosedWrittenOff() || status.isOverpaid())) {
|
||||
log.debug("Loan buy down fee change on buy down fee amortization for closed loan {}", loan.getId());
|
||||
loanBuyDownFeeAmortizationProcessingService.processBuyDownFeeAmortizationOnLoanClosure(loan, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class LoanBuyDownFeeAdjustmentTransactionListener
|
||||
implements BusinessEventListener<LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent> {
|
||||
|
||||
@Override
|
||||
public void onBusinessEvent(final LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent event) {
|
||||
final Loan loan = event.get().getLoan();
|
||||
final LoanStatus status = loan.getStatus();
|
||||
if (loan.getLoanProductRelatedDetail().isEnableBuyDownFee()
|
||||
&& (status.isClosedObligationsMet() || status.isClosedWrittenOff() || status.isOverpaid())) {
|
||||
log.debug("Loan buy down fee change on buy down fee amortization for closed loan {}", loan.getId());
|
||||
loanBuyDownFeeAmortizationProcessingService.processBuyDownFeeAmortizationOnLoanClosure(loan, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class LoanAdjustTransactionListener implements BusinessEventListener<LoanAdjustTransactionBusinessEvent> {
|
||||
|
||||
@Override
|
||||
public void onBusinessEvent(final LoanAdjustTransactionBusinessEvent event) {
|
||||
final LoanTransaction transactionToAdjust = event.get().getTransactionToAdjust();
|
||||
final boolean isTransactionBuyDownFeeRelated = transactionToAdjust.isBuyDownFee()
|
||||
|| transactionToAdjust.isBuyDownFeeAdjustment();
|
||||
final Loan loan = transactionToAdjust.getLoan();
|
||||
final LoanStatus status = loan.getStatus();
|
||||
if (loan.getLoanProductRelatedDetail().isEnableBuyDownFee() && isTransactionBuyDownFeeRelated
|
||||
&& (status.isClosedObligationsMet() || status.isClosedWrittenOff() || status.isOverpaid())) {
|
||||
log.debug("Loan buy down fee change on buy down fee amortization for closed loan {}", loan.getId());
|
||||
loanBuyDownFeeAmortizationProcessingService.processBuyDownFeeAmortizationOnLoanClosure(loan, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class LoanChargeOffEventListener implements BusinessEventListener<LoanChargeOffPostBusinessEvent> {
|
||||
|
||||
@Override
|
||||
|
||||
+27
-35
@@ -24,7 +24,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
@@ -37,9 +36,6 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBalanceChangedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeAdjustmentTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
@@ -177,6 +173,31 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
capitalizedIncomeBalance
|
||||
.setUnrecognizedAmount(capitalizedIncomeBalance.getUnrecognizedAmount().add(transactionToAdjust.getAmount()));
|
||||
}
|
||||
if (transactionToAdjust.isBuyDownFee()) {
|
||||
if (newTransactionDetail.isNotZero()) {
|
||||
throw new InvalidLoanTransactionTypeException("transaction", "buy.down.fee.cannot.be.adjusted",
|
||||
"Buy down fee transaction cannot be adjusted");
|
||||
}
|
||||
|
||||
LoanBuyDownFeeBalance buyDownFeeBalance = loanBuyDownFeeBalanceRepository.findByLoanIdAndLoanTransactionId(loan.getId(),
|
||||
transactionToAdjust.getId());
|
||||
|
||||
if (MathUtil.isGreaterThanZero(buyDownFeeBalance.getAmountAdjustment())) {
|
||||
throw new InvalidLoanTransactionTypeException("transaction", "buy.down.fee.cannot.be.reversed.when.adjusted",
|
||||
"Buy down fee transaction cannot be reversed when non-reversed adjustment exists for it.");
|
||||
}
|
||||
loanBuyDownFeeBalanceRepository.delete(buyDownFeeBalance);
|
||||
}
|
||||
if (transactionToAdjust.isBuyDownFeeAdjustment()) {
|
||||
if (newTransactionDetail.isNotZero()) {
|
||||
throw new InvalidLoanTransactionTypeException("transaction", "buy.down.fee.adjustment.cannot.be.adjusted",
|
||||
"Buy down fee adjustment transaction cannot be adjusted");
|
||||
}
|
||||
LoanBuyDownFeeBalance buyDownFeeBalance = loanBuyDownFeeBalanceRepository.findBalanceForAdjustment(transactionToAdjust.getId());
|
||||
|
||||
buyDownFeeBalance.setAmountAdjustment(buyDownFeeBalance.getAmountAdjustment().subtract(transactionToAdjust.getAmount()));
|
||||
buyDownFeeBalance.setUnrecognizedAmount(buyDownFeeBalance.getUnrecognizedAmount().add(transactionToAdjust.getAmount()));
|
||||
}
|
||||
|
||||
LocalDate recalculateFrom = null;
|
||||
|
||||
@@ -292,9 +313,9 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
&& transactionForAdjustment.isNotWaiver() && transactionForAdjustment.isNotCreditBalanceRefund()
|
||||
&& !transactionForAdjustment.isDeferredIncome() && !transactionForAdjustment.isCapitalizedIncomeAdjustment()
|
||||
&& !transactionForAdjustment.isBuyDownFeeAdjustment()) {
|
||||
final String errorMessage = "Only (non-reversed) transactions of type repayment, waiver, accrual, credit balance refund, capitalized income, capitalized income adjustment or buy down fee adjustment can be adjusted.";
|
||||
final String errorMessage = "Only (non-reversed) transactions of type repayment, waiver, accrual, credit balance refund, capitalized income, capitalized income adjustment, buy down fee or buy down fee adjustment can be adjusted.";
|
||||
throw new InvalidLoanTransactionTypeException("transaction",
|
||||
"adjustment.is.only.allowed.to.repayment.or.waiver.or.creditbalancerefund.or.capitalizedIncome.or.capitalizedIncomeAdjustment.or.buyDownFeeAdjustment.transactions",
|
||||
"adjustment.is.only.allowed.to.repayment.or.waiver.or.creditbalancerefund.or.capitalizedIncome.or.capitalizedIncomeAdjustment.or.buyDownFee.or.buyDownFeeAdjustment.transactions",
|
||||
errorMessage);
|
||||
}
|
||||
|
||||
@@ -318,17 +339,6 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
LoanAdjustTransactionBusinessEvent.Data eventData = new LoanAdjustTransactionBusinessEvent.Data(loanTransaction);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanAdjustTransactionBusinessEvent(eventData));
|
||||
});
|
||||
} else if (transactionForAdjustment.isBuyDownFee()) {
|
||||
Optional<LoanTransaction> optAmortizationAdjustmentTransaction = buyDownFeePlatformService
|
||||
.reverseBuyDownFee(transactionForAdjustment);
|
||||
if (optAmortizationAdjustmentTransaction.isPresent()) {
|
||||
loan.addLoanTransaction(optAmortizationAdjustmentTransaction.get());
|
||||
loanTransactionRepository.saveAndFlush(optAmortizationAdjustmentTransaction.get());
|
||||
businessEventNotifierService
|
||||
.notifyPostBusinessEvent(new LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent(
|
||||
optAmortizationAdjustmentTransaction.get()));
|
||||
}
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanBuyDownFeeTransactionBusinessEvent(transactionForAdjustment));
|
||||
}
|
||||
|
||||
if (loan.isClosedWrittenOff()) {
|
||||
@@ -347,24 +357,6 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
if (transactionForAdjustment.getTypeOf().equals(LoanTransactionType.CAPITALIZED_INCOME)) {
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
}
|
||||
|
||||
if (transactionForAdjustment.getTypeOf().equals(LoanTransactionType.BUY_DOWN_FEE_ADJUSTMENT)) {
|
||||
// adjust buy down fee balance
|
||||
final LoanTransaction originalBuyDownFeeTransaction = transactionForAdjustment.getLoanTransactionRelations().stream()
|
||||
.filter(r -> r.getRelationType().equals(LoanTransactionRelationTypeEnum.ADJUSTMENT)).findFirst().get()
|
||||
.getToTransaction();
|
||||
final LoanBuyDownFeeBalance buyDownFeeBalance = loanBuyDownFeeBalanceRepository.findByLoanIdAndLoanTransactionId(loan.getId(),
|
||||
originalBuyDownFeeTransaction.getId());
|
||||
if (buyDownFeeBalance != null) {
|
||||
buyDownFeeBalance.setAmountAdjustment(
|
||||
MathUtil.nullToZero(buyDownFeeBalance.getAmountAdjustment()).subtract(transactionForAdjustment.getAmount()));
|
||||
buyDownFeeBalance.setUnrecognizedAmount(
|
||||
MathUtil.nullToZero(buyDownFeeBalance.getUnrecognizedAmount()).add(transactionForAdjustment.getAmount()));
|
||||
loanBuyDownFeeBalanceRepository.save(buyDownFeeBalance);
|
||||
}
|
||||
businessEventNotifierService
|
||||
.notifyPostBusinessEvent(new LoanBuyDownFeeAdjustmentTransactionBusinessEvent(transactionForAdjustment));
|
||||
}
|
||||
}
|
||||
|
||||
private Loan saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
|
||||
|
||||
+2
-6
@@ -395,14 +395,10 @@ public class LoanAccountConfiguration {
|
||||
LoanAssembler loanAssembler, LoanTransactionRepository loanTransactionRepository,
|
||||
PaymentDetailWritePlatformService paymentDetailWritePlatformService, LoanJournalEntryPoster loanJournalEntryPoster,
|
||||
NoteWritePlatformService noteWritePlatformService, ExternalIdFactory externalIdFactory,
|
||||
LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository,
|
||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanBalanceService loanBalanceService,
|
||||
LoanLifecycleStateMachine loanLifecycleStateMachine, BusinessEventNotifierService businessEventNotifierService,
|
||||
LoanTransactionRelationRepository loanTransactionRelationRepository) {
|
||||
LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository, BusinessEventNotifierService businessEventNotifierService) {
|
||||
return new BuyDownFeeWritePlatformServiceImpl(loanTransactionValidator, loanAssembler, loanTransactionRepository,
|
||||
paymentDetailWritePlatformService, loanJournalEntryPoster, noteWritePlatformService, externalIdFactory,
|
||||
loanBuyDownFeeBalanceRepository, reprocessLoanTransactionsService, loanBalanceService, loanLifecycleStateMachine,
|
||||
businessEventNotifierService, loanTransactionRelationRepository);
|
||||
loanBuyDownFeeBalanceRepository, businessEventNotifierService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -211,5 +211,4 @@
|
||||
<include file="parts/0190_buy_down_fee_amortization.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0191_add_LoanApprovedAmountChangedBusinessEvent.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0192_create_loan_approved_amount_history.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0193_buy_down_fee_events.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet id="4" author="fineract">
|
||||
<update tableName="m_external_event_configuration">
|
||||
<column name="type" value="LoanBuyDownFeeTransactionBusinessEvent"/>
|
||||
<where>type='LoanBuyDownFeeTransactionCreatedBusinessEvent'</where>
|
||||
</update>
|
||||
<update tableName="m_external_event_configuration">
|
||||
<column name="type" value="LoanBuyDownFeeAdjustmentTransactionBusinessEvent"/>
|
||||
<where>type='LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent'</where>
|
||||
</update>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+2
-2
@@ -110,7 +110,7 @@ public class ExternalEventConfigurationValidationServiceTest {
|
||||
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent",
|
||||
"LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent",
|
||||
"LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "LoanUndoContractTerminationBusinessEvent",
|
||||
"LoanBuyDownFeeTransactionBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionBusinessEvent",
|
||||
"LoanBuyDownFeeTransactionCreatedBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent",
|
||||
"LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent",
|
||||
"LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "LoanApprovedAmountChangedBusinessEvent");
|
||||
|
||||
@@ -204,7 +204,7 @@ public class ExternalEventConfigurationValidationServiceTest {
|
||||
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent",
|
||||
"LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent",
|
||||
"LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "LoanUndoContractTerminationBusinessEvent",
|
||||
"LoanBuyDownFeeTransactionBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionBusinessEvent",
|
||||
"LoanBuyDownFeeTransactionCreatedBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent",
|
||||
"LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent",
|
||||
"LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "LoanApprovedAmountChangedBusinessEvent");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user