FINERACT-2354: In case full transaction reprocessing, we need to recalculate the schedule as well
This commit is contained in:
+3
-3
@@ -47,7 +47,7 @@ import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -67,7 +67,7 @@ public class InternalCOBApiResource implements InitializingBean {
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final ToApiJsonSerializer<List> toApiJsonSerializerForList;
|
||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final LoanScheduleService loanScheduleService;
|
||||
|
||||
protected DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN);
|
||||
|
||||
@@ -113,7 +113,7 @@ public class InternalCOBApiResource implements InitializingBean {
|
||||
@Path("loan-reprocess/{loanId}")
|
||||
@Transactional
|
||||
public void loanReprocess(@Context final UriInfo uriInfo, @PathParam("loanId") long loanId) {
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loanRepositoryWrapper.findOneWithNotFoundDetection(loanId));
|
||||
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loanRepositoryWrapper.findOneWithNotFoundDetection(loanId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-3
@@ -859,9 +859,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
loan.getLoanTransactions().add(refundTransaction);
|
||||
|
||||
+10
-29
@@ -113,9 +113,6 @@ 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.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.InstallmentNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanTransactionTypeException;
|
||||
@@ -277,20 +274,12 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
}
|
||||
|
||||
if (reprocessRequired) {
|
||||
if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction()
|
||||
|| (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
if (loan.isProgressiveSchedule()) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
if (overpaidReprocess) {
|
||||
reprocessLoanTransactionsService.reprocessTransactionsWithPostTransactionChecks(loan, transactionDate);
|
||||
} else {
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
}
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
loanLifecycleStateMachine.determineAndTransition(loan, transactionDate);
|
||||
loan = loanAccountService.saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||
}
|
||||
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled() && isAppliedOnBackDate
|
||||
@@ -600,7 +589,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
|
||||
loanChargeValidator.validateLoanIsNotClosed(loan, loanCharge);
|
||||
loanChargeValidator.validateLoanChargeIsNotWaived(loan, loanCharge);
|
||||
reprocessLoanTransactionsService.removeLoanCharge(loan, loanCharge);
|
||||
loanChargeService.removeLoanCharge(loan, loanCharge);
|
||||
this.loanRepositoryWrapper.save(loan);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanDeleteChargeBusinessEvent(loanCharge));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -857,9 +846,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
|
||||
if (reprocessRequired) {
|
||||
addInstallmentIfPenaltyAppliedAfterLastDueDate(loan, lastChargeDate);
|
||||
if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction()
|
||||
|| (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
if (loan.isProgressiveSchedule()) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
@@ -885,22 +872,16 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT);
|
||||
loanChargeAdjustmentTransaction.getLoanTransactionRelations().add(loanTransactionRelation);
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory
|
||||
.determineProcessor(loan.transactionProcessingStrategy());
|
||||
loan.addLoanTransaction(loanChargeAdjustmentTransaction);
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction()
|
||||
|| (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
if (loan.isProgressiveSchedule()) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(loanChargeAdjustmentTransaction));
|
||||
} else {
|
||||
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanChargeAdjustmentTransaction,
|
||||
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
|
||||
reprocessLoanTransactionsService.processLatestTransaction(loanChargeAdjustmentTransaction, loan);
|
||||
}
|
||||
loan.addLoanTransaction(loanChargeAdjustmentTransaction);
|
||||
loanAccountService.saveLoanTransactionWithDataIntegrityViolationChecks(loanChargeAdjustmentTransaction);
|
||||
loanLifecycleStateMachine.determineAndTransition(loan, loan.getLastUserTransactionDate());
|
||||
|
||||
@@ -1444,12 +1425,12 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(waiveLoanChargeTransaction, loanCharge,
|
||||
waiveLoanChargeTransaction.getAmount(loan.getCurrency()).getAmount(), loanInstallmentNumber);
|
||||
waiveLoanChargeTransaction.getLoanChargesPaid().add(loanChargePaidBy);
|
||||
|
||||
loan.addLoanTransaction(waiveLoanChargeTransaction);
|
||||
if (loan.isCumulativeSchedule() && loan.isInterestBearingAndInterestRecalculationEnabled()
|
||||
&& DateUtils.isBefore(loanCharge.getDueLocalDate(), businessDate)) {
|
||||
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);
|
||||
}
|
||||
// Waive of charges whose due date falls after latest 'repayment' transaction don't require entire loan schedule
|
||||
|
||||
+3
-4
@@ -66,7 +66,6 @@ public class LoanDisbursementService {
|
||||
|
||||
private final LoanChargeValidator loanChargeValidator;
|
||||
private final LoanDisbursementValidator loanDisbursementValidator;
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final LoanChargeService loanChargeService;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
private final LoanJournalEntryPoster loanJournalEntryPoster;
|
||||
@@ -326,7 +325,7 @@ public class LoanDisbursementService {
|
||||
for (LoanCharge loanCharge : tempCharges) {
|
||||
loanChargeValidator.validateLoanIsNotClosed(loan, loanCharge);
|
||||
loanChargeValidator.validateLoanChargeIsNotWaived(loan, loanCharge);
|
||||
reprocessLoanTransactionsService.removeLoanCharge(loan, loanCharge);
|
||||
loanChargeService.removeLoanCharge(loan, loanCharge);
|
||||
}
|
||||
loan.getTrancheCharges().clear();
|
||||
} else {
|
||||
@@ -336,7 +335,7 @@ public class LoanDisbursementService {
|
||||
if (loan.getCharges().contains(deleteCharge)) {
|
||||
loanChargeValidator.validateLoanIsNotClosed(loan, deleteCharge);
|
||||
loanChargeValidator.validateLoanChargeIsNotWaived(loan, deleteCharge);
|
||||
reprocessLoanTransactionsService.removeLoanCharge(loan, deleteCharge);
|
||||
loanChargeService.removeLoanCharge(loan, deleteCharge);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,7 +358,7 @@ public class LoanDisbursementService {
|
||||
loanChargeValidator.validateLoanChargeIsNotWaived(loan, charge); //
|
||||
return true; //
|
||||
}) //
|
||||
.forEach(loanCharge -> reprocessLoanTransactionsService.removeLoanCharge(loan, loanCharge));
|
||||
.forEach(loanCharge -> loanChargeService.removeLoanCharge(loan, loanCharge));
|
||||
}
|
||||
|
||||
// This method returns date format and locale if present in the JsonCommand
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class LoanPointInTimeServiceImpl implements LoanPointInTimeService {
|
||||
// the loan's state
|
||||
if (txCount != afterRemovalTxCount || chargeCount != afterRemovalChargeCount) {
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null, null);
|
||||
loanScheduleService.recalculateSchedule(loan, scheduleGeneratorDTO);
|
||||
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
LoanArrearsData arrearsData = arrearsAgingService.calculateArrearsForLoan(loan);
|
||||
|
||||
+4
-31
@@ -21,7 +21,6 @@ package org.apache.fineract.portfolio.loanaccount.service;
|
||||
import jakarta.persistence.FlushModeType;
|
||||
import java.math.MathContext;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -65,7 +64,6 @@ public class LoanTransactionProcessingServiceImpl implements LoanTransactionProc
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory;
|
||||
private final LoanTermVariationsMapper loanMapper;
|
||||
private final InterestScheduleModelRepositoryWrapper modelRepository;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
private final LoanTransactionService loanTransactionService;
|
||||
|
||||
@Override
|
||||
@@ -131,32 +129,6 @@ public class LoanTransactionProcessingServiceImpl implements LoanTransactionProc
|
||||
return transactionProcessorFactory.determineProcessor(transactionProcessingStrategyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ChangedTransactionDetail> processPostDisbursementTransactions(Loan loan) {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = getTransactionProcessor(
|
||||
loan.getTransactionProcessingStrategyCode());
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = loanTransactionService
|
||||
.retrieveListOfTransactionsForReprocessing(loan);
|
||||
|
||||
final List<LoanTransaction> copyTransactions = new ArrayList<>();
|
||||
|
||||
if (allNonContraTransactionsPostDisbursement.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// TODO: Probably this is not needed and can be eliminated, make sure to double check it
|
||||
for (LoanTransaction loanTransaction : allNonContraTransactionsPostDisbursement) {
|
||||
copyTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
|
||||
}
|
||||
final ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTransactions(
|
||||
loan.getDisbursementDate(), copyTransactions, loan.getCurrency(), loan.getRepaymentScheduleInstallments(),
|
||||
loan.getActiveCharges());
|
||||
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
|
||||
return Optional.of(changedTransactionDetail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanScheduleDTO getRecalculatedSchedule(final ScheduleGeneratorDTO generatorDTO, Loan loan) {
|
||||
if (!loan.isInterestBearingAndInterestRecalculationEnabled() || loan.isNpa() || loan.isChargedOff()) {
|
||||
@@ -232,9 +204,10 @@ public class LoanTransactionProcessingServiceImpl implements LoanTransactionProc
|
||||
AdvancedPaymentScheduleTransactionProcessor advancedProcessor, Loan loan, LoanTransaction loanTransaction) {
|
||||
Optional<ProgressiveLoanInterestScheduleModel> savedModel = modelRepository.getSavedModel(loan,
|
||||
loanTransaction.getTransactionDate());
|
||||
ProgressiveLoanInterestScheduleModel model = savedModel
|
||||
.orElseGet(() -> advancedProcessor.calculateInterestScheduleModel(loan.getId(), loanTransaction.getTransactionDate()));
|
||||
|
||||
if (savedModel.isEmpty()) {
|
||||
throw new IllegalArgumentException("No saved model found for loan transaction " + loanTransaction);
|
||||
}
|
||||
ProgressiveLoanInterestScheduleModel model = savedModel.get();
|
||||
ProgressiveTransactionCtx progressiveContext = new ProgressiveTransactionCtx(loan.getCurrency(),
|
||||
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(), new MoneyHolder(loan.getTotalOverpaidAsMoney()),
|
||||
new ChangedTransactionDetail(), model, getTotalRefundInterestAmount(loan));
|
||||
|
||||
+9
-25
@@ -21,11 +21,9 @@ package org.apache.fineract.portfolio.loanaccount.service;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
|
||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||
import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
|
||||
@@ -51,18 +49,16 @@ import org.apache.fineract.portfolio.floatingrates.exception.FloatingRateNotFoun
|
||||
import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
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;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.apache.fineract.portfolio.note.domain.Note;
|
||||
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class LoanUtilService {
|
||||
public class LoanUtilService implements ILoanUtilService {
|
||||
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
@@ -74,17 +70,20 @@ public class LoanUtilService {
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
private final NoteRepository noteRepository;
|
||||
|
||||
@Override
|
||||
public ScheduleGeneratorDTO buildScheduleGeneratorDTO(final Loan loan, final LocalDate recalculateFrom) {
|
||||
final HolidayDetailDTO holidayDetailDTO = null;
|
||||
return buildScheduleGeneratorDTO(loan, recalculateFrom, null, holidayDetailDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduleGeneratorDTO buildScheduleGeneratorDTO(final Loan loan, final LocalDate recalculateFrom,
|
||||
final LocalDate rescheduleTill) {
|
||||
final HolidayDetailDTO holidayDetailDTO = null;
|
||||
return buildScheduleGeneratorDTO(loan, recalculateFrom, rescheduleTill, holidayDetailDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduleGeneratorDTO buildScheduleGeneratorDTO(final Loan loan, final LocalDate recalculateFrom, final LocalDate recalculateTill,
|
||||
final HolidayDetailDTO holidayDetailDTO) {
|
||||
HolidayDetailDTO holidayDetails = holidayDetailDTO;
|
||||
@@ -147,6 +146,7 @@ public class LoanUtilService {
|
||||
return scheduleGeneratorDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isLoanRepaymentsSyncWithMeeting(final Group group, final Calendar calendar) {
|
||||
Boolean isSkipRepaymentOnFirstMonth = false;
|
||||
Long entityId = null;
|
||||
@@ -170,6 +170,7 @@ public class LoanUtilService {
|
||||
return isSkipRepaymentOnFirstMonth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate getCalculatedRepaymentsStartingFromDate(final Loan loan) {
|
||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstanceByEntityId(loan.getId(),
|
||||
CalendarEntityType.LOANS.getValue());
|
||||
@@ -190,6 +191,7 @@ public class LoanUtilService {
|
||||
return holidayDetailDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HolidayDetailDTO constructHolidayDTO(final Long officeId, LocalDate localDate) {
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, localDate,
|
||||
@@ -225,16 +227,6 @@ public class LoanUtilService {
|
||||
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar, calendarHistoryDataWrapper);
|
||||
}
|
||||
|
||||
public LocalDate getCalculatedRepaymentsStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan,
|
||||
final Calendar calendar) {
|
||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||
if (calendar == null) {
|
||||
return getCalculatedRepaymentsStartingFromDate(loan);
|
||||
}
|
||||
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar, calendarHistoryDataWrapper);
|
||||
|
||||
}
|
||||
|
||||
private LocalDate calculateRepaymentStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan, final Calendar calendar,
|
||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
|
||||
LocalDate calculatedRepaymentsStartingFromDate = loan.getExpectedFirstRepaymentOnDate();
|
||||
@@ -305,6 +297,7 @@ public class LoanUtilService {
|
||||
return calculatedRepaymentsStartingFromDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateRepaymentTransactionType(LoanTransactionType repaymentTransactionType) {
|
||||
if (!repaymentTransactionType.isRepaymentType()) {
|
||||
throw new PlatformServiceUnavailableException("error.msg.repaymentTransactionType.provided.not.a.repayment.type",
|
||||
@@ -313,6 +306,7 @@ public class LoanUtilService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientOrGroupActive(final Loan loan) {
|
||||
final Client client = loan.client();
|
||||
if (client != null && client.isNotActive()) {
|
||||
@@ -324,14 +318,4 @@ public class LoanUtilService {
|
||||
}
|
||||
}
|
||||
|
||||
public void persistNote(Loan loan, JsonCommand command, Map<String, Object> changes) {
|
||||
if (command.hasParameter(LoanApiConstants.noteParameterName)) {
|
||||
final String note = command.stringValueOfParameterNamed(LoanApiConstants.noteParameterName);
|
||||
final Note newNote = Note.loanNote(loan, note);
|
||||
changes.put(LoanApiConstants.noteParameterName, note);
|
||||
|
||||
noteRepository.save(newNote);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+43
-55
@@ -952,10 +952,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final boolean isTransactionChronologicallyLatest = loanTransactionService.isChronologicallyLatestRepaymentOrWaiver(loan,
|
||||
newInterestPaymentWaiverTransaction);
|
||||
|
||||
if (newInterestPaymentWaiverTransaction.isNotZero()) {
|
||||
loan.addLoanTransaction(newInterestPaymentWaiverTransaction);
|
||||
}
|
||||
|
||||
final LoanRepaymentScheduleInstallment currentInstallment = loan.fetchLoanRepaymentScheduleInstallmentByDueDate(transactionDate);
|
||||
|
||||
boolean reprocess = true;
|
||||
@@ -970,6 +966,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loanTransactionProcessingService.processLatestTransaction(loan.getTransactionProcessingStrategyCode(),
|
||||
newInterestPaymentWaiverTransaction, new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(),
|
||||
loan.getActiveCharges(), new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
|
||||
|
||||
reprocess = false;
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
if (currentInstallment == null || currentInstallment.isNotFullyPaidOff()) {
|
||||
@@ -982,22 +979,25 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!reprocess) {
|
||||
loan.addLoanTransaction(newInterestPaymentWaiverTransaction);
|
||||
}
|
||||
}
|
||||
if (reprocess) {
|
||||
reprocessChangedLoanTransactions(loan, scheduleGeneratorDTO);
|
||||
reprocessChangedLoanTransactions(loan, newInterestPaymentWaiverTransaction, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
loanLifecycleStateMachine.determineAndTransition(loan, newInterestPaymentWaiverTransaction.getTransactionDate());
|
||||
}
|
||||
|
||||
private void reprocessChangedLoanTransactions(Loan loan, ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
private void reprocessChangedLoanTransactions(Loan loan, LoanTransaction newInterestPaymentWaiverTransaction,
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
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);
|
||||
}
|
||||
|
||||
loan.addLoanTransaction(newInterestPaymentWaiverTransaction);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
@@ -1304,13 +1304,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
validateLoanTransactionAmountChargeBack(loanTransaction, newTransaction);
|
||||
|
||||
if (loan.isInterestBearing() && loan.isInterestRecalculationEnabled()) {
|
||||
if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction()
|
||||
|| (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
if (loan.isInterestBearing() && loan.isInterestRecalculationEnabled() && loan.isProgressiveSchedule()) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
// Store the Loan Transaction Relation
|
||||
@@ -2285,11 +2281,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loan.getLoanProductRelatedDetail().setPrincipal(loan.getPrincipalAmountForRepaymentSchedule());
|
||||
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.processPostDisbursementTransactions(loan);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2441,9 +2435,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|| rescheduledRepaymentDate != null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -2757,9 +2749,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, null, null);
|
||||
loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
final List<LoanTransaction> loanTransactions = loanTransactionRepository.findNonReversedTransactionsForReprocessingByLoan(loan);
|
||||
loanTransactions.add(chargeOffTransaction);
|
||||
reprocessLoanTransactionsService.reprocessParticularTransactions(loan, loanTransactions);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(chargeOffTransaction));
|
||||
loan.addLoanTransaction(chargeOffTransaction);
|
||||
} else {
|
||||
reprocessLoanTransactionsService.processLatestTransaction(chargeOffTransaction, loan);
|
||||
@@ -3010,9 +3000,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
loan.addLoanTransaction(interestRefundTxn);
|
||||
@@ -3059,13 +3047,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
public void handleChargebackTransaction(final Loan loan, LoanTransaction chargebackTransaction) {
|
||||
loanTransactionValidator.validateIfTransactionIsChargeback(chargebackTransaction);
|
||||
|
||||
loan.addLoanTransaction(chargebackTransaction);
|
||||
if (loan.isInterestBearing() && loan.isInterestRecalculationEnabled()) {
|
||||
final List<LoanTransaction> transactions = loanTransactionService.retrieveListOfTransactionsForReprocessing(loan);
|
||||
loanTransactionProcessingService.reprocessLoanTransactions(loan.getTransactionProcessingStrategyCode(),
|
||||
loan.getDisbursementDate(), transactions, loan.getCurrency(), loan.getRepaymentScheduleInstallments(),
|
||||
loan.getActiveCharges());
|
||||
loan.addLoanTransaction(chargebackTransaction);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
} else {
|
||||
loan.addLoanTransaction(chargebackTransaction);
|
||||
loanTransactionProcessingService.processLatestTransaction(loan.getTransactionProcessingStrategyCode(), chargebackTransaction,
|
||||
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
|
||||
@@ -3252,16 +3238,24 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final LoanTransaction loanTransaction = LoanTransaction.writeoff(loan, loan.getOffice(), writtenOffOnLocalDate, externalId);
|
||||
LocalDate lastTransactionDate = loan.getLastUserTransactionDate();
|
||||
if (DateUtils.isAfter(lastTransactionDate, writtenOffOnLocalDate)) {
|
||||
final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions.";
|
||||
final String errorMessage = "The date of the writeoff transaction must occur on or after previous transactions.";
|
||||
throw new InvalidLoanStateTransitionException("writeoff", "must.occur.on.or.after.other.transaction.dates", errorMessage,
|
||||
writtenOffOnLocalDate);
|
||||
}
|
||||
|
||||
loan.addLoanTransaction(loanTransaction);
|
||||
loanTransactionProcessingService.processLatestTransaction(loan.getTransactionProcessingStrategyCode(), loanTransaction,
|
||||
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
|
||||
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled()
|
||||
&& DateUtils.isBeforeBusinessDate(loanTransaction.getTransactionDate())) {
|
||||
if (loan.isProgressiveSchedule()) {
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
loan.addLoanTransaction(loanTransaction);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
} else {
|
||||
loan.addLoanTransaction(loanTransaction);
|
||||
loanTransactionProcessingService.processLatestTransaction(loan.getTransactionProcessingStrategyCode(), loanTransaction,
|
||||
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
|
||||
}
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING, loan);
|
||||
changes.put(PARAM_STATUS, LoanEnumerations.status(loan.getLoanStatus()));
|
||||
@@ -3272,17 +3266,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
if (loan.isDisbursementAllowed() && loan.atLeastOnceDisbursed()) {
|
||||
loan.getLoanRepaymentScheduleDetail().setPrincipal(loan.getDisbursedAmount());
|
||||
loan.removeDisbursementDetail();
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
if (loan.isCumulativeSchedule() && loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO);
|
||||
} else if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction()
|
||||
|| (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
if (loan.isCumulativeSchedule()) {
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO);
|
||||
} else {
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
}
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
LocalDate lastLoanTransactionDate = loan.getLatestTransactionDate();
|
||||
loanLifecycleStateMachine.determineAndTransition(loan, lastLoanTransactionDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3385,8 +3375,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -3422,7 +3411,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
&& DateUtils.isEqual(loanTermVariations.getTermApplicableFrom(), lastTransactionDate))
|
||||
|| DateUtils.isAfter(loanTermVariations.getTermApplicableFrom(), lastTransactionDate));
|
||||
reverseExistingTransactionsTillLastDisbursal(loan, lastDisbursalTransaction);
|
||||
loanScheduleService.recalculateSchedule(loan, scheduleGeneratorDTO);
|
||||
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan, scheduleGeneratorDTO);
|
||||
actualChanges.put("undolastdisbursal", "true");
|
||||
actualChanges.put("disbursedAmount", loan.getDisbursedAmount());
|
||||
loanLifecycleStateMachine.determineAndTransition(loan, loan.getLastUserTransactionDate());
|
||||
@@ -3442,8 +3431,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
"reversed");
|
||||
writeOffTransaction.reverse();
|
||||
loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO, loan);
|
||||
if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction() || (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
if (loan.isProgressiveSchedule()) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
+3
-5
@@ -81,11 +81,9 @@ public class ProgressiveLoanInterestRefundServiceImpl implements InterestRefundS
|
||||
LocalDate relatedRefundTransactionDate, List<LoanTransaction> transactionsToReprocess) {
|
||||
List<LoanRepaymentScheduleInstallment> installmentsToReprocess = new ArrayList<>(
|
||||
loan.getRepaymentScheduleInstallments().stream().filter(i -> !i.isReAged() && !i.isAdditional()).toList());
|
||||
if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction() || (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
|
||||
Pair<ChangedTransactionDetail, ProgressiveLoanInterestScheduleModel> reprocessResult = processor
|
||||
.reprocessProgressiveLoanTransactions(loan.getDisbursementDate(), relatedRefundTransactionDate, transactionsToReprocess,
|
||||
|
||||
+1
-28
@@ -21,23 +21,16 @@ package org.apache.fineract.portfolio.loanaccount.service;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionBalance;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
||||
@@ -51,10 +44,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Slf4j
|
||||
public class ProgressiveLoanSummaryDataProvider extends CommonLoanSummaryDataProvider {
|
||||
|
||||
private final AdvancedPaymentScheduleTransactionProcessor advancedPaymentScheduleTransactionProcessor;
|
||||
private final EMICalculator emiCalculator;
|
||||
private final LoanRepositoryWrapper loanRepository;
|
||||
private final LoanTransactionRepository loanTransactionRepository;
|
||||
private final InterestScheduleModelRepositoryWrapper modelRepository;
|
||||
|
||||
@Override
|
||||
@@ -81,24 +72,6 @@ public class ProgressiveLoanSummaryDataProvider extends CommonLoanSummaryDataPro
|
||||
&& businessDate.isAfter(i.getFromDate()) && !businessDate.isAfter(i.getDueDate())).findFirst();
|
||||
}
|
||||
|
||||
private ProgressiveLoanInterestScheduleModel calculateModel(Loan loan, LocalDate businessDate) {
|
||||
final List<LoanTransaction> transactionsToReprocess = loanTransactionRepository
|
||||
.findNonReversedTransactionsForReprocessingByLoan(loan).stream().filter(t -> !t.isAccrualActivity()).toList();
|
||||
Pair<ChangedTransactionDetail, ProgressiveLoanInterestScheduleModel> changedTransactionDetailProgressiveLoanInterestScheduleModelPair = advancedPaymentScheduleTransactionProcessor
|
||||
.reprocessProgressiveLoanTransactions(loan.getDisbursementDate(), businessDate, transactionsToReprocess, loan.getCurrency(),
|
||||
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges());
|
||||
ProgressiveLoanInterestScheduleModel model = changedTransactionDetailProgressiveLoanInterestScheduleModelPair.getRight();
|
||||
final List<Long> replayedTransactions = changedTransactionDetailProgressiveLoanInterestScheduleModelPair.getLeft()
|
||||
.getTransactionChanges().stream().filter(change -> change.getOldTransaction() != null && change.getNewTransaction() != null)
|
||||
.map(change -> change.getNewTransaction().getId()).filter(Objects::nonNull).toList();
|
||||
|
||||
if (!replayedTransactions.isEmpty()) {
|
||||
log.warn("Reprocessed transactions show differences: There are unsaved changes of the following transactions: {}",
|
||||
replayedTransactions);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(final Loan loan,
|
||||
final Collection<LoanSchedulePeriodData> periods, final LocalDate businessDate, final CurrencyData currency,
|
||||
@@ -117,7 +90,7 @@ public class ProgressiveLoanSummaryDataProvider extends CommonLoanSummaryDataPro
|
||||
|
||||
Optional<ProgressiveLoanInterestScheduleModel> savedModel = modelRepository.getSavedModel(loan, businessDate);
|
||||
|
||||
ProgressiveLoanInterestScheduleModel model = savedModel.orElseGet(() -> calculateModel(loan, businessDate));
|
||||
ProgressiveLoanInterestScheduleModel model = savedModel.orElse(null);
|
||||
if (model != null) {
|
||||
OutstandingDetails outstandingDetails = emiCalculator.getOutstandingAmountsTillDate(model, businessDate);
|
||||
if (!loan.isInterestRecalculationEnabled()) {
|
||||
|
||||
+16
-97
@@ -19,10 +19,8 @@
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import jakarta.persistence.FlushModeType;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.annotation.WithFlushMode;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
@@ -30,16 +28,11 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.transaction
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanAccrualTransactionCreatedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionBusinessEvent;
|
||||
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;
|
||||
import org.apache.fineract.portfolio.interestpauses.service.LoanAccountTransfersService;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.TransactionChangeData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
@@ -78,111 +71,41 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reprocessParticularTransactions(final Loan loan, final List<LoanTransaction> loanTransactions) {
|
||||
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan, loanTransactions);
|
||||
handleChangedDetail(changedTransactionDetail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reprocessTransactionsWithPostTransactionChecks(final Loan loan, final LocalDate transactionDate) {
|
||||
public void reprocessTransactions(final Loan loan, final List<LoanTransaction> newTransactions) {
|
||||
final List<LoanTransaction> transactions = loanTransactionRepository.findNonReversedTransactionsForReprocessingByLoan(loan);
|
||||
transactions.addAll(newTransactions);
|
||||
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan, transactions);
|
||||
handleChangedDetail(changedTransactionDetail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reprocessTransactionsWithoutChecks(final Loan loan, final LocalDate transactionDate,
|
||||
final List<LoanTransaction> newTransactions) {
|
||||
public void reprocessTransactionsWithoutChecks(final Loan loan, final List<LoanTransaction> newTransactions) {
|
||||
final List<LoanTransaction> transactions = loanTransactionRepository.findNonReversedTransactionsForReprocessingByLoan(loan);
|
||||
transactions.addAll(newTransactions);
|
||||
reprocessTransactionsAndFetchChangedTransactions(loan, transactions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processPostDisbursementTransactions(final Loan loan) {
|
||||
loanTransactionProcessingService.processPostDisbursementTransactions(loan).ifPresent(this::handleChangedDetail);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
|
||||
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loan.getCurrency())) {
|
||||
/*
|
||||
* TODO Vishwas Currently we do not allow removing a loan charge after a loan is approved (hence there is no
|
||||
* need to adjust any loan transactions).
|
||||
*
|
||||
* Consider removing this block of code or logically completing it for the future by getting the list of
|
||||
* affected Transactions
|
||||
*/
|
||||
reprocessTransactions(loan);
|
||||
return;
|
||||
}
|
||||
loan.getLoanCharges().remove(loanCharge);
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLatestTransaction(final LoanTransaction loanTransaction, final Loan loan) {
|
||||
LoanRepaymentScheduleTransactionProcessor transactionProcessor = loanTransactionProcessingService
|
||||
.getTransactionProcessor(loan.getTransactionProcessingStrategyCode());
|
||||
|
||||
TransactionCtx transactionCtx;
|
||||
if (transactionProcessor instanceof AdvancedPaymentScheduleTransactionProcessor advancedProcessor) {
|
||||
if (transactionProcessor instanceof AdvancedPaymentScheduleTransactionProcessor) {
|
||||
Optional<ProgressiveLoanInterestScheduleModel> savedModel = interestScheduleModelRepositoryWrapper.getSavedModel(loan,
|
||||
loanTransaction.getTransactionDate());
|
||||
ProgressiveLoanInterestScheduleModel model = savedModel
|
||||
.orElseGet(() -> advancedProcessor.calculateInterestScheduleModel(loan.getId(), loanTransaction.getTransactionDate()));
|
||||
if (savedModel.isEmpty()) {
|
||||
throw new IllegalArgumentException("No saved model found for loan transaction " + loanTransaction);
|
||||
} else {
|
||||
|
||||
final ProgressiveTransactionCtx progressiveTransactionCtx = new ProgressiveTransactionCtx(loan.getCurrency(),
|
||||
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(), new MoneyHolder(loan.getTotalOverpaidAsMoney()),
|
||||
new ChangedTransactionDetail(), model);
|
||||
progressiveTransactionCtx.setChargedOff(loan.isChargedOff());
|
||||
progressiveTransactionCtx.setWrittenOff(loan.isClosedWrittenOff());
|
||||
progressiveTransactionCtx.setContractTerminated(loan.isContractTermination());
|
||||
transactionCtx = progressiveTransactionCtx;
|
||||
final ProgressiveTransactionCtx progressiveTransactionCtx = new ProgressiveTransactionCtx(loan.getCurrency(),
|
||||
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(), new MoneyHolder(loan.getTotalOverpaidAsMoney()),
|
||||
new ChangedTransactionDetail(), savedModel.get());
|
||||
progressiveTransactionCtx.setChargedOff(loan.isChargedOff());
|
||||
progressiveTransactionCtx.setWrittenOff(loan.isClosedWrittenOff());
|
||||
progressiveTransactionCtx.setContractTerminated(loan.isContractTermination());
|
||||
transactionCtx = progressiveTransactionCtx;
|
||||
}
|
||||
} else {
|
||||
transactionCtx = new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
new MoneyHolder(loan.getTotalOverpaidAsMoney()), new ChangedTransactionDetail());
|
||||
@@ -201,11 +124,7 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
|
||||
|
||||
@Override
|
||||
public void updateModel(Loan loan) {
|
||||
Optional<ProgressiveLoanInterestScheduleModel> savedModel = interestScheduleModelRepositoryWrapper.getSavedModel(loan,
|
||||
ThreadLocalContextUtil.getBusinessDate());
|
||||
if (savedModel.isEmpty()) {
|
||||
reprocessTransactions(loan);
|
||||
}
|
||||
interestScheduleModelRepositoryWrapper.getSavedModel(loan, ThreadLocalContextUtil.getBusinessDate());
|
||||
}
|
||||
|
||||
private void handleChangedDetail(final ChangedTransactionDetail changedTransactionDetail) {
|
||||
|
||||
+3
-1
@@ -67,6 +67,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualsProcessingS
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanDownPaymentHandlerService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanJournalEntryPoster;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||
import org.apache.fineract.portfolio.note.domain.Note;
|
||||
@@ -100,6 +101,7 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository;
|
||||
private final LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository;
|
||||
private final LoanScheduleService loanScheduleService;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult adjustLoanTransaction(Loan loan, LoanTransaction transactionToAdjust, LoanAdjustmentParameter parameter,
|
||||
@@ -346,7 +348,7 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
}
|
||||
|
||||
if (transactionForAdjustment.getTypeOf().equals(LoanTransactionType.CAPITALIZED_INCOME)) {
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-18
@@ -76,7 +76,7 @@ public class LoanContractTerminationServiceImpl {
|
||||
private final LoanTransactionService loanTransactionService;
|
||||
|
||||
public CommandProcessingResult applyContractTermination(final JsonCommand command) {
|
||||
final Loan loan = loanAssembler.assembleFrom(command.getLoanId());
|
||||
Loan loan = loanAssembler.assembleFrom(command.getLoanId());
|
||||
// validate client or group is active
|
||||
loanUtilService.checkClientOrGroupActive(loan);
|
||||
|
||||
@@ -87,7 +87,19 @@ public class LoanContractTerminationServiceImpl {
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
|
||||
final LoanTransaction contractTermination = LoanTransaction.contractTermination(loan, DateUtils.getBusinessLocalDate(), externalId);
|
||||
loanTransactionRepository.save(contractTermination);
|
||||
|
||||
// Mark Contract Termination, Update Loan SubStatus
|
||||
loan.setLoanSubStatus(LoanSubStatus.CONTRACT_TERMINATION);
|
||||
changes.put(LoanApiConstants.subStatusAttributeName, loan.getLoanSubStatus().getCode());
|
||||
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(contractTermination));
|
||||
loan.addLoanTransaction(contractTermination);
|
||||
} else {
|
||||
reprocessLoanTransactionsService.processLatestTransaction(contractTermination, loan);
|
||||
loan.addLoanTransaction(contractTermination);
|
||||
}
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
@@ -95,22 +107,7 @@ public class LoanContractTerminationServiceImpl {
|
||||
final Note note = Note.loanTransactionNote(loan, contractTermination, noteText);
|
||||
noteRepository.save(note);
|
||||
}
|
||||
|
||||
// Mark Contract Termination, Update Loan SubStatus
|
||||
loan.setLoanSubStatus(LoanSubStatus.CONTRACT_TERMINATION);
|
||||
loanRepository.save(loan);
|
||||
changes.put(LoanApiConstants.subStatusAttributeName, loan.getLoanSubStatus().getCode());
|
||||
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
final List<LoanTransaction> loanTransactions = loanTransactionService.retrieveListOfTransactionsForReprocessing(loan);
|
||||
loanTransactions.add(contractTermination);
|
||||
reprocessLoanTransactionsService.reprocessParticularTransactions(loan, loanTransactions);
|
||||
loan.addLoanTransaction(contractTermination);
|
||||
} else {
|
||||
reprocessLoanTransactionsService.processLatestTransaction(contractTermination, loan);
|
||||
loan.addLoanTransaction(contractTermination);
|
||||
}
|
||||
|
||||
loanTransactionRepository.saveAndFlush(contractTermination);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanTransactionContractTerminationPostBusinessEvent(contractTermination));
|
||||
|
||||
|
||||
+12
-27
@@ -62,17 +62,16 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepositor
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeInterestHandlingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.InterestScheduleModelRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanRepaymentScheduleService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||
import org.apache.fineract.portfolio.note.domain.Note;
|
||||
@@ -100,14 +99,16 @@ public class LoanReAgingService {
|
||||
private final LoanRepaymentScheduleService loanRepaymentScheduleService;
|
||||
private final LoanReadPlatformService loanReadPlatformService;
|
||||
private final LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository;
|
||||
private final InterestScheduleModelRepositoryWrapper modelRepository;
|
||||
private final LoanTransactionService loanTransactionService;
|
||||
|
||||
public CommandProcessingResult reAge(final Long loanId, final JsonCommand command) {
|
||||
final Loan loan = loanAssembler.assembleFrom(loanId);
|
||||
reAgingValidator.validateReAge(loan, command);
|
||||
|
||||
final LoanTransaction reAgeTransaction = createReAgeTransaction(loan, command);
|
||||
loanTransactionRepository.saveAndFlush(reAgeTransaction);
|
||||
processReAgeTransaction(loan, reAgeTransaction, true);
|
||||
loanTransactionRepository.saveAndFlush(reAgeTransaction);
|
||||
loan.updateLoanScheduleDependentDerivedFields();
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
@@ -170,8 +171,7 @@ public class LoanReAgingService {
|
||||
if (reAgeTransaction == null) {
|
||||
throw new LoanTransactionNotFoundException("Re-Age transaction for loan was not found");
|
||||
}
|
||||
if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction() || (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
if (loan.isProgressiveSchedule()) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
@@ -196,31 +196,16 @@ public class LoanReAgingService {
|
||||
}
|
||||
|
||||
private void processReAgeTransaction(final Loan loan, final LoanTransaction reAgeTransaction, final boolean withPostTransactionChecks) {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory
|
||||
.determineProcessor(loan.transactionProcessingStrategy());
|
||||
if (reAgeTransaction.getTransactionDate().isBefore(reAgeTransaction.getSubmittedOnDate())
|
||||
&& !loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
if (reAgeTransaction.getTransactionDate().isBefore(reAgeTransaction.getSubmittedOnDate())) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
if (withPostTransactionChecks) {
|
||||
reprocessLoanTransactionsService.reprocessTransactionsWithPostTransactionChecks(loan,
|
||||
reAgeTransaction.getTransactionDate());
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(reAgeTransaction));
|
||||
} else {
|
||||
reprocessLoanTransactionsService.reprocessTransactionsWithoutChecks(loan, reAgeTransaction.getTransactionDate(),
|
||||
List.of(reAgeTransaction));
|
||||
reprocessLoanTransactionsService.reprocessTransactionsWithoutChecks(loan, List.of(reAgeTransaction));
|
||||
}
|
||||
} else if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
if (loan.isProgressiveSchedule() && ((loan.hasChargeOffTransaction() && loan.hasAccelerateChargeOffStrategy())
|
||||
|| loan.hasContractTerminationTransaction()
|
||||
|| (loan.isInterestRecalculationEnabled() && loan.hasReAgingTransaction()))) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null);
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
final List<LoanTransaction> loanTransactions = loanTransactionRepository.findNonReversedTransactionsForReprocessingByLoan(loan);
|
||||
loanTransactions.add(reAgeTransaction);
|
||||
reprocessLoanTransactionsService.reprocessParticularTransactions(loan, loanTransactions);
|
||||
} else {
|
||||
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(reAgeTransaction,
|
||||
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
|
||||
reprocessLoanTransactionsService.processLatestTransaction(reAgeTransaction, loan);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -21,8 +21,6 @@ package org.apache.fineract.portfolio.loanaccount.starter;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor;
|
||||
@@ -136,12 +134,11 @@ public class LoanAccountAutoStarter {
|
||||
@Bean
|
||||
@Conditional(AdvancedPaymentScheduleTransactionProcessorCondition.class)
|
||||
public AdvancedPaymentScheduleTransactionProcessor advancedPaymentScheduleTransactionProcessor(final EMICalculator emiCalculator,
|
||||
final LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
final @Lazy ProgressiveLoanInterestRefundServiceImpl progressiveLoanInterestRefundService,
|
||||
final ExternalIdFactory externalIdFactory, final LoanScheduleComponent loanSchedule,
|
||||
final LoanTransactionRepository loanTransactionRepository, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService, @Lazy final LoanChargeService loanChargeService) {
|
||||
return new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, loanRepositoryWrapper, progressiveLoanInterestRefundService,
|
||||
externalIdFactory, loanSchedule, loanTransactionRepository, loanChargeValidator, loanBalanceService, loanChargeService);
|
||||
final LoanChargeValidator loanChargeValidator, final LoanBalanceService loanBalanceService,
|
||||
@Lazy final LoanChargeService loanChargeService) {
|
||||
return new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, progressiveLoanInterestRefundService, externalIdFactory,
|
||||
loanSchedule, loanChargeValidator, loanBalanceService, loanChargeService);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -112,6 +112,7 @@ import org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoReadPlat
|
||||
import org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoWritePlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoWritePlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ILoanUtilService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.InterestRefundServiceDelegate;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccountServiceImpl;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualActivityProcessingService;
|
||||
@@ -495,11 +496,10 @@ public class LoanAccountConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(LoanDisbursementService.class)
|
||||
public LoanDisbursementService loanDisbursementService(LoanChargeValidator loanChargeValidator,
|
||||
LoanDisbursementValidator loanDisbursementValidator, ReprocessLoanTransactionsService reprocessLoanTransactionsService,
|
||||
LoanChargeService loanChargeService, LoanBalanceService loanBalanceService, LoanJournalEntryPoster journalEntryPoster,
|
||||
LoanTransactionRepository loanTransactionRepository) {
|
||||
return new LoanDisbursementService(loanChargeValidator, loanDisbursementValidator, reprocessLoanTransactionsService,
|
||||
loanChargeService, loanBalanceService, journalEntryPoster, loanTransactionRepository);
|
||||
LoanDisbursementValidator loanDisbursementValidator, LoanChargeService loanChargeService, LoanBalanceService loanBalanceService,
|
||||
LoanJournalEntryPoster journalEntryPoster, LoanTransactionRepository loanTransactionRepository) {
|
||||
return new LoanDisbursementService(loanChargeValidator, loanDisbursementValidator, loanChargeService, loanBalanceService,
|
||||
journalEntryPoster, loanTransactionRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -515,9 +515,9 @@ public class LoanAccountConfiguration {
|
||||
public LoanScheduleService loanScheduleService(final LoanChargeService loanChargeService,
|
||||
final ReprocessLoanTransactionsService reprocessLoanTransactionsService, final LoanMapper loanMapper,
|
||||
final LoanTransactionProcessingService loanTransactionProcessingService, LoanScheduleComponent loanSchedule,
|
||||
final LoanTransactionRepository loanTransactionRepository) {
|
||||
final LoanTransactionRepository loanTransactionRepository, final ILoanUtilService loanUtilService) {
|
||||
return new LoanScheduleService(loanChargeService, reprocessLoanTransactionsService, loanMapper, loanTransactionProcessingService,
|
||||
loanSchedule, loanTransactionRepository);
|
||||
loanSchedule, loanTransactionRepository, loanUtilService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -544,9 +544,9 @@ public class LoanAccountConfiguration {
|
||||
@ConditionalOnMissingBean(InterestPauseWritePlatformService.class)
|
||||
public InterestPauseWritePlatformService interestPauseWritePlatformService(LoanTermVariationsRepository loanTermVariationsRepository,
|
||||
LoanRepositoryWrapper loanRepositoryWrapper, LoanAssembler loanAssembler,
|
||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService, BusinessEventNotifierService businessEventNotifierService) {
|
||||
BusinessEventNotifierService businessEventNotifierService, LoanScheduleService loanScheduleService) {
|
||||
return new InterestPauseWritePlatformServiceImpl(loanTermVariationsRepository, loanRepositoryWrapper, loanAssembler,
|
||||
reprocessLoanTransactionsService, businessEventNotifierService);
|
||||
businessEventNotifierService, loanScheduleService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+3
@@ -165,6 +165,9 @@ class LoanChargeWritePlatformServiceImplTest {
|
||||
@Mock
|
||||
private LoanJournalEntryPoster journalEntryPoster;
|
||||
|
||||
@Mock
|
||||
private LoanScheduleService loanScheduleService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(loanAssembler.assembleFrom(LOAN_ID)).thenReturn(loan);
|
||||
|
||||
Reference in New Issue
Block a user