FINERACT-2080: Extract calculations from loan entity
This commit is contained in:
committed by
Adam Saghy
parent
18a55874ba
commit
47d5330802
+8
-4
@@ -104,11 +104,13 @@ import org.apache.fineract.portfolio.loanaccount.service.InterestRefundServiceDe
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualTransactionBusinessEventService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualsProcessingService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanDownPaymentHandlerService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanRefundService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionProcessingService;
|
||||
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.loanproduct.domain.LoanSupportedInterestRefundTypes;
|
||||
@@ -147,7 +149,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||
private final LoanAccrualsProcessingService loanAccrualsProcessingService;
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory;
|
||||
private final InterestRefundServiceDelegate interestRefundServiceDelegate;
|
||||
private final LoanTransactionValidator loanTransactionValidator;
|
||||
private final LoanForeclosureValidator loanForeclosureValidator;
|
||||
@@ -161,6 +162,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||
private final LoanTransactionProcessingService loanTransactionProcessingService;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
private final LoanTransactionService loanTransactionService;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -767,7 +770,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
existingTransactionIds.addAll(loan.findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = null;
|
||||
final LoanRepaymentScheduleInstallment foreCloseDetail = loan.fetchLoanForeclosureDetail(foreClosureDate);
|
||||
final LoanRepaymentScheduleInstallment foreCloseDetail = loanBalanceService.fetchLoanForeclosureDetail(loan, foreClosureDate);
|
||||
|
||||
loanAccrualsProcessingService.processAccrualsOnLoanForeClosure(loan, foreClosureDate, newTransactions);
|
||||
|
||||
@@ -875,7 +878,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
LoanTransaction refundTransaction = LoanTransaction.refund(loan, loanTransactionType, transactionAmount, paymentDetail,
|
||||
transactionDate, txnExternalId);
|
||||
|
||||
final boolean isTransactionChronologicallyLatest = loan.isChronologicallyLatestRepaymentOrWaiver(refundTransaction);
|
||||
final boolean isTransactionChronologicallyLatest = loanTransactionService.isChronologicallyLatestRepaymentOrWaiver(loan,
|
||||
refundTransaction);
|
||||
|
||||
boolean shouldCreateInterestRefundTransaction = loan.getLoanProductRelatedDetail().getSupportedInterestRefundTypes().stream()
|
||||
.map(LoanSupportedInterestRefundTypes::getTransactionType)
|
||||
@@ -1002,7 +1006,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
final List<LoanRepaymentScheduleInstallment> newInstallments = new ArrayList<>(loan.getRepaymentScheduleInstallments());
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
final Money[] balances = loan.retrieveIncomeForOverlappingPeriod(transactionDate);
|
||||
final Money[] balances = loanBalanceService.retrieveIncomeForOverlappingPeriod(loan, transactionDate);
|
||||
boolean isInterestComponent = true;
|
||||
for (final LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) {
|
||||
if (!DateUtils.isAfter(transactionDate, installment.getDueDate())) {
|
||||
|
||||
+2
-1
@@ -1571,7 +1571,8 @@ public class LoanScheduleAssembler {
|
||||
for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) {
|
||||
if (loanScheduleModelPeriod instanceof LoanScheduleModelDisbursementPeriod) {
|
||||
for (final LoanCharge loanCharge : nonCompoundingCharges) {
|
||||
loanCharge.populateDerivedFields(totalInterest, loanCharge.amountOrPercentage(), null, BigDecimal.ZERO);
|
||||
loanChargeService.populateDerivedFields(loanCharge, totalInterest, loanCharge.amountOrPercentage(), null,
|
||||
BigDecimal.ZERO);
|
||||
loanScheduleModelPeriod.addLoanCharges(loanCharge.getAmountOutstanding(), BigDecimal.ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -55,6 +55,7 @@ public class LoanAccrualActivityProcessingServiceImpl implements LoanAccrualActi
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final LoanTransactionAssembler loanTransactionAssembler;
|
||||
private final LoanAccountService loanAccountService;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
@@ -93,7 +94,7 @@ public class LoanAccrualActivityProcessingServiceImpl implements LoanAccrualActi
|
||||
return;
|
||||
}
|
||||
|
||||
LocalDate closureDate = loan.isOverPaid() ? loan.getOverpaidOnDate() : loan.getClosedOnDate();
|
||||
LocalDate closureDate = loanBalanceService.isOverPaid(loan) ? loan.getOverpaidOnDate() : loan.getClosedOnDate();
|
||||
|
||||
// Reverse accrual activities posted after the closure date
|
||||
loan.getLoanTransactions(t -> t.isAccrualActivity() && !t.isReversed() && t.getDateOf().isAfter(closureDate))
|
||||
|
||||
+3
-2
@@ -113,6 +113,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||
private final LoanChargeService loanChargeService;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
|
||||
/**
|
||||
* method adds accrual for batch job "Add Periodic Accrual Transactions" and add accruals api for Loan
|
||||
@@ -307,7 +308,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
|
||||
// TODO implement progressive accrual case
|
||||
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()
|
||||
&& (loan.getAccruedTill() == null || !DateUtils.isEqual(foreClosureDate, loan.getAccruedTill()))) {
|
||||
final LoanRepaymentScheduleInstallment foreCloseDetail = loan.fetchLoanForeclosureDetail(foreClosureDate);
|
||||
final LoanRepaymentScheduleInstallment foreCloseDetail = loanBalanceService.fetchLoanForeclosureDetail(loan, foreClosureDate);
|
||||
MonetaryCurrency currency = loan.getCurrency();
|
||||
reverseTransactionsAfter(retrieveListOfAccrualTransactions(loan), foreClosureDate, false);
|
||||
|
||||
@@ -494,7 +495,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
|
||||
Money interest = null;
|
||||
final boolean isPastPeriod = isAfterPeriod(tillDate, installment);
|
||||
final boolean isInPeriod = isInPeriod(tillDate, installment, false);
|
||||
if (isPastPeriod || loan.isClosed() || loan.isOverPaid()) {
|
||||
if (isPastPeriod || loan.isClosed() || loanBalanceService.isOverPaid(loan)) {
|
||||
interest = installment.getInterestCharged(currency).minus(installment.getCreditedInterest());
|
||||
} else {
|
||||
if (isInPeriod) { // first period first day is not accrued
|
||||
|
||||
+6
-5
@@ -61,6 +61,7 @@ public class LoanChargeAssembler {
|
||||
private final LoanChargeRepository loanChargeRepository;
|
||||
private final LoanProductRepository loanProductRepository;
|
||||
private final ExternalIdFactory externalIdFactory;
|
||||
private final LoanChargeService loanChargeService;
|
||||
|
||||
public Set<LoanCharge> fromParsedJson(final JsonElement element, List<LoanDisbursementDetails> disbursementDetails) {
|
||||
JsonArray jsonDisbursement = this.fromApiJsonHelper.extractJsonArrayNamed("disbursementData", element);
|
||||
@@ -210,7 +211,7 @@ public class LoanChargeAssembler {
|
||||
.orElseThrow(() -> new LoanChargeNotFoundException(loanChargeId));
|
||||
|
||||
if (!loanCharge.isTrancheDisbursementCharge() || disbursementChargeIds.contains(loanChargeId)) {
|
||||
loanCharge.update(amount, dueDate, numberOfRepayments);
|
||||
loanChargeService.update(loanCharge, amount, dueDate, numberOfRepayments);
|
||||
loanCharges.add(loanCharge);
|
||||
}
|
||||
|
||||
@@ -296,7 +297,7 @@ public class LoanChargeAssembler {
|
||||
if (percentage == null) {
|
||||
percentage = chargeDefinition.getAmount();
|
||||
}
|
||||
loanCharge = LoanCharge.calculatePerInstallmentChargeAmount(loan,
|
||||
loanCharge = loanChargeService.calculatePerInstallmentChargeAmount(loan,
|
||||
ChargeCalculationType.fromInt(chargeDefinition.getChargeCalculation()), percentage);
|
||||
}
|
||||
|
||||
@@ -314,7 +315,7 @@ public class LoanChargeAssembler {
|
||||
}
|
||||
|
||||
ExternalId externalId = externalIdFactory.createFromCommand(command, "externalId");
|
||||
return new LoanCharge(loan, chargeDefinition, amountPercentageAppliedTo, amount, chargeTime, chargeCalculation, dueDate,
|
||||
return loanChargeService.create(loan, chargeDefinition, amountPercentageAppliedTo, amount, chargeTime, chargeCalculation, dueDate,
|
||||
chargePaymentMode, null, loanCharge, externalId);
|
||||
}
|
||||
|
||||
@@ -324,7 +325,7 @@ public class LoanChargeAssembler {
|
||||
public LoanCharge createNewWithoutLoan(final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate,
|
||||
final ChargePaymentMode chargePaymentMode, final Integer numberOfRepayments, final ExternalId externalId) {
|
||||
return new LoanCharge(null, chargeDefinition, loanPrincipal, amount, chargeTime, chargeCalculation, dueDate, chargePaymentMode,
|
||||
numberOfRepayments, BigDecimal.ZERO, externalId);
|
||||
return loanChargeService.create(null, chargeDefinition, loanPrincipal, amount, chargeTime, chargeCalculation, dueDate,
|
||||
chargePaymentMode, numberOfRepayments, BigDecimal.ZERO, externalId);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -288,9 +288,9 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
.equals(loan.transactionProcessingStrategy())) {
|
||||
// [For Adv payment allocation strategy] check if charge due date is earlier than last transaction
|
||||
// date, if yes trigger reprocess else no reprocessing
|
||||
LoanTransaction lastPaymentTransaction = loan.getLastTransactionForReprocessing();
|
||||
if (lastPaymentTransaction != null
|
||||
&& DateUtils.isAfter(loanCharge.getEffectiveDueDate(), lastPaymentTransaction.getTransactionDate())) {
|
||||
final Optional<LocalDate> lastPaymentTransactionDate = loanTransactionRepository.findLastTransactionDateForReprocessing(loan);
|
||||
if (lastPaymentTransactionDate.isPresent()
|
||||
&& DateUtils.isAfter(loanCharge.getEffectiveDueDate(), lastPaymentTransactionDate.get())) {
|
||||
reprocessRequired = false;
|
||||
}
|
||||
}
|
||||
@@ -475,7 +475,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
||||
final Map<String, Object> changes = new LinkedHashMap<>(3);
|
||||
if (loan.getActiveCharges().contains(loanCharge)) {
|
||||
final BigDecimal amount = loanChargeService.calculateAmountPercentageAppliedTo(loan, loanCharge);
|
||||
final Map<String, Object> loanChargeChanges = loanCharge.update(command, amount);
|
||||
final Map<String, Object> loanChargeChanges = loanChargeService.update(command, amount, loanCharge);
|
||||
changes.putAll(loanChargeChanges);
|
||||
loan.updateSummaryWithTotalFeeChargesDueAtDisbursement(loan.deriveSumTotalOfChargesDueAtDisbursement());
|
||||
}
|
||||
|
||||
+2
-2
@@ -244,8 +244,8 @@ public class LoanDisbursementService {
|
||||
if (TemporaryConfigurationServiceContainer.isExternalIdAutoGenerationEnabled()) {
|
||||
externalId = ExternalId.generate();
|
||||
}
|
||||
final LoanCharge loanCharge = new LoanCharge(loan, chargeDefinition, principal, null, null, null, expectedDisbursementDate,
|
||||
null, null, BigDecimal.ZERO, externalId);
|
||||
final LoanCharge loanCharge = loanChargeService.create(loan, chargeDefinition, principal, null, null, null,
|
||||
expectedDisbursementDate, null, null, BigDecimal.ZERO, externalId);
|
||||
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = new LoanTrancheDisbursementCharge(loanCharge,
|
||||
disbursementDetails);
|
||||
loanCharge.updateLoanTrancheDisbursementCharge(loanTrancheDisbursementCharge);
|
||||
|
||||
+5
-2
@@ -179,6 +179,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
private final LoanForeclosureValidator loanForeclosureValidator;
|
||||
private final LoanTransactionMapper loanTransactionMapper;
|
||||
private final LoanTransactionProcessingService loadTransactionProcessingService;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
|
||||
@Override
|
||||
public LoanAccountData retrieveOne(final Long loanId) {
|
||||
@@ -2088,7 +2089,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
|
||||
final LocalDate earliestUnpaidInstallmentDate = DateUtils.getBusinessLocalDate();
|
||||
|
||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchLoanForeclosureDetail(transactionDate);
|
||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loanBalanceService.fetchLoanForeclosureDetail(loan,
|
||||
transactionDate);
|
||||
BigDecimal unrecognizedIncomePortion = null;
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
@@ -2236,7 +2238,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
return loanRepositoryWrapper.existsByLoanId(loanId);
|
||||
}
|
||||
|
||||
private LoanTransaction deriveDefaultInterestWaiverTransaction(Loan loan) {
|
||||
private LoanTransaction deriveDefaultInterestWaiverTransaction(final Loan loan) {
|
||||
final Money totalInterestOutstanding = loan.getTotalInterestOutstandingOnLoan();
|
||||
Money possibleInterestToWaive = totalInterestOutstanding.copy();
|
||||
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
|
||||
@@ -2260,4 +2262,5 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
return LoanTransaction.waiver(loan.getOffice(), loan, possibleInterestToWaive, transactionDate, possibleInterestToWaive,
|
||||
possibleInterestToWaive.zero(), ExternalId.empty());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-3
@@ -61,6 +61,8 @@ public class LoanTransactionProcessingServiceImpl implements LoanTransactionProc
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory;
|
||||
private final LoanTermVariationsMapper loanMapper;
|
||||
private final InterestScheduleModelRepositoryWrapper modelRepository;
|
||||
private final LoanTransactionService loanTransactionService;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
|
||||
@Override
|
||||
public boolean canProcessLatestTransactionOnly(Loan loan, LoanTransaction loanTransaction,
|
||||
@@ -86,7 +88,7 @@ public class LoanTransactionProcessingServiceImpl implements LoanTransactionProc
|
||||
ProgressiveTransactionCtx progressiveContext = new ProgressiveTransactionCtx(loan.getCurrency(),
|
||||
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(), new MoneyHolder(loan.getTotalOverpaidAsMoney()),
|
||||
new ChangedTransactionDetail(), savedModel.orElse(null), getTotalRefundInterestAmount(loan));
|
||||
progressiveContext.getAlreadyProcessedTransactions().addAll(loan.retrieveListOfTransactionsForReprocessing());
|
||||
progressiveContext.getAlreadyProcessedTransactions().addAll(loanTransactionService.retrieveListOfTransactionsForReprocessing(loan));
|
||||
progressiveContext.setChargedOff(loan.isChargedOff());
|
||||
ChangedTransactionDetail result = advancedProcessor.processLatestTransaction(loanTransaction, progressiveContext);
|
||||
if (savedModel.isPresent() && !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
@@ -158,7 +160,9 @@ public class LoanTransactionProcessingServiceImpl implements LoanTransactionProc
|
||||
public Optional<ChangedTransactionDetail> processPostDisbursementTransactions(Loan loan) {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = getTransactionProcessor(
|
||||
loan.getTransactionProcessingStrategyCode());
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = loan.retrieveListOfTransactionsForReprocessing();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = loanTransactionService
|
||||
.retrieveListOfTransactionsForReprocessing(loan);
|
||||
|
||||
final List<LoanTransaction> copyTransactions = new ArrayList<>();
|
||||
|
||||
if (allNonContraTransactionsPostDisbursement.isEmpty()) {
|
||||
@@ -173,7 +177,7 @@ public class LoanTransactionProcessingServiceImpl implements LoanTransactionProc
|
||||
loan.getDisbursementDate(), copyTransactions, loan.getCurrency(), loan.getRepaymentScheduleInstallments(),
|
||||
loan.getActiveCharges());
|
||||
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
|
||||
return Optional.of(changedTransactionDetail);
|
||||
}
|
||||
|
||||
+136
-130
@@ -287,6 +287,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
|
||||
private final LoanMapper loanMapper;
|
||||
private final LoanTransactionProcessingService loanTransactionProcessingService;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
private final LoanTransactionService loanTransactionService;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -572,7 +574,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loanTransactionValidator.validateActivityNotBeforeClientOrGroupTransferDate(loan, LoanEvent.LOAN_DISBURSED,
|
||||
actualDisbursementDate1);
|
||||
loanDisbursementService.handleDisbursementTransaction(loan, actualDisbursementDate1, paymentDetail1);
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
final Money interestApplied = Money.of(loan.getCurrency(), loan.getSummary().getTotalInterestCharged());
|
||||
|
||||
/*
|
||||
@@ -591,11 +593,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
|
||||
if (loan.getLoanProduct().isMultiDisburseLoan() || loan.isProgressiveSchedule()) {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = loan.retrieveListOfTransactionsForReprocessing();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = loanTransactionService
|
||||
.retrieveListOfTransactionsForReprocessing(loan);
|
||||
if (!allNonContraTransactionsPostDisbursement.isEmpty()) {
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan);
|
||||
}
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
}
|
||||
|
||||
loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, loan);
|
||||
@@ -972,8 +975,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
newInterestPaymentWaiverTransaction.updateLoan(loan);
|
||||
|
||||
final boolean isTransactionChronologicallyLatest = loan
|
||||
.isChronologicallyLatestRepaymentOrWaiver(newInterestPaymentWaiverTransaction);
|
||||
final boolean isTransactionChronologicallyLatest = loanTransactionService.isChronologicallyLatestRepaymentOrWaiver(loan,
|
||||
newInterestPaymentWaiverTransaction);
|
||||
|
||||
if (newInterestPaymentWaiverTransaction.isNotZero()) {
|
||||
loan.addLoanTransaction(newInterestPaymentWaiverTransaction);
|
||||
@@ -1412,7 +1415,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
Money unrecognizedIncome = transactionAmountAsMoney.zero();
|
||||
Money interestComponent = transactionAmountAsMoney;
|
||||
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||
Money receivableInterest = loan.getReceivableInterest(transactionDate);
|
||||
Money receivableInterest = loanBalanceService.getReceivableInterest(loan, transactionDate);
|
||||
if (transactionAmountAsMoney.isGreaterThan(receivableInterest)) {
|
||||
interestComponent = receivableInterest;
|
||||
unrecognizedIncome = transactionAmountAsMoney.minus(receivableInterest);
|
||||
@@ -2024,119 +2027,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
}
|
||||
|
||||
public void updateLoanRepaymentScheduleDates(final Loan loan, final LocalDate meetingStartDate, final String recuringRule,
|
||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||
final boolean isSkipRepaymentonfirstdayofmonth, final Integer numberofDays) {
|
||||
// first repayment's from date is same as disbursement date.
|
||||
LocalDate tmpFromDate = loan.getDisbursementDate();
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType = loan.getLoanRepaymentScheduleDetail().getRepaymentPeriodFrequencyType();
|
||||
final Integer loanRepaymentInterval = loan.getLoanRepaymentScheduleDetail().getRepayEvery();
|
||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
|
||||
LocalDate newRepaymentDate;
|
||||
LocalDate latestRepaymentDate = null;
|
||||
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
|
||||
// FIXME: AA this won't update repayment dates before current date.
|
||||
if (DateUtils.isAfter(oldDueDate, meetingStartDate) && DateUtils.isDateInTheFuture(oldDueDate)) {
|
||||
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate,
|
||||
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
|
||||
|
||||
final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(repaymentPeriodFrequencyType,
|
||||
loanRepaymentInterval, tmpFromDate);
|
||||
|
||||
if (DateUtils.isAfter(newRepaymentDate, maxDateLimitForNewRepayment)) {
|
||||
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, meetingStartDate, tmpFromDate,
|
||||
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
|
||||
}
|
||||
|
||||
if (isHolidayEnabled) {
|
||||
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
|
||||
}
|
||||
if (DateUtils.isBefore(latestRepaymentDate, newRepaymentDate)) {
|
||||
latestRepaymentDate = newRepaymentDate;
|
||||
}
|
||||
|
||||
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
|
||||
// reset from date to get actual daysInPeriod
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
tmpFromDate = newRepaymentDate;// update with new repayment date
|
||||
} else {
|
||||
tmpFromDate = oldDueDate;
|
||||
}
|
||||
}
|
||||
if (latestRepaymentDate != null) {
|
||||
loan.setExpectedMaturityDate(latestRepaymentDate);
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDate getMaxDateLimitForNewRepayment(final PeriodFrequencyType periodFrequencyType, final Integer loanRepaymentInterval,
|
||||
final LocalDate startDate) {
|
||||
LocalDate dueRepaymentPeriodDate = startDate;
|
||||
final int repaidEvery = 2 * loanRepaymentInterval;
|
||||
switch (periodFrequencyType) {
|
||||
case DAYS -> dueRepaymentPeriodDate = startDate.plusDays(repaidEvery);
|
||||
case WEEKS -> dueRepaymentPeriodDate = startDate.plusWeeks(repaidEvery);
|
||||
case MONTHS -> dueRepaymentPeriodDate = startDate.plusMonths(repaidEvery);
|
||||
case YEARS -> dueRepaymentPeriodDate = startDate.plusYears(repaidEvery);
|
||||
case INVALID, WHOLE_TERM -> {
|
||||
}
|
||||
}
|
||||
return dueRepaymentPeriodDate.minusDays(1);// get 2n-1 range date from startDate
|
||||
}
|
||||
|
||||
private void updateLoanRepaymentScheduleDates(final Loan loan, final String recurringRule, final boolean isHolidayEnabled,
|
||||
final List<Holiday> holidays, final WorkingDays workingDays, final LocalDate presentMeetingDate, final LocalDate newMeetingDate,
|
||||
final boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays) {
|
||||
// first repayment's from date is same as disbursement date.
|
||||
// meetingStartDate is used as seedDate Capture the seedDate from user and use the seedDate as meetingStart date
|
||||
|
||||
LocalDate tmpFromDate = loan.getDisbursementDate();
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType = loan.getLoanRepaymentScheduleDetail().getRepaymentPeriodFrequencyType();
|
||||
final Integer loanRepaymentInterval = loan.getLoanRepaymentScheduleDetail().getRepayEvery();
|
||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
|
||||
LocalDate newRepaymentDate;
|
||||
boolean isFirstTime = true;
|
||||
LocalDate latestRepaymentDate = null;
|
||||
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
if (!DateUtils.isBefore(oldDueDate, presentMeetingDate)) {
|
||||
if (isFirstTime) {
|
||||
isFirstTime = false;
|
||||
newRepaymentDate = newMeetingDate;
|
||||
} else {
|
||||
// tmpFromDate.plusDays(1) is done to make sure
|
||||
// getNewRepaymentMeetingDate method returns next meeting
|
||||
// date and not the same as tmpFromDate
|
||||
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recurringRule, tmpFromDate, tmpFromDate.plusDays(1),
|
||||
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays);
|
||||
}
|
||||
|
||||
if (isHolidayEnabled) {
|
||||
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
|
||||
}
|
||||
if (DateUtils.isBefore(latestRepaymentDate, newRepaymentDate)) {
|
||||
latestRepaymentDate = newRepaymentDate;
|
||||
}
|
||||
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
|
||||
// reset from date to get actual daysInPeriod
|
||||
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
|
||||
tmpFromDate = newRepaymentDate;// update with new repayment date
|
||||
} else {
|
||||
tmpFromDate = oldDueDate;
|
||||
}
|
||||
}
|
||||
if (latestRepaymentDate != null) {
|
||||
loan.setExpectedMaturityDate(latestRepaymentDate);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLoanCycle(final Loan loan) {
|
||||
final List<Loan> loansToUpdate;
|
||||
if (loan.isGroupLoan()) {
|
||||
@@ -2924,7 +2814,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, null, null);
|
||||
loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
final List<LoanTransaction> loanTransactions = loan.retrieveListOfTransactionsForReprocessing();
|
||||
final List<LoanTransaction> loanTransactions = loanTransactionService.retrieveListOfTransactionsForReprocessing(loan);
|
||||
loanTransactions.add(chargeOffTransaction);
|
||||
reprocessLoanTransactionsService.reprocessParticularTransactions(loan, loanTransactions);
|
||||
loan.addLoanTransaction(chargeOffTransaction);
|
||||
@@ -3117,9 +3007,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
loan.addLoanTransaction(chargebackTransaction);
|
||||
if (loan.isInterestBearing() && loan.isInterestRecalculationEnabled()) {
|
||||
final List<LoanTransaction> transactions = loanTransactionService.retrieveListOfTransactionsForReprocessing(loan);
|
||||
loanTransactionProcessingService.reprocessLoanTransactions(loan.getTransactionProcessingStrategyCode(),
|
||||
loan.getDisbursementDate(), loan.retrieveListOfTransactionsForReprocessing(), loan.getCurrency(),
|
||||
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges());
|
||||
loan.getDisbursementDate(), transactions, loan.getCurrency(), loan.getRepaymentScheduleInstallments(),
|
||||
loan.getActiveCharges());
|
||||
} else {
|
||||
loanTransactionProcessingService.processLatestTransaction(loan.getTransactionProcessingStrategyCode(), chargebackTransaction,
|
||||
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
@@ -3215,7 +3106,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
loan.adjustNetDisbursalAmount(loan.getApprovedPrincipal());
|
||||
actualChanges.put(ACTUAL_DISBURSEMENT_DATE, "");
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
@@ -3246,7 +3137,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(loan.getCurrency(), loan.getDisbursementDate(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges());
|
||||
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
}
|
||||
|
||||
private void reverseExistingTransactions(final Loan loan) {
|
||||
@@ -3319,7 +3210,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
|
||||
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
|
||||
return Optional.of(loanTransaction);
|
||||
}
|
||||
@@ -3383,7 +3274,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
changes.put("externalId", externalId);
|
||||
loanTransaction = LoanTransaction.writeoff(loan, loan.getOffice(), closureDate, externalId);
|
||||
final boolean isLastTransaction = loan.isChronologicallyLatestTransaction(loanTransaction, loan.getLoanTransactions());
|
||||
final boolean isLastTransaction = loanTransactionRepository.isChronologicallyLatest(loanTransaction.getTransactionDate(),
|
||||
loan);
|
||||
if (!isLastTransaction) {
|
||||
final String errorMessage = "The closing date of the loan must be on or after latest transaction date.";
|
||||
throw new InvalidLoanStateTransitionException("close.loan", "must.occur.on.or.after.latest.transaction.date",
|
||||
@@ -3395,7 +3287,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
|
||||
new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
|
||||
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
} else if (totalOutstanding.isGreaterThanZero()) {
|
||||
final String errorMessage = "A loan with money outstanding cannot be closed";
|
||||
throw new InvalidLoanStateTransitionException("close", "loan.has.money.outstanding", errorMessage,
|
||||
@@ -3403,8 +3295,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
}
|
||||
|
||||
if (loan.isOverPaid()) {
|
||||
final Money totalLoanOverpayment = loan.calculateTotalOverpayment();
|
||||
if (loanBalanceService.isOverPaid(loan)) {
|
||||
final Money totalLoanOverpayment = loanBalanceService.calculateTotalOverpayment(loan);
|
||||
if (totalLoanOverpayment.isGreaterThanZero() && loan.getInArrearsTolerance().isGreaterThanOrEqualTo(totalLoanOverpayment)) {
|
||||
// TODO - KW - technically should set somewhere that this loan
|
||||
// has 'overpaid' amount
|
||||
@@ -3474,7 +3366,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
final LoanDisbursementDetails disbursementDetail = loan.getDisbursementDetails(lastTransactionDate,
|
||||
lastDisbursalTransaction.getAmount());
|
||||
loan.updateLoanToLastDisbursalState(disbursementDetail);
|
||||
loanBalanceService.updateLoanToLastDisbursalState(loan, disbursementDetail);
|
||||
loan.getLoanTermVariations()
|
||||
.removeIf(loanTermVariations -> (loanTermVariations.getTermType().isDueDateVariation()
|
||||
&& DateUtils.isAfter(loanTermVariations.fetchDateValue(), lastTransactionDate))
|
||||
@@ -3579,4 +3471,118 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
return !statusEnum.hasStateOf(actualLoanStatus) || isMultiTrancheDisburse;
|
||||
}
|
||||
|
||||
private void updateLoanRepaymentScheduleDates(final Loan loan, final LocalDate meetingStartDate, final String recuringRule,
|
||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||
final boolean isSkipRepaymentonfirstdayofmonth, final Integer numberofDays) {
|
||||
// first repayment's from date is same as disbursement date.
|
||||
LocalDate tmpFromDate = loan.getDisbursementDate();
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType = loan.getLoanRepaymentScheduleDetail().getRepaymentPeriodFrequencyType();
|
||||
final Integer loanRepaymentInterval = loan.getLoanRepaymentScheduleDetail().getRepayEvery();
|
||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
|
||||
LocalDate newRepaymentDate;
|
||||
LocalDate latestRepaymentDate = null;
|
||||
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
|
||||
// FIXME: AA this won't update repayment dates before current date.
|
||||
if (DateUtils.isAfter(oldDueDate, meetingStartDate) && DateUtils.isDateInTheFuture(oldDueDate)) {
|
||||
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate,
|
||||
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
|
||||
|
||||
final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(repaymentPeriodFrequencyType,
|
||||
loanRepaymentInterval, tmpFromDate);
|
||||
|
||||
if (DateUtils.isAfter(newRepaymentDate, maxDateLimitForNewRepayment)) {
|
||||
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, meetingStartDate, tmpFromDate,
|
||||
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
|
||||
}
|
||||
|
||||
if (isHolidayEnabled) {
|
||||
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
|
||||
}
|
||||
if (DateUtils.isBefore(latestRepaymentDate, newRepaymentDate)) {
|
||||
latestRepaymentDate = newRepaymentDate;
|
||||
}
|
||||
|
||||
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
|
||||
// reset from date to get actual daysInPeriod
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
tmpFromDate = newRepaymentDate;// update with new repayment date
|
||||
} else {
|
||||
tmpFromDate = oldDueDate;
|
||||
}
|
||||
}
|
||||
if (latestRepaymentDate != null) {
|
||||
loan.setExpectedMaturityDate(latestRepaymentDate);
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDate getMaxDateLimitForNewRepayment(final PeriodFrequencyType periodFrequencyType, final Integer loanRepaymentInterval,
|
||||
final LocalDate startDate) {
|
||||
LocalDate dueRepaymentPeriodDate = startDate;
|
||||
final int repaidEvery = 2 * loanRepaymentInterval;
|
||||
switch (periodFrequencyType) {
|
||||
case DAYS -> dueRepaymentPeriodDate = startDate.plusDays(repaidEvery);
|
||||
case WEEKS -> dueRepaymentPeriodDate = startDate.plusWeeks(repaidEvery);
|
||||
case MONTHS -> dueRepaymentPeriodDate = startDate.plusMonths(repaidEvery);
|
||||
case YEARS -> dueRepaymentPeriodDate = startDate.plusYears(repaidEvery);
|
||||
case INVALID, WHOLE_TERM -> {
|
||||
}
|
||||
}
|
||||
return dueRepaymentPeriodDate.minusDays(1);// get 2n-1 range date from startDate
|
||||
}
|
||||
|
||||
private void updateLoanRepaymentScheduleDates(final Loan loan, final String recurringRule, final boolean isHolidayEnabled,
|
||||
final List<Holiday> holidays, final WorkingDays workingDays, final LocalDate presentMeetingDate, final LocalDate newMeetingDate,
|
||||
final boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays) {
|
||||
// first repayment's from date is same as disbursement date.
|
||||
// meetingStartDate is used as seedDate Capture the seedDate from user and use the seedDate as meetingStart date
|
||||
|
||||
LocalDate tmpFromDate = loan.getDisbursementDate();
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType = loan.getLoanRepaymentScheduleDetail().getRepaymentPeriodFrequencyType();
|
||||
final Integer loanRepaymentInterval = loan.getLoanRepaymentScheduleDetail().getRepayEvery();
|
||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
|
||||
LocalDate newRepaymentDate;
|
||||
boolean isFirstTime = true;
|
||||
LocalDate latestRepaymentDate = null;
|
||||
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
if (!DateUtils.isBefore(oldDueDate, presentMeetingDate)) {
|
||||
if (isFirstTime) {
|
||||
isFirstTime = false;
|
||||
newRepaymentDate = newMeetingDate;
|
||||
} else {
|
||||
// tmpFromDate.plusDays(1) is done to make sure
|
||||
// getNewRepaymentMeetingDate method returns next meeting
|
||||
// date and not the same as tmpFromDate
|
||||
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recurringRule, tmpFromDate, tmpFromDate.plusDays(1),
|
||||
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays);
|
||||
}
|
||||
|
||||
if (isHolidayEnabled) {
|
||||
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
|
||||
}
|
||||
if (DateUtils.isBefore(latestRepaymentDate, newRepaymentDate)) {
|
||||
latestRepaymentDate = newRepaymentDate;
|
||||
}
|
||||
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
|
||||
// reset from date to get actual daysInPeriod
|
||||
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
|
||||
tmpFromDate = newRepaymentDate;// update with new repayment date
|
||||
} else {
|
||||
tmpFromDate = oldDueDate;
|
||||
}
|
||||
}
|
||||
if (latestRepaymentDate != null) {
|
||||
loan.setExpectedMaturityDate(latestRepaymentDate);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -53,6 +53,7 @@ public class ProgressiveLoanSummaryDataProvider extends CommonLoanSummaryDataPro
|
||||
private final AdvancedPaymentScheduleTransactionProcessor advancedPaymentScheduleTransactionProcessor;
|
||||
private final EMICalculator emiCalculator;
|
||||
private final LoanRepositoryWrapper loanRepository;
|
||||
private final LoanTransactionService loanTransactionService;
|
||||
private final InterestScheduleModelRepositoryWrapper modelRepository;
|
||||
|
||||
@Override
|
||||
@@ -80,8 +81,8 @@ public class ProgressiveLoanSummaryDataProvider extends CommonLoanSummaryDataPro
|
||||
}
|
||||
|
||||
private ProgressiveLoanInterestScheduleModel calculateModel(Loan loan, LocalDate businessDate) {
|
||||
List<LoanTransaction> transactionsToReprocess = loan.retrieveListOfTransactionsForReprocessing().stream()
|
||||
.filter(t -> !t.isAccrualActivity()).toList();
|
||||
final List<LoanTransaction> transactionsToReprocess = loanTransactionService.retrieveListOfTransactionsForReprocessing(loan)
|
||||
.stream().filter(t -> !t.isAccrualActivity()).toList();
|
||||
Pair<ChangedTransactionDetail, ProgressiveLoanInterestScheduleModel> changedTransactionDetailProgressiveLoanInterestScheduleModelPair = advancedPaymentScheduleTransactionProcessor
|
||||
.reprocessProgressiveLoanTransactions(loan.getDisbursementDate(), businessDate, transactionsToReprocess, loan.getCurrency(),
|
||||
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges());
|
||||
|
||||
+22
-6
@@ -22,6 +22,8 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
@@ -35,6 +37,8 @@ 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.LoanTransactionComparator;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel;
|
||||
@@ -49,15 +53,27 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
|
||||
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
|
||||
private final LoanTransactionProcessingService loanTransactionProcessingService;
|
||||
private final InterestScheduleModelRepositoryWrapper interestScheduleModelRepositoryWrapper;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
private final LoanTransactionRepository loanTransactionRepository;
|
||||
|
||||
@Override
|
||||
public void reprocessTransactions(final Loan loan) {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = loan.retrieveListOfTransactionsForReprocessing();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsForReprocessing(loan);
|
||||
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan,
|
||||
allNonContraTransactionsPostDisbursement);
|
||||
handleChangedDetail(changedTransactionDetail);
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retrieveListOfTransactionsForReprocessing(final Loan loan) {
|
||||
return loan.getLoanTransactions().stream().filter(loanTransactionForReprocessingPredicate())
|
||||
.sorted(LoanTransactionComparator.INSTANCE).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Predicate<LoanTransaction> loanTransactionForReprocessingPredicate() {
|
||||
return transaction -> transaction.isNotReversed() && (transaction.isChargeOff() || transaction.isReAge()
|
||||
|| transaction.isAccrualActivity() || transaction.isReAmortize() || !transaction.isNonMonetaryTransaction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reprocessParticularTransactions(final Loan loan, final List<LoanTransaction> loanTransactions) {
|
||||
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan, loanTransactions);
|
||||
@@ -66,8 +82,8 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
|
||||
|
||||
@Override
|
||||
public void reprocessTransactionsWithPostTransactionChecks(final Loan loan, final LocalDate transactionDate) {
|
||||
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan,
|
||||
loan.retrieveListOfTransactionsForReprocessing());
|
||||
final List<LoanTransaction> transactions = retrieveListOfTransactionsForReprocessing(loan);
|
||||
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan, transactions);
|
||||
handleChangedDetail(changedTransactionDetail);
|
||||
}
|
||||
|
||||
@@ -101,7 +117,7 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
|
||||
return;
|
||||
}
|
||||
loan.getLoanCharges().remove(loanCharge);
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
}
|
||||
|
||||
private void removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(final Loan loan, final LoanCharge loanCharge) {
|
||||
@@ -147,7 +163,7 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
|
||||
.map(TransactionChangeData::getNewTransaction).peek(transaction -> transaction.updateLoan(loan)).toList();
|
||||
loan.getLoanTransactions().addAll(newTransactions);
|
||||
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
handleChangedDetail(changedTransactionDetail);
|
||||
}
|
||||
|
||||
@@ -185,7 +201,7 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
|
||||
final List<LoanTransaction> newTransactions = changedTransactionDetail.getTransactionChanges().stream()
|
||||
.map(TransactionChangeData::getNewTransaction).toList();
|
||||
loan.getLoanTransactions().addAll(newTransactions);
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
loanBalanceService.updateLoanSummaryDerivedFields(loan);
|
||||
return changedTransactionDetail;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -60,6 +60,7 @@ import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidat
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanTransactionValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualTransactionBusinessEventService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualsProcessingService;
|
||||
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.LoanUtilService;
|
||||
@@ -91,6 +92,7 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
private final LoanAccrualsProcessingService loanAccrualsProcessingService;
|
||||
private final LoanChargeValidator loanChargeValidator;
|
||||
private final LoanJournalEntryPoster journalEntryPoster;
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult adjustLoanTransaction(Loan loan, LoanTransaction transactionToAdjust, LoanAdjustmentParameter parameter,
|
||||
@@ -112,7 +114,7 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
Money unrecognizedIncome = transactionAmountAsMoney.zero();
|
||||
Money interestComponent = transactionAmountAsMoney;
|
||||
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||
Money receivableInterest = loan.getReceivableInterest(transactionDate);
|
||||
Money receivableInterest = loanBalanceService.getReceivableInterest(loan, transactionDate);
|
||||
if (transactionAmountAsMoney.isGreaterThan(receivableInterest)) {
|
||||
interestComponent = receivableInterest;
|
||||
unrecognizedIncome = transactionAmountAsMoney.minus(receivableInterest);
|
||||
|
||||
+42
-23
@@ -33,6 +33,9 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.imp
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.RBILoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanInterestRefundServiceImpl;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
||||
@@ -48,63 +51,77 @@ public class LoanAccountAutoStarter {
|
||||
@Bean
|
||||
@Conditional(CreocoreLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public CreocoreLoanRepaymentScheduleTransactionProcessor creocoreLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new CreocoreLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new CreocoreLoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator, loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(EarlyRepaymentLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public EarlyPaymentLoanRepaymentScheduleTransactionProcessor earlyPaymentLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new EarlyPaymentLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new EarlyPaymentLoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator, loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(MifosStandardLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public FineractStyleLoanRepaymentScheduleTransactionProcessor fineractStyleLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new FineractStyleLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new FineractStyleLoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator, loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(HeavensFamilyLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public HeavensFamilyLoanRepaymentScheduleTransactionProcessor heavensFamilyLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new HeavensFamilyLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new HeavensFamilyLoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator, loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(InterestPrincipalPenaltiesFeesLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor interestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator,
|
||||
loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(PrincipalInterestPenaltiesFeesLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor principalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator,
|
||||
loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(RBIIndiaLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public RBILoanRepaymentScheduleTransactionProcessor rbiLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
return new RBILoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
public RBILoanRepaymentScheduleTransactionProcessor rbiLoanRepaymentScheduleTransactionProcessor(
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new RBILoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator, loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor duePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator,
|
||||
loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor duePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(externalIdFactory, loanChargeValidator,
|
||||
loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -117,11 +134,13 @@ public class LoanAccountAutoStarter {
|
||||
|
||||
@Bean
|
||||
@Conditional(AdvancedPaymentScheduleTransactionProcessorCondition.class)
|
||||
public AdvancedPaymentScheduleTransactionProcessor advancedPaymentScheduleTransactionProcessor(EMICalculator emiCalculator,
|
||||
LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
@Lazy ProgressiveLoanInterestRefundServiceImpl progressiveLoanInterestRefundService, ExternalIdFactory externalIdFactory,
|
||||
LoanScheduleComponent loanSchedule) {
|
||||
public AdvancedPaymentScheduleTransactionProcessor advancedPaymentScheduleTransactionProcessor(final EMICalculator emiCalculator,
|
||||
final LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
final @Lazy ProgressiveLoanInterestRefundServiceImpl progressiveLoanInterestRefundService,
|
||||
final ExternalIdFactory externalIdFactory, final LoanScheduleComponent loanSchedule,
|
||||
final LoanTransactionService loanTransactionService, final LoanChargeValidator loanChargeValidator,
|
||||
final LoanBalanceService loanBalanceService) {
|
||||
return new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, loanRepositoryWrapper, progressiveLoanInterestRefundService,
|
||||
externalIdFactory, loanSchedule);
|
||||
externalIdFactory, loanSchedule, loanTransactionService, loanChargeValidator, loanBalanceService);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-14
@@ -118,6 +118,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanArrearsAgingService
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanArrearsAgingServiceImpl;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssemblerImpl;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanCalculateRepaymentPastDueService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanCapitalizedIncomeAmortizationEventService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanCapitalizedIncomeAmortizationProcessingService;
|
||||
@@ -143,6 +144,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanStatusChangePlatfor
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionProcessingService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionRelationReadService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformServiceJpaRepositoryImpl;
|
||||
@@ -268,11 +270,11 @@ public class LoanAccountConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(LoanChargeAssembler.class)
|
||||
public LoanChargeAssembler loanChargeAssembler(
|
||||
|
||||
FromJsonHelper fromApiJsonHelper, ChargeRepositoryWrapper chargeRepository, LoanChargeRepository loanChargeRepository,
|
||||
LoanProductRepository loanProductRepository, ExternalIdFactory externalIdFactory) {
|
||||
return new LoanChargeAssembler(fromApiJsonHelper, chargeRepository, loanChargeRepository, loanProductRepository, externalIdFactory);
|
||||
public LoanChargeAssembler loanChargeAssembler(final FromJsonHelper fromApiJsonHelper, final ChargeRepositoryWrapper chargeRepository,
|
||||
final LoanChargeRepository loanChargeRepository, final LoanProductRepository loanProductRepository,
|
||||
final ExternalIdFactory externalIdFactory, final LoanChargeService loanChargeService) {
|
||||
return new LoanChargeAssembler(fromApiJsonHelper, chargeRepository, loanChargeRepository, loanProductRepository, externalIdFactory,
|
||||
loanChargeService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -331,14 +333,14 @@ public class LoanAccountConfiguration {
|
||||
DelinquencyReadPlatformService delinquencyReadPlatformService, LoanTransactionRepository loanTransactionRepository,
|
||||
LoanChargePaidByReadService loanChargePaidByReadService, LoanTransactionRelationReadService loanTransactionRelationReadService,
|
||||
LoanForeclosureValidator loanForeclosureValidator, LoanTransactionMapper loanTransactionMapper,
|
||||
LoanTransactionProcessingService loanTransactionProcessingService) {
|
||||
LoanTransactionProcessingService loanTransactionProcessingService, LoanBalanceService loanBalanceService) {
|
||||
return new LoanReadPlatformServiceImpl(jdbcTemplate, context, loanRepositoryWrapper, applicationCurrencyRepository,
|
||||
loanProductReadPlatformService, clientReadPlatformService, groupReadPlatformService, loanDropdownReadPlatformService,
|
||||
fundReadPlatformService, chargeReadPlatformService, codeValueReadPlatformService, calendarReadPlatformService,
|
||||
staffReadPlatformService, paginationHelper, paymentTypeReadPlatformService, floatingRatesReadPlatformService,
|
||||
loanUtilService, configurationDomainService, accountDetailsReadPlatformService, columnValidator, sqlGenerator,
|
||||
delinquencyReadPlatformService, loanTransactionRepository, loanChargePaidByReadService, loanTransactionRelationReadService,
|
||||
loanForeclosureValidator, loanTransactionMapper, loanTransactionProcessingService);
|
||||
loanForeclosureValidator, loanTransactionMapper, loanTransactionProcessingService, loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -402,7 +404,8 @@ public class LoanAccountConfiguration {
|
||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanAccountService loanAccountService,
|
||||
LoanJournalEntryPoster journalEntryPoster, LoanAdjustmentService loanAdjustmentService,
|
||||
LoanAccountingBridgeMapper loanAccountingBridgeMapper, LoanMapper loanMapper,
|
||||
LoanTransactionProcessingService loanTransactionProcessingService) {
|
||||
LoanTransactionProcessingService loanTransactionProcessingService, final LoanBalanceService loanBalanceService,
|
||||
LoanTransactionService loanTransactionService) {
|
||||
return new LoanWritePlatformServiceJpaRepositoryImpl(context, loanTransactionValidator, loanUpdateCommandFromApiJsonDeserializer,
|
||||
loanRepositoryWrapper, loanAccountDomainService, noteRepository, loanTransactionRepository,
|
||||
loanTransactionRelationRepository, loanAssembler, journalEntryWritePlatformService, calendarInstanceRepository,
|
||||
@@ -417,7 +420,7 @@ public class LoanAccountConfiguration {
|
||||
loanTransactionAssembler, loanAccrualsProcessingService, loanOfficerValidator, loanDownPaymentTransactionValidator,
|
||||
loanDisbursementService, loanScheduleService, loanChargeValidator, loanOfficerService, reprocessLoanTransactionsService,
|
||||
loanAccountService, journalEntryPoster, loanAdjustmentService, loanAccountingBridgeMapper, loanMapper,
|
||||
loanTransactionProcessingService);
|
||||
loanTransactionProcessingService, loanBalanceService, loanTransactionService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -434,10 +437,12 @@ public class LoanAccountConfiguration {
|
||||
LoanDownPaymentTransactionValidator loanDownPaymentTransactionValidator, LoanScheduleService loanScheduleService,
|
||||
LoanRefundService loanRefundService, LoanRefundValidator loanRefundValidator,
|
||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService,
|
||||
LoanTransactionProcessingService loanTransactionProcessingService, LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
LoanTransactionProcessingService loanTransactionProcessingService, LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||
LoanBalanceService loanBalanceService, LoanTransactionService loanTransactionService) {
|
||||
return new LoanDownPaymentHandlerServiceImpl(loanTransactionRepository, businessEventNotifierService,
|
||||
loanDownPaymentTransactionValidator, loanScheduleService, loanRefundService, loanRefundValidator,
|
||||
reprocessLoanTransactionsService, loanTransactionProcessingService, loanLifecycleStateMachine);
|
||||
reprocessLoanTransactionsService, loanTransactionProcessingService, loanLifecycleStateMachine, loanBalanceService,
|
||||
loanTransactionService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -457,9 +462,10 @@ public class LoanAccountConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(LoanChargeService.class)
|
||||
public LoanChargeService loanChargeService(LoanChargeValidator loanChargeValidator,
|
||||
LoanTransactionProcessingService loanTransactionProcessingService, LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
return new LoanChargeService(loanChargeValidator, loanTransactionProcessingService, loanLifecycleStateMachine);
|
||||
public LoanChargeService loanChargeService(final LoanChargeValidator loanChargeValidator,
|
||||
final LoanTransactionProcessingService loanTransactionProcessingService,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanBalanceService loanBalanceService) {
|
||||
return new LoanChargeService(loanChargeValidator, loanTransactionProcessingService, loanLifecycleStateMachine, loanBalanceService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+12
-3
@@ -87,12 +87,17 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionProcessingService;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -122,6 +127,9 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
|
||||
@Mock
|
||||
private AvroDateTimeMapper mapper;
|
||||
|
||||
private final LoanChargeService loanChargeService = new LoanChargeService(mock(LoanChargeValidator.class),
|
||||
mock(LoanTransactionProcessingService.class), mock(LoanLifecycleStateMachine.class), mock(LoanBalanceService.class));
|
||||
|
||||
private MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
|
||||
|
||||
private static final String CUSTOM_DATA_PREFIX = "test_data_loan_delinquency_range_business_event";
|
||||
@@ -275,7 +283,7 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
|
||||
.thenReturn(installmentDelinquencyTags);
|
||||
|
||||
when(loanForProcessing.getLoanCharges()).thenAnswer(a -> repaymentScheduleInstallments.get(0).getInstallmentCharges().stream()
|
||||
.map(c -> c.getLoanCharge()).collect(Collectors.toList()));
|
||||
.map(LoanInstallmentCharge::getLoanCharge).collect(Collectors.toSet()));
|
||||
|
||||
// when
|
||||
LoanAccountDelinquencyRangeDataV1 data = (LoanAccountDelinquencyRangeDataV1) serializer.toAvroDTO(event);
|
||||
@@ -431,8 +439,9 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
|
||||
}
|
||||
|
||||
private LoanCharge buildLoanCharge(Loan loan, BigDecimal amount, Charge charge) {
|
||||
LoanCharge loanCharge = new LoanCharge(loan, charge, amount, amount, ChargeTimeType.SPECIFIED_DUE_DATE, ChargeCalculationType.FLAT,
|
||||
LocalDate.of(2022, 6, 27), ChargePaymentMode.REGULAR, 1, new BigDecimal(100), ExternalId.generate());
|
||||
LoanCharge loanCharge = loanChargeService.create(loan, charge, amount, amount, ChargeTimeType.SPECIFIED_DUE_DATE,
|
||||
ChargeCalculationType.FLAT, LocalDate.of(2022, 6, 27), ChargePaymentMode.REGULAR, 1, new BigDecimal(100),
|
||||
ExternalId.generate());
|
||||
ReflectionTestUtils.setField(loanCharge, "id", 1L);
|
||||
return loanCharge;
|
||||
}
|
||||
|
||||
+5
-1
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -48,6 +49,9 @@ class DefaultLoanLifecycleStateMachineTest {
|
||||
@Mock
|
||||
private BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Mock
|
||||
private LoanBalanceService loanBalanceService;
|
||||
|
||||
private DefaultLoanLifecycleStateMachine underTest;
|
||||
|
||||
private MockedStatic<MoneyHelper> moneyHelperStatic;
|
||||
@@ -58,7 +62,7 @@ class DefaultLoanLifecycleStateMachineTest {
|
||||
moneyHelperStatic = Mockito.mockStatic(MoneyHelper.class);
|
||||
moneyHelperStatic.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.UP));
|
||||
moneyHelperStatic.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.UP);
|
||||
underTest = new DefaultLoanLifecycleStateMachine(businessEventNotifierService);
|
||||
underTest = new DefaultLoanLifecycleStateMachine(businessEventNotifierService, loanBalanceService);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
||||
+3
-1
@@ -41,6 +41,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.apache.fineract.portfolio.rate.domain.Rate;
|
||||
@@ -61,7 +63,7 @@ public class LoanBuilder {
|
||||
private Staff loanOfficer;
|
||||
private CodeValue loanPurpose;
|
||||
private LoanRepaymentScheduleTransactionProcessor transactionProcessor = new InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(
|
||||
mock(ExternalIdFactory.class));
|
||||
mock(ExternalIdFactory.class), mock(LoanChargeValidator.class), mock(LoanBalanceService.class));
|
||||
private LoanProductRelatedDetail loanRepaymentScheduleDetail;
|
||||
private LoanStatus loanStatus = LoanStatus.SUBMITTED_AND_PENDING_APPROVAL;
|
||||
private LoanSubStatus loanSubStatus;
|
||||
|
||||
+18
-3
@@ -265,8 +265,23 @@ public class LoanTest {
|
||||
* @return the {@link LoanCharge}
|
||||
*/
|
||||
private LoanCharge buildLoanCharge() {
|
||||
return new LoanCharge(mock(Loan.class), mock(Charge.class), new BigDecimal(100), new BigDecimal(100),
|
||||
ChargeTimeType.TRANCHE_DISBURSEMENT, ChargeCalculationType.FLAT, LocalDate.of(2022, 6, 27), ChargePaymentMode.REGULAR, 1,
|
||||
new BigDecimal(100), ExternalId.generate());
|
||||
final LoanCharge loanCharge = new LoanCharge();
|
||||
|
||||
loanCharge.setLoan(mock(Loan.class));
|
||||
loanCharge.setCharge(mock(Charge.class));
|
||||
loanCharge.setAmount(new BigDecimal(100));
|
||||
loanCharge.setAmountOutstanding(new BigDecimal(100));
|
||||
loanCharge.setChargeTime(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue());
|
||||
loanCharge.setChargeCalculation(ChargeCalculationType.FLAT.getValue());
|
||||
loanCharge.setDueDate(LocalDate.of(2022, 6, 27));
|
||||
loanCharge.setChargePaymentMode(ChargePaymentMode.REGULAR.getValue());
|
||||
loanCharge.setPercentage(null);
|
||||
loanCharge.setAmountPercentageAppliedTo(null);
|
||||
loanCharge.setAmountPaid(null);
|
||||
loanCharge.setAmountWaived(null);
|
||||
loanCharge.setAmountWrittenOff(null);
|
||||
loanCharge.setExternalId(ExternalId.generate());
|
||||
|
||||
return loanCharge;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.refEq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
@@ -34,6 +35,7 @@ import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
@@ -44,6 +46,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -99,7 +103,8 @@ public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
underTest = new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(null);
|
||||
underTest = new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(mock(ExternalIdFactory.class),
|
||||
mock(LoanChargeValidator.class), mock(LoanBalanceService.class));
|
||||
Mockito.reset(charges, transactionMappings);
|
||||
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
|
||||
+6
-1
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.refEq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
@@ -34,6 +35,7 @@ import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
@@ -44,6 +46,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -100,7 +104,8 @@ public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
underTest = new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(null);
|
||||
underTest = new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(mock(ExternalIdFactory.class),
|
||||
mock(LoanChargeValidator.class), mock(LoanBalanceService.class));
|
||||
Mockito.reset(charges, transactionMappings);
|
||||
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
|
||||
+8
-1
@@ -111,13 +111,20 @@ public class LoanDownPaymentHandlerServiceImplTest {
|
||||
@Mock
|
||||
private LoanLifecycleStateMachine loanLifecycleStateMachine;
|
||||
|
||||
@Mock
|
||||
private LoanBalanceService loanBalanceService;
|
||||
|
||||
@Mock
|
||||
private LoanTransactionService loanTransactionService;
|
||||
|
||||
private LoanDownPaymentHandlerServiceImpl underTest;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
underTest = new LoanDownPaymentHandlerServiceImpl(loanTransactionRepository, businessEventNotifierService,
|
||||
loanDownPaymentTransactionValidator, loanScheduleService, loanRefundService, loanRefundValidator,
|
||||
reprocessLoanTransactionsService, loanTransactionProcessingService, loanLifecycleStateMachine);
|
||||
reprocessLoanTransactionsService, loanTransactionProcessingService, loanLifecycleStateMachine, loanBalanceService,
|
||||
loanTransactionService);
|
||||
moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.UP));
|
||||
moneyHelper.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.UP);
|
||||
tempConfigServiceMock.when(TemporaryConfigurationServiceContainer::isExternalIdAutoGenerationEnabled).thenReturn(true);
|
||||
|
||||
Reference in New Issue
Block a user