FINERACT-2354: In case full transaction reprocessing, we need to recalculate the schedule as well
This commit is contained in:
+5
-5
@@ -46,7 +46,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
|
||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanTermVariationsRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@AllArgsConstructor
|
||||
@@ -56,8 +56,8 @@ public class InterestPauseWritePlatformServiceImpl implements InterestPauseWrite
|
||||
private final LoanTermVariationsRepository loanTermVariationsRepository;
|
||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
private final LoanAssembler loanAssembler;
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final LoanScheduleService loanScheduleService;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult createInterestPause(final ExternalId loanExternalId, final String startDateString,
|
||||
@@ -114,7 +114,7 @@ public class InterestPauseWritePlatformServiceImpl implements InterestPauseWrite
|
||||
loanTermVariationsRepository.delete(variation);
|
||||
loan.getLoanTermVariations().remove(variation);
|
||||
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan);
|
||||
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanScheduleVariationsDeletedBusinessEvent(loan));
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
||||
@@ -141,7 +141,7 @@ public class InterestPauseWritePlatformServiceImpl implements InterestPauseWrite
|
||||
|
||||
LoanTermVariations updatedVariation = loanTermVariationsRepository.save(variation);
|
||||
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan);
|
||||
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanScheduleVariationsAddedBusinessEvent(loan));
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
||||
@@ -161,7 +161,7 @@ public class InterestPauseWritePlatformServiceImpl implements InterestPauseWrite
|
||||
final LoanTermVariations savedVariation = loanTermVariationsRepository.saveAndFlush(variation);
|
||||
loan.getLoanTermVariations().add(savedVariation);
|
||||
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan);
|
||||
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanScheduleVariationsAddedBusinessEvent(loan));
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
|
||||
public interface ILoanUtilService {
|
||||
|
||||
ScheduleGeneratorDTO buildScheduleGeneratorDTO(Loan loan, LocalDate recalculateFrom);
|
||||
|
||||
ScheduleGeneratorDTO buildScheduleGeneratorDTO(Loan loan, LocalDate recalculateFrom, LocalDate rescheduleTill);
|
||||
|
||||
ScheduleGeneratorDTO buildScheduleGeneratorDTO(Loan loan, LocalDate recalculateFrom, LocalDate recalculateTill,
|
||||
HolidayDetailDTO holidayDetailDTO);
|
||||
|
||||
Boolean isLoanRepaymentsSyncWithMeeting(Group group, Calendar calendar);
|
||||
|
||||
LocalDate getCalculatedRepaymentsStartingFromDate(Loan loan);
|
||||
|
||||
HolidayDetailDTO constructHolidayDTO(Long officeId, LocalDate localDate);
|
||||
|
||||
void validateRepaymentTransactionType(LoanTransactionType repaymentTransactionType);
|
||||
|
||||
void checkClientOrGroupActive(Loan loan);
|
||||
}
|
||||
+1
@@ -94,6 +94,7 @@ public class LoanBalanceService {
|
||||
|
||||
public void updateLoanSummaryDerivedFields(final Loan loan) {
|
||||
flushModeHandler.withFlushMode(FlushModeType.COMMIT, () -> {
|
||||
loan.updateLoanScheduleDependentDerivedFields();
|
||||
if (loan.isNotDisbursed()) {
|
||||
if (loan.getSummary() != null) {
|
||||
loan.getSummary().zeroFields();
|
||||
|
||||
+48
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.configuration.service.TemporaryConfigu
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
|
||||
@@ -901,4 +902,51 @@ public class LoanChargeService {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void removeLoanCharge(final Loan loan, final LoanCharge loanCharge) {
|
||||
final boolean removed = loanCharge.isActive();
|
||||
if (removed) {
|
||||
loanCharge.setActive(false);
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(loan.getCurrency(), loan.getDisbursementDate(), loan.getRepaymentScheduleInstallments(),
|
||||
loan.getActiveCharges());
|
||||
loan.updateSummaryWithTotalFeeChargesDueAtDisbursement(loan.deriveSumTotalOfChargesDueAtDisbursement());
|
||||
}
|
||||
|
||||
removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loan, loanCharge);
|
||||
loan.getLoanCharges().remove(loanCharge);
|
||||
}
|
||||
|
||||
private void removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(final Loan loan, final LoanCharge loanCharge) {
|
||||
if (loanCharge.isDueAtDisbursement()) {
|
||||
LoanTransaction transactionToRemove = null;
|
||||
List<LoanTransaction> transactions = loan.getLoanTransactions();
|
||||
for (final LoanTransaction transaction : transactions) {
|
||||
if (transaction.isRepaymentAtDisbursement()
|
||||
&& doesLoanChargePaidByContainLoanCharge(transaction.getLoanChargesPaid(), loanCharge)) {
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
final Money chargeAmount = Money.of(currency, loanCharge.amount());
|
||||
if (transaction.isGreaterThan(chargeAmount)) {
|
||||
final Money principalPortion = Money.zero(currency);
|
||||
final Money interestPortion = Money.zero(currency);
|
||||
final Money penaltyChargesPortion = Money.zero(currency);
|
||||
|
||||
transaction.updateComponentsAndTotal(principalPortion, interestPortion, chargeAmount, penaltyChargesPortion);
|
||||
|
||||
} else {
|
||||
transactionToRemove = transaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (transactionToRemove != null) {
|
||||
loan.removeLoanTransaction(transactionToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doesLoanChargePaidByContainLoanCharge(Set<LoanChargePaidBy> loanChargePaidBys, LoanCharge loanCharge) {
|
||||
return loanChargePaidBys.stream() //
|
||||
.anyMatch(loanChargePaidBy -> loanChargePaidBy.getLoanCharge().equals(loanCharge));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-3
@@ -156,9 +156,7 @@ public class LoanDownPaymentHandlerServiceImpl implements LoanDownPaymentHandler
|
||||
if (!processLatest || reprocessOnPostConditions) {
|
||||
if (loan.isCumulativeSchedule() && loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO);
|
||||
} else if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction()
|
||||
|| (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
} else if (loan.isProgressiveSchedule()) {
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
|
||||
+12
-2
@@ -42,6 +42,7 @@ public class LoanScheduleService {
|
||||
private final LoanTransactionProcessingService loanTransactionProcessingService;
|
||||
private final LoanScheduleComponent loanSchedule;
|
||||
private final LoanTransactionRepository loanTransactionRepository;
|
||||
private final ILoanUtilService loanUtilService;
|
||||
|
||||
/**
|
||||
* Ability to regenerate the repayment schedule based on the loans current details/state.
|
||||
@@ -60,7 +61,7 @@ public class LoanScheduleService {
|
||||
}
|
||||
}
|
||||
|
||||
public void recalculateSchedule(final Loan loan, final ScheduleGeneratorDTO generatorDTO) {
|
||||
public void regenerateScheduleWithReprocessingTransactions(final Loan loan, final ScheduleGeneratorDTO generatorDTO) {
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled() && !loan.isChargedOff()) {
|
||||
regenerateRepaymentScheduleWithInterestRecalculation(loan, generatorDTO);
|
||||
} else {
|
||||
@@ -123,11 +124,20 @@ public class LoanScheduleService {
|
||||
}
|
||||
}
|
||||
}
|
||||
loanTransactionProcessingService.processPostDisbursementTransactions(loan);
|
||||
}
|
||||
|
||||
public void handleRegenerateRepaymentScheduleWithInterestRecalculation(final Loan loan, final ScheduleGeneratorDTO generatorDTO) {
|
||||
regenerateRepaymentScheduleWithInterestRecalculation(loan, generatorDTO);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
}
|
||||
|
||||
public void regenerateScheduleWithReprocessingTransactions(Loan loan) {
|
||||
ScheduleGeneratorDTO generatorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
regenerateScheduleWithReprocessingTransactions(loan, generatorDTO);
|
||||
}
|
||||
|
||||
public void regenerateRepaymentSchedule(final Loan loan) {
|
||||
ScheduleGeneratorDTO generatorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
regenerateRepaymentSchedule(loan, generatorDTO);
|
||||
}
|
||||
}
|
||||
|
||||
-3
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.OutstandingAmountsDTO;
|
||||
@@ -48,8 +47,6 @@ public interface LoanTransactionProcessingService {
|
||||
|
||||
LoanRepaymentScheduleTransactionProcessor getTransactionProcessor(String transactionProcessingStrategyCode);
|
||||
|
||||
Optional<ChangedTransactionDetail> processPostDisbursementTransactions(Loan loan);
|
||||
|
||||
LoanScheduleDTO getRecalculatedSchedule(ScheduleGeneratorDTO generatorDTO, Loan loan);
|
||||
|
||||
OutstandingAmountsDTO fetchPrepaymentDetail(ScheduleGeneratorDTO scheduleGeneratorDTO, LocalDate onDate, Loan loan);
|
||||
|
||||
+2
-10
@@ -18,25 +18,17 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
|
||||
public interface ReprocessLoanTransactionsService {
|
||||
|
||||
void reprocessTransactions(Loan loan);
|
||||
|
||||
void reprocessParticularTransactions(Loan loan, List<LoanTransaction> loanTransactions);
|
||||
void reprocessTransactions(Loan loan, List<LoanTransaction> loanTransactions);
|
||||
|
||||
void reprocessTransactionsWithPostTransactionChecks(Loan loan, LocalDate transactionDate);
|
||||
|
||||
void reprocessTransactionsWithoutChecks(Loan loan, LocalDate transactionDate, List<LoanTransaction> newTransactions);
|
||||
|
||||
void processPostDisbursementTransactions(Loan loan);
|
||||
|
||||
void removeLoanCharge(Loan loan, LoanCharge loanCharge);
|
||||
void reprocessTransactionsWithoutChecks(Loan loan, List<LoanTransaction> newTransactions);
|
||||
|
||||
void processLatestTransaction(LoanTransaction loanTransaction, Loan loan);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user