This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new cb6a15c3d2 FINERACT-2234: Replace in-memory transaction loops with
repository queries
cb6a15c3d2 is described below
commit cb6a15c3d222a7c199450a4aa803ee3f546ac15a
Author: Oleksii Novikov <[email protected]>
AuthorDate: Wed Jun 25 10:08:57 2025 +0300
FINERACT-2234: Replace in-memory transaction loops with repository queries
---
.../DelinquencyReadPlatformServiceImpl.java | 11 +--
.../starter/DelinquencyConfiguration.java | 6 +-
.../portfolio/loanaccount/domain/Loan.java | 100 +++-----------------
.../loanaccount/domain/LoanTransaction.java | 4 -
.../domain/LoanTransactionRepository.java | 102 +++++++++++++++++++--
...anChargeRepaymentScheduleProcessingWrapper.java | 1 -
...tLoanRepaymentScheduleTransactionProcessor.java | 25 +++--
.../AbstractCumulativeLoanScheduleGenerator.java | 39 ++++----
...liningBalanceInterestLoanScheduleGenerator.java | 8 +-
...umulativeFlatInterestLoanScheduleGenerator.java | 8 +-
.../serialization/LoanChargeValidator.java | 20 ++--
.../loanaccount/service/LoanBalanceService.java | 63 ++++++++++++-
...dvancedPaymentScheduleTransactionProcessor.java | 22 ++---
.../CapitalizedIncomeWritePlatformServiceImpl.java | 2 +-
.../InternalProgressiveLoanApiResource.java | 7 +-
...cedPaymentScheduleTransactionProcessorTest.java | 4 +-
.../domain/LoanAccountDomainServiceJpa.java | 3 +-
.../service/LoanAccrualsProcessingServiceImpl.java | 4 +-
.../loanaccount/service/LoanAssemblerImpl.java | 8 +-
.../service/LoanDisbursementService.java | 3 +-
.../LoanTransactionProcessingServiceImpl.java | 2 +-
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 14 +--
.../ProgressiveLoanSummaryDataProvider.java | 7 +-
.../ReprocessLoanTransactionsServiceImpl.java | 21 +----
.../LoanContractTerminationServiceImpl.java | 2 +-
.../starter/LoanAccountAutoStarter.java | 6 +-
.../starter/LoanAccountConfiguration.java | 4 +-
...AccountDelinquencyRangeEventSerializerTest.java | 2 +-
.../portfolio/loanaccount/domain/LoanBuilder.java | 11 +--
29 files changed, 281 insertions(+), 228 deletions(-)
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
index 29e0b0843d..7406584aff 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
@@ -58,6 +58,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.springframework.lang.NonNull;
import org.springframework.transaction.annotation.Transactional;
@@ -77,6 +78,7 @@ public class DelinquencyReadPlatformServiceImpl implements
DelinquencyReadPlatfo
private final LoanDelinquencyActionRepository
loanDelinquencyActionRepository;
private final DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper;
private final ConfigurationDomainService configurationDomainService;
+ private final LoanTransactionRepository loanTransactionRepository;
@Override
public List<DelinquencyRangeData> retrieveAllDelinquencyRanges() {
@@ -174,7 +176,7 @@ public class DelinquencyReadPlatformServiceImpl implements
DelinquencyReadPlatfo
private void addInstallmentLevelDelinquencyData(CollectionData
collectionData, Long loanId) {
Collection<LoanInstallmentDelinquencyTagData>
loanInstallmentDelinquencyTagData =
retrieveLoanInstallmentsCurrentDelinquencyTag(
loanId);
- if (loanInstallmentDelinquencyTagData != null &&
loanInstallmentDelinquencyTagData.size() > 0) {
+ if (loanInstallmentDelinquencyTagData != null &&
!loanInstallmentDelinquencyTagData.isEmpty()) {
// installment level delinquency grouped by rangeId, and summed up
the delinquent amount
Collection<InstallmentLevelDelinquency>
installmentLevelDelinquencies = loanInstallmentDelinquencyTagData.stream()
@@ -254,12 +256,7 @@ public class DelinquencyReadPlatformServiceImpl implements
DelinquencyReadPlatfo
}
}
- LocalDate lastTransactionDate = null;
- for (final LoanTransaction transaction : loan.getLoanTransactions()) {
- if (transaction.isRepaymentLikeType() &&
transaction.isGreaterThanZero()) {
- lastTransactionDate = transaction.getTransactionDate();
- }
- }
+ final LocalDate lastTransactionDate =
loanTransactionRepository.findLastRepaymentLikeTransactionDate(loan).orElse(null);
LocalDate possibleNextRepaymentDate = earliestUnpaidInstallmentDate;
if (DateUtils.isAfter(lastTransactionDate,
earliestUnpaidInstallmentDate)) {
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java
index 71e6382196..530ce477f3 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java
@@ -42,6 +42,7 @@ import
org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketPars
import
org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import
org.apache.fineract.portfolio.loanaccount.service.LoanTransactionReadService;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -60,11 +61,12 @@ public class DelinquencyConfiguration {
LoanDelinquencyDomainService loanDelinquencyDomainService,
LoanInstallmentDelinquencyTagRepository
repositoryLoanInstallmentDelinquencyTag,
LoanDelinquencyActionRepository loanDelinquencyActionRepository,
- DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper,
ConfigurationDomainService configurationDomainService) {
+ DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper,
ConfigurationDomainService configurationDomainService,
+ LoanTransactionRepository loanTransactionRepository) {
return new DelinquencyReadPlatformServiceImpl(repositoryRange,
repositoryBucket, repositoryLoanDelinquencyTagHistory, mapperRange,
mapperBucket, mapperLoanDelinquencyTagHistory, loanRepository,
loanDelinquencyDomainService,
repositoryLoanInstallmentDelinquencyTag,
loanDelinquencyActionRepository, delinquencyEffectivePauseHelper,
- configurationDomainService);
+ configurationDomainService, loanTransactionRepository);
}
@Bean
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 3c8d29df2c..8951bdd50a 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -59,7 +59,6 @@ import
org.apache.fineract.infrastructure.codes.domain.CodeValue;
import
org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.service.DateUtils;
-import org.apache.fineract.infrastructure.core.service.MathUtil;
import
org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -74,7 +73,6 @@ import org.apache.fineract.portfolio.fund.domain.Fund;
import org.apache.fineract.portfolio.group.domain.Group;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
-import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import
org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import
org.apache.fineract.portfolio.loanproduct.domain.LoanSupportedInterestRefundTypes;
@@ -433,13 +431,13 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
final List<LoanDisbursementDetails> disbursementDetails, final
BigDecimal maxOutstandingLoanBalance,
final Boolean createStandingInstructionAtDisbursement, final
Boolean isFloatingInterestRate,
final BigDecimal interestRateDifferential, final List<Rate> rates,
final BigDecimal fixedPrincipalPercentagePerInstallment,
- final ExternalId externalId, final LoanApplicationTerms
loanApplicationTerms, final LoanScheduleModel loanScheduleModel,
- final Boolean enableInstallmentLevelDelinquency, final LocalDate
submittedOnDate) {
+ final ExternalId externalId, final LoanApplicationTerms
loanApplicationTerms, final Boolean enableInstallmentLevelDelinquency,
+ final LocalDate submittedOnDate) {
return new Loan(accountNo, client, null, loanType, fund, officer,
loanPurpose, transactionProcessingStrategy, loanProduct,
loanRepaymentScheduleDetail, null, loanCharges, collateral,
null, fixedEmiAmount, disbursementDetails,
maxOutstandingLoanBalance,
createStandingInstructionAtDisbursement, isFloatingInterestRate,
interestRateDifferential, rates,
- fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, loanScheduleModel,
- enableInstallmentLevelDelinquency, submittedOnDate);
+ fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, enableInstallmentLevelDelinquency,
+ submittedOnDate);
}
public static Loan newGroupLoanApplication(final String accountNo, final
Group group, final AccountType loanType,
@@ -450,13 +448,13 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
final List<LoanDisbursementDetails> disbursementDetails, final
BigDecimal maxOutstandingLoanBalance,
final Boolean createStandingInstructionAtDisbursement, final
Boolean isFloatingInterestRate,
final BigDecimal interestRateDifferential, final List<Rate> rates,
final BigDecimal fixedPrincipalPercentagePerInstallment,
- final ExternalId externalId, final LoanApplicationTerms
loanApplicationTerms, final LoanScheduleModel loanScheduleModel,
- final Boolean enableInstallmentLevelDelinquency, final LocalDate
submittedOnDate) {
+ final ExternalId externalId, final LoanApplicationTerms
loanApplicationTerms, final Boolean enableInstallmentLevelDelinquency,
+ final LocalDate submittedOnDate) {
return new Loan(accountNo, null, group, loanType, fund, officer,
loanPurpose, transactionProcessingStrategy, loanProduct,
loanRepaymentScheduleDetail, null, loanCharges, null,
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails,
maxOutstandingLoanBalance,
createStandingInstructionAtDisbursement, isFloatingInterestRate,
interestRateDifferential, rates,
- fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, loanScheduleModel,
- enableInstallmentLevelDelinquency, submittedOnDate);
+ fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, enableInstallmentLevelDelinquency,
+ submittedOnDate);
}
public static Loan newIndividualLoanApplicationFromGroup(final String
accountNo, final Client client, final Group group,
@@ -467,13 +465,13 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
final List<LoanDisbursementDetails> disbursementDetails, final
BigDecimal maxOutstandingLoanBalance,
final Boolean createStandingInstructionAtDisbursement, final
Boolean isFloatingInterestRate,
final BigDecimal interestRateDifferential, final List<Rate> rates,
final BigDecimal fixedPrincipalPercentagePerInstallment,
- final ExternalId externalId, final LoanApplicationTerms
loanApplicationTerms, final LoanScheduleModel loanScheduleModel,
- final Boolean enableInstallmentLevelDelinquency, final LocalDate
submittedOnDate) {
+ final ExternalId externalId, final LoanApplicationTerms
loanApplicationTerms, final Boolean enableInstallmentLevelDelinquency,
+ final LocalDate submittedOnDate) {
return new Loan(accountNo, client, group, loanType, fund, officer,
loanPurpose, transactionProcessingStrategy, loanProduct,
loanRepaymentScheduleDetail, null, loanCharges, null,
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails,
maxOutstandingLoanBalance,
createStandingInstructionAtDisbursement, isFloatingInterestRate,
interestRateDifferential, rates,
- fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, loanScheduleModel,
- enableInstallmentLevelDelinquency, submittedOnDate);
+ fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, enableInstallmentLevelDelinquency,
+ submittedOnDate);
}
protected Loan() {
@@ -488,8 +486,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
final List<LoanDisbursementDetails> disbursementDetails, final
BigDecimal maxOutstandingLoanBalance,
final Boolean createStandingInstructionAtDisbursement, final
Boolean isFloatingInterestRate,
final BigDecimal interestRateDifferential, final List<Rate> rates,
final BigDecimal fixedPrincipalPercentagePerInstallment,
- final ExternalId externalId, final LoanApplicationTerms
loanApplicationTerms, final LoanScheduleModel loanScheduleModel,
- final Boolean enableInstallmentLevelDelinquency, final LocalDate
submittedOnDate) {
+ final ExternalId externalId, final LoanApplicationTerms
loanApplicationTerms, final Boolean enableInstallmentLevelDelinquency,
+ final LocalDate submittedOnDate) {
this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
this.isFloatingInterestRate = isFloatingInterestRate;
@@ -850,17 +848,6 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
this.postDatedChecks = new ArrayList<>();
}
- public List<LoanTransaction> retrieveListOfTransactionsExcludeAccruals() {
- final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
- for (final LoanTransaction transaction : this.loanTransactions) {
- if (transaction.isNotReversed() &&
!transaction.isNonMonetaryTransaction()) {
- repaymentsOrWaivers.add(transaction);
- }
- }
- repaymentsOrWaivers.sort(LoanTransactionComparator.INSTANCE);
- return repaymentsOrWaivers;
- }
-
public List<LoanTransaction> retrieveListOfTransactionsByType(final
LoanTransactionType transactionType) {
return this.loanTransactions.stream()
.filter(transaction -> transaction.isNotReversed() &&
transaction.getTypeOf().equals(transactionType))
@@ -880,11 +867,6 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
.orElse(null);
}
- public Money calculateTotalRecoveredPayments() {
- // in case logic for reversing recovered payment is implemented handle
subtraction from totalRecoveredPayments
- return getTotalRecoveredPayments();
- }
-
public MonetaryCurrency loanCurrency() {
return this.loanRepaymentScheduleDetail.getCurrency();
}
@@ -1033,17 +1015,6 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
return cumulativePaid;
}
- public Money getTotalRecoveredPayments() {
- Money cumulativePaid = Money.zero(getCurrency());
-
- for (final LoanTransaction recoveredPayment : this.loanTransactions) {
- if (recoveredPayment.isRecoveryRepayment()) {
- cumulativePaid =
cumulativePaid.plus(recoveredPayment.getAmount(getCurrency()));
- }
- }
- return cumulativePaid;
- }
-
public Money getTotalPrincipalOutstandingUntil(LocalDate date) {
return getRepaymentScheduleInstallments().stream()
.filter(installment -> installment.getDueDate().isBefore(date)
|| installment.getDueDate().isEqual(date))
@@ -1236,7 +1207,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
.filter(date -> DateUtils.isBefore(getDisbursementDate(),
date)).max(LocalDate::compareTo).orElse(getDisbursementDate());
}
- private boolean isUserTransaction(LoanTransaction transaction) {
+ public boolean isUserTransaction(LoanTransaction transaction) {
return !(transaction.isReversed() || transaction.isAccrualRelated() ||
transaction.isIncomePosting());
}
@@ -1391,47 +1362,6 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
return recalculatedOn;
}
- public void updateLoanOutstandingBalances() {
- Money outstanding = Money.zero(getCurrency());
- List<LoanTransaction> loanTransactions =
retrieveListOfTransactionsExcludeAccruals();
- for (LoanTransaction loanTransaction : loanTransactions) {
- if (loanTransaction.isDisbursement() ||
loanTransaction.isIncomePosting() || loanTransaction.isCapitalizedIncome()) {
- outstanding =
outstanding.plus(loanTransaction.getAmount(getCurrency()))
-
.minus(loanTransaction.getOverPaymentPortion(getCurrency()));
-
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
- } else if (loanTransaction.isChargeback() ||
loanTransaction.isCreditBalanceRefund()) {
- Money transactionOutstanding =
loanTransaction.getPrincipalPortion(getCurrency());
- if (loanTransaction.isOverPaid()) {
- // in case of advanced payment strategy and
creditAllocations the full amount is recognized first
- if (this.getCreditAllocationRules() != null &&
!this.getCreditAllocationRules().isEmpty()) {
- Money payedPrincipal =
loanTransaction.getLoanTransactionToRepaymentScheduleMappings().stream() //
- .map(mapping ->
mapping.getPrincipalPortion(getCurrency())) //
- .reduce(Money.zero(getCurrency()),
Money::plus);
- transactionOutstanding =
loanTransaction.getPrincipalPortion(getCurrency()).minus(payedPrincipal);
- } else {
- // in case legacy payment strategy
- transactionOutstanding =
loanTransaction.getAmount(getCurrency())
-
.minus(loanTransaction.getOverPaymentPortion(getCurrency()));
- }
- if (transactionOutstanding.isLessThanZero()) {
- transactionOutstanding = Money.zero(getCurrency());
- }
- }
- outstanding = outstanding.plus(transactionOutstanding);
-
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
- } else if (!loanTransaction.isAccrualActivity()) {
- if (this.loanInterestRecalculationDetails != null
- &&
this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()
- && !loanTransaction.isRepaymentAtDisbursement()) {
- outstanding =
outstanding.minus(loanTransaction.getAmount(getCurrency()));
- } else {
- outstanding =
outstanding.minus(loanTransaction.getPrincipalPortion(getCurrency()));
- }
-
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
- }
- }
- }
-
public String transactionProcessingStrategy() {
return this.transactionProcessingStrategyCode;
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 397343026e..9023a83471 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -911,10 +911,6 @@ public class LoanTransaction extends
AbstractAuditableWithUTCDateTimeCustom<Long
|| this.isIncomePosting());
}
- public boolean hasLoanTransactionRelations() {
- return !loanTransactionRelations.isEmpty();
- }
-
public List<LoanTransactionRelation>
getLoanTransactionRelations(Predicate<LoanTransactionRelation> predicate) {
return loanTransactionRelations.stream().filter(predicate).toList();
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionRepository.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionRepository.java
index 04b791eb49..3934f0253f 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionRepository.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionRepository.java
@@ -127,7 +127,8 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.INITIATE_TRANSFER,
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REJECT_TRANSFER,
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.WITHDRAW_TRANSFER,
-
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION_ADJUSTMENT
)
""")
Optional<LocalDate> findLastTransactionDateForReprocessing(@Param("loan")
Loan loan);
@@ -174,7 +175,7 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
AND lt.typeOf IN :types
AND lt.dateOf = :transactionDate
""")
- Optional<LoanTransaction>
findNonReversedByLoanAndTypesAndDate(@Param("loan") Loan loan, @Param("type")
Set<LoanTransactionType> types,
+ Optional<LoanTransaction>
findNonReversedByLoanAndTypesAndDate(@Param("loan") Loan loan, @Param("types")
Set<LoanTransactionType> types,
@Param("transactionDate") LocalDate transactionDate);
@Query("""
@@ -184,7 +185,7 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
AND lt.reversed = false
AND lt.typeOf IN :types
AND lt.dateOf > :transactionDate
- ORDER BY lt.dateOf
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
""")
List<LoanTransaction>
findNonReversedByLoanAndTypesAndAfterDate(@Param("loan") Loan loan,
@Param("types") Set<LoanTransactionType> types,
@Param("transactionDate") LocalDate transactionDate);
@@ -196,7 +197,7 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
AND lt.reversed = false
AND lt.typeOf = :type
AND lt.dateOf > :transactionDate
- ORDER BY lt.dateOf
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
""")
List<LoanTransaction>
findNonReversedByLoanAndTypeAndAfterDate(@Param("loan") Loan loan,
@Param("type") LoanTransactionType type,
@Param("transactionDate") LocalDate transactionDate);
@@ -219,6 +220,7 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
AND lt.reversed = false
AND lt.typeOf IN :types
AND lt.id NOT IN :existingTransactionIds
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
""")
List<LoanTransaction>
findNonReversedByLoanAndTypesAndNotInIds(@Param("loan") Loan loan,
@Param("types") Set<LoanTransactionType> types,
@Param("existingTransactionIds") List<Long>
existingTransactionIds);
@@ -229,6 +231,7 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
WHERE lt.loan = :loan
AND lt.reversed = false
AND lt.typeOf IN :types
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
""")
List<LoanTransaction> findNonReversedByLoanAndTypes(@Param("loan") Loan
loan, @Param("types") Set<LoanTransactionType> types);
@@ -238,6 +241,7 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
WHERE lt.loan = :loan
AND lt.reversed = false
AND lt.typeOf = :type
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
""")
List<LoanTransaction> findNonReversedByLoanAndType(@Param("loan") Loan
loan, @Param("type") LoanTransactionType type);
@@ -248,7 +252,7 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
AND lt.reversed = false
AND lt.dateOf >= :date
AND lt.typeOf IN :types
- ORDER BY lt.dateOf
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
""")
List<LoanTransaction>
findNonReversedByLoanAndTypesAndOnOrAfterDate(@Param("loan") Loan loan,
@Param("types") Set<LoanTransactionType> types, @Param("date")
LocalDate date);
@@ -333,7 +337,7 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
AND lt.reversed = false
AND lt.typeOf = :type
AND lt.dateOf IN :transactionDates
- ORDER BY lt.id
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
""")
List<LoanTransaction> findNonReversedLoanAndTypeAndDates(@Param("loan")
Loan loan, @Param("type") LoanTransactionType type,
@Param("transactionDates") Set<LocalDate> transactionDates);
@@ -367,4 +371,90 @@ public interface LoanTransactionRepository extends
JpaRepository<LoanTransaction
AND ltr.relationType =
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum.ADJUSTMENT
""")
List<LoanTransaction>
findAdjustmentsForCapitalizedIncome(@Param("capitalizedIncome") LoanTransaction
capitalizedIncome);
+
+ @Query("""
+ SELECT lt FROM LoanTransaction lt
+ WHERE lt.loan = :loan
+ AND lt.reversed = false
+ AND lt.typeOf NOT IN (
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CONTRA,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.MARKED_FOR_RESCHEDULING,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.ACCRUAL,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.ACCRUAL_ADJUSTMENT,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.APPROVE_TRANSFER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.INITIATE_TRANSFER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REJECT_TRANSFER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.WITHDRAW_TRANSFER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION_ADJUSTMENT
+ )
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
+ """)
+ List<LoanTransaction>
findNonReversedTransactionsForReprocessingByLoan(@Param("loan") Loan loan);
+
+ @Query("""
+ SELECT MAX(lt.dateOf) FROM LoanTransaction lt
+ WHERE lt.loan = :loan
+ AND lt.reversed = false
+ AND lt.amount > 0
+ AND lt.typeOf IN (
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REPAYMENT,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.MERCHANT_ISSUED_REFUND,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.PAYOUT_REFUND,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.GOODWILL_CREDIT,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CHARGE_REFUND,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CHARGE_ADJUSTMENT,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.DOWN_PAYMENT,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.INTEREST_PAYMENT_WAIVER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.INTEREST_REFUND,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT
+ )
+ """)
+ Optional<LocalDate> findLastRepaymentLikeTransactionDate(@Param("loan")
Loan loan);
+
+ @Query("""
+ SELECT CASE WHEN COUNT(lt) > 0 THEN true ELSE false END
+ FROM LoanTransaction lt
+ WHERE lt.loan = :loan
+ AND lt.reversed = false
+ AND lt.typeOf = :type
+ AND lt.dateOf > :transactionDate
+ """)
+ boolean existsNonReversedByLoanAndTypeAndAfterDate(@Param("loan") Loan
loan, @Param("type") LoanTransactionType type,
+ @Param("transactionDate") LocalDate transactionDate);
+
+ @Query("""
+ SELECT lt FROM LoanTransaction lt
+ WHERE lt.loan = :loan
+ AND lt.reversed = false
+ AND lt.typeOf NOT IN (
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CONTRA,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.MARKED_FOR_RESCHEDULING,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.ACCRUAL,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.ACCRUAL_ADJUSTMENT,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.ACCRUAL_ACTIVITY,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.APPROVE_TRANSFER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.INITIATE_TRANSFER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REJECT_TRANSFER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.WITHDRAW_TRANSFER,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CHARGE_OFF,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REAMORTIZE,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REAGE,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CONTRACT_TERMINATION,
+
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION_ADJUSTMENT
+ )
+ ORDER BY lt.dateOf, lt.createdDate, lt.id
+ """)
+ List<LoanTransaction>
findNonReversedMonetaryTransactionsByLoan(@Param("loan") Loan loan);
+
+ @Query("""
+ SELECT COALESCE(SUM(lt.amount), 0)
+ FROM LoanTransaction lt
+ WHERE lt.loan = :loan
+ AND lt.reversed = false
+ AND lt.typeOf =
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.RECOVERY_REPAYMENT
+ """)
+ BigDecimal calculateTotalRecoveryPaymentAmount(@Param("loan") Loan loan);
+
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapper.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapper.java
index d12449b894..f73ed71b6d 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapper.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapper.java
@@ -37,7 +37,6 @@ public class
SingleLoanChargeRepaymentScheduleProcessingWrapper {
public void reprocess(final MonetaryCurrency currency, final LocalDate
disbursementDate,
final List<LoanRepaymentScheduleInstallment> installments,
LoanCharge loanCharge) {
- Loan loan = loanCharge.getLoan();
Money zero = Money.zero(currency);
Money totalInterest = zero;
Money totalPrincipal = zero;
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
index a6aaa89ca6..b733c459da 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
@@ -217,11 +217,9 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
loanTransaction.resetDerivedComponents();
handleRefund(loanTransaction, currency, installments, charges);
} else if (loanTransaction.isCreditBalanceRefund()) {
- recalculateCreditTransaction(changedTransactionDetail,
loanTransaction, currency, installments, transactionsToBeProcessed,
- overpaymentHolder);
+ recalculateCreditTransaction(changedTransactionDetail,
loanTransaction, currency, installments, overpaymentHolder);
} else if (loanTransaction.isChargeback()) {
- recalculateCreditTransaction(changedTransactionDetail,
loanTransaction, currency, installments, transactionsToBeProcessed,
- overpaymentHolder);
+ recalculateCreditTransaction(changedTransactionDetail,
loanTransaction, currency, installments, overpaymentHolder);
reprocessChargebackTransactionRelation(changedTransactionDetail,
transactionsToBeProcessed);
} else if (loanTransaction.isChargeOff()) {
recalculateChargeOffTransaction(changedTransactionDetail,
loanTransaction, currency, installments);
@@ -475,7 +473,7 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
protected void reprocessInstallments(LocalDate disbursementDate,
List<LoanTransaction> transactions,
List<LoanRepaymentScheduleInstallment> installments,
MonetaryCurrency currency) {
- LoanRepaymentScheduleInstallment lastInstallment =
installments.get(installments.size() - 1);
+ LoanRepaymentScheduleInstallment lastInstallment =
installments.getLast();
if (lastInstallment.isAdditional() &&
lastInstallment.getDue(currency).isZero()) {
installments.remove(lastInstallment);
}
@@ -519,8 +517,7 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
}
private void recalculateCreditTransaction(ChangedTransactionDetail
changedTransactionDetail, LoanTransaction loanTransaction,
- MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment>
installments, List<LoanTransaction> transactionsToBeProcessed,
- MoneyHolder overpaymentHolder) {
+ MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment>
installments, MoneyHolder overpaymentHolder) {
// pass through for new transactions
if (loanTransaction.getId() == null) {
return;
@@ -606,7 +603,7 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
// New installment will be added (N+1 scenario)
if (!loanTransactionMapped) {
if (loanTransaction.getTransactionDate().equals(pastDueDate)) {
- LoanRepaymentScheduleInstallment currentInstallment =
installmentToBeProcessed.get(installmentToBeProcessed.size() - 1);
+ LoanRepaymentScheduleInstallment currentInstallment =
installmentToBeProcessed.getLast();
currentInstallment.addToCreditedPrincipal(transactionAmount.getAmount());
currentInstallment.addToPrincipal(transactionDate,
transactionAmount);
if (repaidAmount.isGreaterThanZero()) {
@@ -647,7 +644,7 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
final Set<LoanCharge> loanPenalties = extractPenaltyCharges(charges);
Integer installmentNumber = null;
if (loanTransaction.isChargePayment() && installments.size() == 1) {
- installmentNumber = installments.get(0).getInstallmentNumber();
+ installmentNumber = installments.getFirst().getInstallmentNumber();
}
if (loanTransaction.isNotWaiver() && !loanTransaction.isAccrual() &&
!loanTransaction.isAccrualActivity()) {
@@ -944,12 +941,12 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
return null;
}
LoanCharge latestCharge = null;
- List<LoanCharge> chargesWithSpecificDueDate = new ArrayList<>();
- chargesWithSpecificDueDate.addAll(charges.stream().filter(charge ->
charge.isSpecifiedDueDate()).toList());
+ final List<LoanCharge> chargesWithSpecificDueDate = new ArrayList<>(
+
charges.stream().filter(LoanCharge::isSpecifiedDueDate).toList());
if (!CollectionUtils.isEmpty(chargesWithSpecificDueDate)) {
- Collections.sort(chargesWithSpecificDueDate,
- (charge1, charge2) ->
DateUtils.compare(charge1.getEffectiveDueDate(),
charge2.getEffectiveDueDate()));
- latestCharge =
chargesWithSpecificDueDate.get(chargesWithSpecificDueDate.size() - 1);
+ chargesWithSpecificDueDate
+ .sort((charge1, charge2) ->
DateUtils.compare(charge1.getEffectiveDueDate(),
charge2.getEffectiveDueDate()));
+ latestCharge = chargesWithSpecificDueDate.getLast();
}
return latestCharge;
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
index af07a66b44..9dc0ea7948 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
@@ -56,6 +56,7 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
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;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleModelDownPaymentPeriod;
@@ -63,13 +64,12 @@ import
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleP
import
org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementEmiAmountException;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementOutstandingAmoutException;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.exception.ScheduleDateException;
-import
org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
@RequiredArgsConstructor
public abstract class AbstractCumulativeLoanScheduleGenerator implements
LoanScheduleGenerator {
- private final LoanTransactionService loanTransactionService;
+ private final LoanTransactionRepository loanTransactionRepository;
private final CurrencyMapper currencyMapper;
@Override
@@ -404,7 +404,7 @@ public abstract class
AbstractCumulativeLoanScheduleGenerator implements LoanSch
// this condition is to add the interest from grace period if not
// already applied.
if
(scheduleParams.getTotalOutstandingInterestPaymentDueToGrace().isGreaterThanZero())
{
- LoanScheduleModelPeriod installment = periods.get(periods.size() -
1);
+ LoanScheduleModelPeriod installment = periods.getLast();
installment.addInterestAmount(scheduleParams.getTotalOutstandingInterestPaymentDueToGrace());
scheduleParams.addTotalRepaymentExpected(scheduleParams.getTotalOutstandingInterestPaymentDueToGrace());
scheduleParams.addTotalCumulativeInterest(scheduleParams.getTotalOutstandingInterestPaymentDueToGrace());
@@ -421,7 +421,7 @@ public abstract class
AbstractCumulativeLoanScheduleGenerator implements LoanSch
if (scheduleParams.getScheduleTillDate() != null) {
currentDate = scheduleParams.getScheduleTillDate();
}
- if (scheduleParams.applyInterestRecalculation() &&
scheduleParams.getLatePaymentMap().size() > 0
+ if (scheduleParams.applyInterestRecalculation() &&
!scheduleParams.getLatePaymentMap().isEmpty()
&& DateUtils.isAfter(currentDate,
scheduleParams.getPeriodStartDate())) {
Money totalInterest =
addInterestOnlyRepaymentScheduleForCurrentDate(mc, loanApplicationTerms,
holidayDetailDTO,
monetaryCurrency, periods, currentDate,
loanRepaymentScheduleTransactionProcessor, transactions, loanCharges,
@@ -1345,9 +1345,8 @@ public abstract class
AbstractCumulativeLoanScheduleGenerator implements LoanSch
return
principalToBeScheduled.minus(loanApplicationTerms.getDownPaymentAmount());
}
- private boolean updateFixedInstallmentAmount(final MathContext mc, final
LoanApplicationTerms loanApplicationTerms, int periodNumber,
+ private void updateFixedInstallmentAmount(final MathContext mc, final
LoanApplicationTerms loanApplicationTerms, int periodNumber,
Money outstandingBalance) {
- boolean isAmountChanged = false;
if (loanApplicationTerms.getActualFixedEmiAmount() == null &&
loanApplicationTerms.getInterestMethod().isDecliningBalance()
&&
loanApplicationTerms.getAmortizationMethod().isEqualInstallment()) {
if (periodNumber < loanApplicationTerms.getPrincipalGrace() + 1) {
@@ -1356,9 +1355,7 @@ public abstract class
AbstractCumulativeLoanScheduleGenerator implements LoanSch
Money emiAmount =
loanApplicationTerms.pmtForInstallment(getPaymentPeriodsInOneYearCalculator(),
outstandingBalance,
periodNumber, mc);
loanApplicationTerms.setFixedEmiAmount(emiAmount.getAmount());
- isAmountChanged = true;
}
- return isAmountChanged;
}
private Money fetchArrears(final LoanApplicationTerms
loanApplicationTerms, final MonetaryCurrency currency,
@@ -1984,7 +1981,7 @@ public abstract class
AbstractCumulativeLoanScheduleGenerator implements LoanSch
// this method relates to multi-disbursement loans
BigDecimal principal = BigDecimal.ZERO;
- if (loanApplicationTerms.getDisbursementDatas().size() == 0) {
+ if (loanApplicationTerms.getDisbursementDatas().isEmpty()) {
// non tranche loans have no disbursement data entries in
submitted and approved status
// the appropriate approved amount or applied for amount is used
to show a proposed schedule
if
(loanApplicationTerms.getApprovedPrincipal().getAmount().compareTo(BigDecimal.ZERO)
> 0) {
@@ -2521,10 +2518,9 @@ public abstract class
AbstractCumulativeLoanScheduleGenerator implements LoanSch
}
- if (retainedInstallments.size() > 0
- && retainedInstallments.get(retainedInstallments.size() -
1).getRescheduleInterestPortion() != null) {
+ if (!retainedInstallments.isEmpty() &&
retainedInstallments.getLast().getRescheduleInterestPortion() != null) {
loanApplicationTerms.setInterestTobeApproppriated(
- Money.of(loan.getCurrency(),
retainedInstallments.get(retainedInstallments.size() -
1).getRescheduleInterestPortion()));
+ Money.of(loan.getCurrency(),
retainedInstallments.getLast().getRescheduleInterestPortion()));
}
LoanScheduleModel loanScheduleModel = generate(mc,
loanApplicationTerms, loan.getActiveCharges(), holidayDetailDTO,
loanScheduleParams);
@@ -2723,19 +2719,18 @@ public abstract class
AbstractCumulativeLoanScheduleGenerator implements LoanSch
return principalPortionCalculated;
}
- private LoanRepaymentScheduleInstallment
addLoanRepaymentScheduleInstallment(final
List<LoanRepaymentScheduleInstallment> installments,
+ private void addLoanRepaymentScheduleInstallment(final
List<LoanRepaymentScheduleInstallment> installments,
final LoanScheduleModelPeriod scheduledLoanInstallment) {
- LoanRepaymentScheduleInstallment installment = null;
if (scheduledLoanInstallment.isRepaymentPeriod() ||
scheduledLoanInstallment.isDownPaymentPeriod()) {
- installment = new LoanRepaymentScheduleInstallment(null,
scheduledLoanInstallment.periodNumber(),
- scheduledLoanInstallment.periodFromDate(),
scheduledLoanInstallment.periodDueDate(),
- scheduledLoanInstallment.principalDue(),
scheduledLoanInstallment.interestDue(),
- scheduledLoanInstallment.feeChargesDue(),
scheduledLoanInstallment.penaltyChargesDue(),
-
scheduledLoanInstallment.isRecalculatedInterestComponent(),
scheduledLoanInstallment.getLoanCompoundingDetails(),
- scheduledLoanInstallment.rescheduleInterestPortion(),
scheduledLoanInstallment.isDownPaymentPeriod());
+ final LoanRepaymentScheduleInstallment installment = new
LoanRepaymentScheduleInstallment(null,
+ scheduledLoanInstallment.periodNumber(),
scheduledLoanInstallment.periodFromDate(),
+ scheduledLoanInstallment.periodDueDate(),
scheduledLoanInstallment.principalDue(),
+ scheduledLoanInstallment.interestDue(),
scheduledLoanInstallment.feeChargesDue(),
+ scheduledLoanInstallment.penaltyChargesDue(),
scheduledLoanInstallment.isRecalculatedInterestComponent(),
+ scheduledLoanInstallment.getLoanCompoundingDetails(),
scheduledLoanInstallment.rescheduleInterestPortion(),
+ scheduledLoanInstallment.isDownPaymentPeriod());
installments.add(installment);
}
- return installment;
}
private LoanScheduleModelPeriod
createLoanScheduleModelDownPaymentPeriod(final LoanRepaymentScheduleInstallment
installment,
@@ -2804,7 +2799,7 @@ public abstract class
AbstractCumulativeLoanScheduleGenerator implements LoanSch
LoanScheduleDTO loanScheduleDTO = rescheduleNextInstallments(mc,
loanApplicationTerms, loan, holidayDetailDTO,
loanRepaymentScheduleTransactionProcessor, onDate,
calculateTill);
- final List<LoanTransaction> loanTransactions =
loanTransactionService.retrieveListOfTransactionsForReprocessing(loan);
+ final List<LoanTransaction> loanTransactions =
loanTransactionRepository.findNonReversedTransactionsForReprocessingByLoan(loan);
loanRepaymentScheduleTransactionProcessor.reprocessLoanTransactions(loanApplicationTerms.getExpectedDisbursementDate(),
loanTransactions, currency, loanScheduleDTO.getInstallments(),
loan.getActiveCharges());
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/CumulativeDecliningBalanceInterestLoanScheduleGenerator.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/CumulativeDecliningBalanceInterestLoanScheduleGenerator.java
index 6087a6bd8e..c68596013e 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/CumulativeDecliningBalanceInterestLoanScheduleGenerator.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/CumulativeDecliningBalanceInterestLoanScheduleGenerator.java
@@ -29,7 +29,7 @@ import
org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.mapper.CurrencyMapper;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
-import
org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
import org.springframework.stereotype.Component;
@@ -63,9 +63,9 @@ public class
CumulativeDecliningBalanceInterestLoanScheduleGenerator extends Abs
private final PaymentPeriodsInOneYearCalculator
paymentPeriodsInOneYearCalculator;
public CumulativeDecliningBalanceInterestLoanScheduleGenerator(final
ScheduledDateGenerator scheduledDateGenerator,
- final PaymentPeriodsInOneYearCalculator
paymentPeriodsInOneYearCalculator, final LoanTransactionService
loanTransactionService,
- final CurrencyMapper currencyMapper) {
- super(loanTransactionService, currencyMapper);
+ final PaymentPeriodsInOneYearCalculator
paymentPeriodsInOneYearCalculator,
+ final LoanTransactionRepository loanTransactionRepository, final
CurrencyMapper currencyMapper) {
+ super(loanTransactionRepository, currencyMapper);
this.scheduledDateGenerator = scheduledDateGenerator;
this.paymentPeriodsInOneYearCalculator =
paymentPeriodsInOneYearCalculator;
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/CumulativeFlatInterestLoanScheduleGenerator.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/CumulativeFlatInterestLoanScheduleGenerator.java
index 4d1be6331b..1c3cb39999 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/CumulativeFlatInterestLoanScheduleGenerator.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/CumulativeFlatInterestLoanScheduleGenerator.java
@@ -27,7 +27,7 @@ import java.util.TreeMap;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.mapper.CurrencyMapper;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
-import
org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.springframework.stereotype.Component;
@Component
@@ -37,9 +37,9 @@ public class CumulativeFlatInterestLoanScheduleGenerator
extends AbstractCumulat
private final PaymentPeriodsInOneYearCalculator
paymentPeriodsInOneYearCalculator;
public CumulativeFlatInterestLoanScheduleGenerator(final
ScheduledDateGenerator scheduledDateGenerator,
- final PaymentPeriodsInOneYearCalculator
paymentPeriodsInOneYearCalculator, final LoanTransactionService
loanTransactionService,
- final CurrencyMapper currencyMapper) {
- super(loanTransactionService, currencyMapper);
+ final PaymentPeriodsInOneYearCalculator
paymentPeriodsInOneYearCalculator,
+ final LoanTransactionRepository loanTransactionRepository, final
CurrencyMapper currencyMapper) {
+ super(loanTransactionRepository, currencyMapper);
this.scheduledDateGenerator = scheduledDateGenerator;
this.paymentPeriodsInOneYearCalculator =
paymentPeriodsInOneYearCalculator;
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanChargeValidator.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanChargeValidator.java
index 34e2eb0603..e84dc7841d 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanChargeValidator.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanChargeValidator.java
@@ -19,18 +19,24 @@
package org.apache.fineract.portfolio.loanaccount.serialization;
import java.time.LocalDate;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import
org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import
org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanStateTransitionException;
import
org.apache.fineract.portfolio.loanaccount.exception.LoanChargeRefundException;
import org.springframework.stereotype.Component;
@Component
+@RequiredArgsConstructor
public final class LoanChargeValidator {
+ private final LoanTransactionRepository loanTransactionRepository;
+
public void validateLoanIsNotClosed(final Loan loan, final LoanCharge
loanCharge) {
if (loan.isClosed()) {
final String defaultUserMessage = "This charge cannot be added as
the loan is already closed.";
@@ -80,13 +86,13 @@ public final class LoanChargeValidator {
public void validateRepaymentTypeTransactionNotBeforeAChargeRefund(final
Loan loan, final LoanTransaction repaymentTransaction,
final String reversedOrCreated) {
if (repaymentTransaction.isRepaymentLikeType() &&
!repaymentTransaction.isChargeRefund()) {
- for (LoanTransaction txn : loan.getLoanTransactions()) {
- if (txn.isChargeRefund() &&
DateUtils.isBefore(repaymentTransaction.getTransactionDate(),
txn.getTransactionDate())) {
- final String errorMessage = "loan.transaction.cant.be." +
reversedOrCreated + ".because.later.charge.refund.exists";
- final String details = "Loan Transaction: " + loan.getId()
+ " Can't be " + reversedOrCreated
- + " because a Later Charge Refund Exists.";
- throw new LoanChargeRefundException(errorMessage, details);
- }
+ final boolean existsChargeRefund =
loanTransactionRepository.existsNonReversedByLoanAndTypeAndAfterDate(loan,
+ LoanTransactionType.CHARGE_REFUND,
repaymentTransaction.getTransactionDate());
+ if (existsChargeRefund) {
+ final String errorMessage = "loan.transaction.cant.be." +
reversedOrCreated + ".because.later.charge.refund.exists";
+ final String details = "Loan Transaction: " + loan.getId() + "
Can't be " + reversedOrCreated
+ + " because a Later Charge Refund Exists.";
+ throw new LoanChargeRefundException(errorMessage, details);
}
}
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBalanceService.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBalanceService.java
index cbacb2a24e..a93d21b696 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBalanceService.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBalanceService.java
@@ -21,10 +21,12 @@ package org.apache.fineract.portfolio.loanaccount.service;
import jakarta.persistence.FlushModeType;
import java.math.BigDecimal;
import java.time.LocalDate;
+import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.persistence.FlushModeHandler;
import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -34,6 +36,8 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
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.loanproduct.domain.CreditAllocationTransactionType;
import org.springframework.stereotype.Service;
@@ -43,6 +47,7 @@ public class LoanBalanceService {
private final CapitalizedIncomeBalanceService
capitalizedIncomeBalanceService;
private final FlushModeHandler flushModeHandler;
+ private final LoanTransactionRepository loanTransactionRepository;
public Money calculateTotalOverpayment(final Loan loan) {
Money totalPaidInRepayments = loan.getTotalPaidInRepayments();
@@ -107,7 +112,7 @@ public class LoanBalanceService {
loan.setTotalOverpaid(overpaidBy.getAmountDefaultedToNullIfZero());
}
- final Money recoveredAmount = loan.calculateTotalRecoveredPayments();
+ final Money recoveredAmount = calculateTotalRecoveredPayments(loan);
loan.setTotalRecovered(recoveredAmount.getAmountDefaultedToNullIfZero());
final Money principal =
loan.getLoanRepaymentScheduleDetail().getPrincipal();
@@ -115,7 +120,61 @@ public class LoanBalanceService {
final Money capitalizedIncomeAdjustment =
capitalizedIncomeBalanceService.calculateCapitalizedIncomeAdjustment(loan);
loan.getSummary().updateSummary(loan.getCurrency(), principal,
loan.getRepaymentScheduleInstallments(), loan.getLoanCharges(),
capitalizedIncome, capitalizedIncomeAdjustment);
- loan.updateLoanOutstandingBalances();
+ updateLoanOutstandingBalances(loan);
+ }
+
+ private Money calculateTotalRecoveredPayments(Loan loan) {
+ // in case logic for reversing recovered payment is implemented handle
subtraction from totalRecoveredPayments
+ final BigDecimal totalRecoveryAmount =
loanTransactionRepository.calculateTotalRecoveryPaymentAmount(loan);
+ return Money.of(loan.getCurrency(), totalRecoveryAmount);
+ }
+
+ public void updateLoanOutstandingBalances(Loan loan) {
+ Money outstanding = Money.zero(loan.getCurrency());
+ final List<LoanTransaction> loanTransactions = new ArrayList<>();
+ for (final LoanTransaction transaction : loan.getLoanTransactions()) {
+ if (transaction.isNotReversed() &&
!transaction.isNonMonetaryTransaction()) {
+ loanTransactions.add(transaction);
+ }
+ }
+ loanTransactions.sort(LoanTransactionComparator.INSTANCE);
+
+ for (LoanTransaction loanTransaction : loanTransactions) {
+ if (loanTransaction.isDisbursement() ||
loanTransaction.isIncomePosting() || loanTransaction.isCapitalizedIncome()) {
+ outstanding =
outstanding.plus(loanTransaction.getAmount(loan.getCurrency()))
+
.minus(loanTransaction.getOverPaymentPortion(loan.getCurrency()));
+
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
+ } else if (loanTransaction.isChargeback() ||
loanTransaction.isCreditBalanceRefund()) {
+ Money transactionOutstanding =
loanTransaction.getPrincipalPortion(loan.getCurrency());
+ if (loanTransaction.isOverPaid()) {
+ // in case of advanced payment strategy and
creditAllocations the full amount is recognized first
+ if (loan.getCreditAllocationRules() != null &&
!loan.getCreditAllocationRules().isEmpty()) {
+ Money payedPrincipal =
loanTransaction.getLoanTransactionToRepaymentScheduleMappings().stream() //
+ .map(mapping ->
mapping.getPrincipalPortion(loan.getCurrency())) //
+ .reduce(Money.zero(loan.getCurrency()),
Money::plus);
+ transactionOutstanding =
loanTransaction.getPrincipalPortion(loan.getCurrency()).minus(payedPrincipal);
+ } else {
+ // in case legacy payment strategy
+ transactionOutstanding =
loanTransaction.getAmount(loan.getCurrency())
+
.minus(loanTransaction.getOverPaymentPortion(loan.getCurrency()));
+ }
+ if (transactionOutstanding.isLessThanZero()) {
+ transactionOutstanding =
Money.zero(loan.getCurrency());
+ }
+ }
+ outstanding = outstanding.plus(transactionOutstanding);
+
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
+ } else if (!loanTransaction.isAccrualActivity()) {
+ if (loan.getLoanInterestRecalculationDetails() != null
+ &&
loan.getLoanInterestRecalculationDetails().isCompoundingToBePostedAsTransaction()
+ && !loanTransaction.isRepaymentAtDisbursement()) {
+ outstanding =
outstanding.minus(loanTransaction.getAmount(loan.getCurrency()));
+ } else {
+ outstanding =
outstanding.minus(loanTransaction.getPrincipalPortion(loan.getCurrency()));
+ }
+
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
+ }
+ }
}
public void updateLoanToLastDisbursalState(final Loan loan, final
LoanDisbursementDetails disbursementDetail) {
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index d8d4bda2fe..f9ed025ea2 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -84,6 +84,7 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionComparator;
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.LoanTransactionToRepaymentScheduleMapping;
import
org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
@@ -93,7 +94,6 @@ import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanSchedul
import
org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
import org.apache.fineract.portfolio.loanaccount.service.InterestRefundService;
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
-import
org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
import
org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
import org.apache.fineract.portfolio.loanproduct.calc.data.PeriodDueDetails;
@@ -121,17 +121,17 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
private final LoanRepositoryWrapper loanRepositoryWrapper;
private final InterestRefundService interestRefundService;
private final LoanScheduleComponent loanSchedule;
- private final LoanTransactionService loanTransactionService;
+ private final LoanTransactionRepository loanTransactionRepository;
public AdvancedPaymentScheduleTransactionProcessor(final EMICalculator
emiCalculator, final LoanRepositoryWrapper loanRepositoryWrapper,
final InterestRefundService interestRefundService, final
ExternalIdFactory externalIdFactory,
- final LoanScheduleComponent loanSchedule, final
LoanTransactionService loanTransactionRepository,
+ final LoanScheduleComponent loanSchedule, final
LoanTransactionRepository loanTransactionRepository,
final LoanChargeValidator loanChargeValidator, final
LoanBalanceService loanBalanceService) {
super(externalIdFactory, loanChargeValidator, loanBalanceService);
this.emiCalculator = emiCalculator;
this.loanRepositoryWrapper = loanRepositoryWrapper;
this.interestRefundService = interestRefundService;
- this.loanTransactionService = loanTransactionRepository;
+ this.loanTransactionRepository = loanTransactionRepository;
this.loanSchedule = loanSchedule;
}
@@ -212,7 +212,7 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
}
MoneyHolder overpaymentHolder = new MoneyHolder(Money.zero(currency));
- final Loan loan = loanTransactions.get(0).getLoan();
+ final Loan loan = loanTransactions.getFirst().getLoan();
List<LoanTermVariationsData> loanTermVariations =
loan.getActiveLoanTermVariations().stream().map(LoanTermVariations::toData)
.collect(Collectors.toCollection(ArrayList::new));
final Integer installmentAmountInMultiplesOf =
loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf();
@@ -276,7 +276,7 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
public ProgressiveLoanInterestScheduleModel
calculateInterestScheduleModel(@NotNull Long loanId, LocalDate targetDate) {
Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
- final List<LoanTransaction> transactions =
loanTransactionService.retrieveListOfTransactionsForReprocessing(loan);
+ final List<LoanTransaction> transactions =
loanTransactionRepository.findNonReversedTransactionsForReprocessingByLoan(loan);
MonetaryCurrency currency =
loan.getLoanRepaymentScheduleDetail().getCurrency();
List<LoanRepaymentScheduleInstallment> installments =
loan.getRepaymentScheduleInstallments();
Set<LoanCharge> charges = loan.getActiveCharges();
@@ -552,8 +552,7 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
if (!loanTransactionMapped) {
if (transactionDate.equals(pastDueDate)) {
// Transaction is on Maturity date, no additional
installment is needed
- LoanRepaymentScheduleInstallment currentInstallment =
installmentToBeProcessed
- .get(installmentToBeProcessed.size() - 1);
+ LoanRepaymentScheduleInstallment currentInstallment =
installmentToBeProcessed.getLast();
emiCalculator.creditPrincipal(model, transactionDate,
transactionAmount);
updateRepaymentPeriods(loanTransaction,
progressiveTransactionCtx);
@@ -827,7 +826,7 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
// New installment will be added (N+1 scenario)
if (!loanTransactionMapped) {
if (loanTransaction.getTransactionDate().equals(pastDueDate)) {
- LoanRepaymentScheduleInstallment currentInstallment =
ctx.getInstallments().get(ctx.getInstallments().size() - 1);
+ LoanRepaymentScheduleInstallment currentInstallment =
ctx.getInstallments().getLast();
recognizeAmountsAfterChargeback(ctx, transactionDate,
currentInstallment, chargebackAllocation);
} else {
Loan loan = loanTransaction.getLoan();
@@ -1450,7 +1449,7 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
public void recalculateInterestForDate(LocalDate targetDate,
ProgressiveTransactionCtx ctx) {
if (ctx.getInstallments() != null && !ctx.getInstallments().isEmpty())
{
- Loan loan = ctx.getInstallments().get(0).getLoan();
+ Loan loan = ctx.getInstallments().getFirst().getLoan();
if (loan.isInterestBearingAndInterestRecalculationEnabled() &&
!loan.isNpa() && !ctx.isChargedOff()
&& !ctx.isContractTerminated()) {
@@ -1761,8 +1760,7 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
.max(LocalDate::compareTo);
if (latestDueDate.isPresent()) {
- final LoanRepaymentScheduleInstallment lastInstallment =
installmentsUpToTransactionDate
- .get(installmentsUpToTransactionDate.size() - 1);
+ final LoanRepaymentScheduleInstallment lastInstallment =
installmentsUpToTransactionDate.getLast();
final LoanRepaymentScheduleInstallment
installmentForCharges = new LoanRepaymentScheduleInstallment(loan,
lastInstallment.getInstallmentNumber() + 1,
currentInstallment.getDueDate(), latestDueDate.get(),
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
index f9a7d6133f..840fd690ac 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
@@ -148,7 +148,7 @@ public class CapitalizedIncomeWritePlatformServiceImpl
implements CapitalizedInc
LoanTransaction savedCapitalizedIncomeAdjustment =
loanTransactionRepository.saveAndFlush(capitalizedIncomeAdjustment);
// Update outstanding loan balances
- loan.updateLoanOutstandingBalances();
+ loanBalanceService.updateLoanOutstandingBalances(loan);
// Create a note if provided
final String noteText = command.stringValueOfParameterNamed("note");
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java
index f7bbec6356..60f8cd2630 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java
@@ -40,6 +40,7 @@ import
org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
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.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel;
import org.springframework.beans.factory.InitializingBean;
@@ -56,9 +57,8 @@ public class InternalProgressiveLoanApiResource implements
InitializingBean {
private final LoanRepositoryWrapper loanRepository;
private final AdvancedPaymentScheduleTransactionProcessor
advancedPaymentScheduleTransactionProcessor;
- private final ProgressiveLoanInterestScheduleModelParserService
progressiveLoanInterestScheduleModelParserService;
private final InterestScheduleModelRepositoryWrapper writePlatformService;
- private final LoanTransactionService loanTransactionService;
+ private final LoanTransactionRepository loanTransactionRepository;
@Override
@SuppressFBWarnings("SLF4J_SIGN_ONLY_FORMAT")
@@ -87,7 +87,8 @@ public class InternalProgressiveLoanApiResource implements
InitializingBean {
}
private ProgressiveLoanInterestScheduleModel
reprocessTransactionsAndGetModel(final Loan loan) {
- final List<LoanTransaction> transactionsToReprocess =
loanTransactionService.retrieveListOfTransactionsForReprocessing(loan);
+ final List<LoanTransaction> transactionsToReprocess =
loanTransactionRepository
+ .findNonReversedTransactionsForReprocessingByLoan(loan);
final LocalDate businessDate =
ThreadLocalContextUtil.getBusinessDate();
final Pair<ChangedTransactionDetail,
ProgressiveLoanInterestScheduleModel>
changedTransactionDetailProgressiveLoanInterestScheduleModelPair =
advancedPaymentScheduleTransactionProcessor
.reprocessProgressiveLoanTransactionsTransactional(loan.getDisbursementDate(),
businessDate, transactionsToReprocess,
diff --git
a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java
b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java
index 7efc6ad18c..af7516f3bd 100644
---
a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java
+++
b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java
@@ -67,6 +67,7 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
@@ -74,7 +75,6 @@ import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanSchedul
import
org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
import org.apache.fineract.portfolio.loanaccount.service.InterestRefundService;
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
-import
org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
import
org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
import
org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel;
@@ -120,7 +120,7 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
public void setUp() {
underTest = new
AdvancedPaymentScheduleTransactionProcessor(emiCalculator,
Mockito.mock(LoanRepositoryWrapper.class),
Mockito.mock(InterestRefundService.class),
Mockito.mock(ExternalIdFactory.class),
Mockito.mock(LoanScheduleComponent.class),
- Mockito.mock(LoanTransactionService.class),
Mockito.mock(LoanChargeValidator.class),
+ Mockito.mock(LoanTransactionRepository.class),
Mockito.mock(LoanChargeValidator.class),
Mockito.mock(LoanBalanceService.class));
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L,
"default", "Default", "Asia/Kolkata", null));
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
index c546060ab1..b36039fdb1 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
@@ -134,7 +134,6 @@ public class LoanAccountDomainServiceJpa implements
LoanAccountDomainService {
private final ConfigurationDomainService configurationDomainService;
private final HolidayRepository holidayRepository;
private final WorkingDaysRepositoryWrapper workingDaysRepository;
-
private final JournalEntryWritePlatformService
journalEntryWritePlatformService;
private final NoteRepository noteRepository;
private final BusinessEventNotifierService businessEventNotifierService;
@@ -464,7 +463,7 @@ public class LoanAccountDomainServiceJpa implements
LoanAccountDomainService {
chargesPayment.updateComponents(zero, zero,
charge.getAmount(loan.getCurrency()), zero);
chargesPayment.updateLoan(loan);
loan.addLoanTransaction(chargesPayment);
- loan.updateLoanOutstandingBalances();
+ loanBalanceService.updateLoanOutstandingBalances(loan);
charge.markAsFullyPaid();
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
index c3534e4411..4f3aeb9b04 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
@@ -931,7 +931,7 @@ public class LoanAccrualsProcessingServiceImpl implements
LoanAccrualsProcessing
createUpdateIncomePostingTransaction(loan, compoundingDetail,
interest, fee, penalties, externalId);
createUpdateAccrualTransaction(loan, compoundingDetail, interest, fee,
penalties, feeDetails, externalId);
- loan.updateLoanOutstandingBalances();
+ loanBalanceService.updateLoanOutstandingBalances(loan);
}
private void createUpdateIncomePostingTransaction(Loan loan,
LoanInterestRecalcualtionAdditionalDetails compoundingDetail,
@@ -1000,7 +1000,7 @@ public class LoanAccrualsProcessingServiceImpl implements
LoanAccrualsProcessing
createIncomePostingAndAccrualTransactionOnLoanClosure(loan,
closedDate, interestToPost, feeToPost, penaltyToPost, amountToPost);
}
- loan.updateLoanOutstandingBalances();
+ loanBalanceService.updateLoanOutstandingBalances(loan);
}
private void determineCumulativeIncomeFromInstallments(final Loan loan,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
index abcce34a1d..af94f04d30 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
@@ -261,20 +261,20 @@ public class LoanAssemblerImpl implements LoanAssembler {
loanOfficer, loanPurpose, transactionProcessingStrategy,
loanProductRelatedDetail, loanCharges,
syncDisbursementWithMeeting, fixedEmiAmount,
disbursementDetails, maxOutstandingLoanBalance,
createStandingInstructionAtDisbursement,
isFloatingInterestRate, interestRateDifferential, rates,
- fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, loanScheduleModel,
- isEnableInstallmentLevelDelinquency, submittedOnDate);
+ fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, isEnableInstallmentLevelDelinquency,
+ submittedOnDate);
} else if (group != null) {
loanApplication = Loan.newGroupLoanApplication(accountNo, group,
loanAccountType, loanProduct, fund, loanOfficer, loanPurpose,
transactionProcessingStrategy, loanProductRelatedDetail,
loanCharges, syncDisbursementWithMeeting, fixedEmiAmount,
disbursementDetails, maxOutstandingLoanBalance,
createStandingInstructionAtDisbursement, isFloatingInterestRate,
interestRateDifferential, rates,
fixedPrincipalPercentagePerInstallment, externalId, loanApplicationTerms,
- loanScheduleModel, isEnableInstallmentLevelDelinquency,
submittedOnDate);
+ isEnableInstallmentLevelDelinquency, submittedOnDate);
} else if (client != null) {
loanApplication = Loan.newIndividualLoanApplication(accountNo,
client, loanAccountType, loanProduct, fund, loanOfficer,
loanPurpose, transactionProcessingStrategy,
loanProductRelatedDetail, loanCharges, collateral, fixedEmiAmount,
disbursementDetails, maxOutstandingLoanBalance,
createStandingInstructionAtDisbursement, isFloatingInterestRate,
interestRateDifferential, rates,
fixedPrincipalPercentagePerInstallment, externalId, loanApplicationTerms,
- loanScheduleModel, isEnableInstallmentLevelDelinquency,
submittedOnDate);
+ isEnableInstallmentLevelDelinquency, submittedOnDate);
} else {
throw new IllegalStateException("No loan application exists for
either a client or group (or both).");
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDisbursementService.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDisbursementService.java
index 8daee2dc69..428f0d4b2b 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDisbursementService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDisbursementService.java
@@ -63,6 +63,7 @@ public class LoanDisbursementService {
private final LoanDisbursementValidator loanDisbursementValidator;
private final ReprocessLoanTransactionsService
reprocessLoanTransactionsService;
private final LoanChargeService loanChargeService;
+ private final LoanBalanceService loanBalanceService;
public void updateDisbursementDetails(final Loan loan, final JsonCommand
jsonCommand, final Map<String, Object> actualChanges) {
final List<Long> disbursementList = loan.fetchDisbursementIds();
@@ -217,7 +218,7 @@ public class LoanDisbursementService {
chargesPayment.updateComponentsAndTotal(zero, zero,
disbursentMoney, zero);
chargesPayment.updateLoan(loan);
loan.addLoanTransaction(chargesPayment);
- loan.updateLoanOutstandingBalances();
+ loanBalanceService.updateLoanOutstandingBalances(loan);
}
final LocalDate expectedDate = loan.getExpectedFirstRepaymentOnDate();
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanTransactionProcessingServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanTransactionProcessingServiceImpl.java
index a8a358a3f8..825880c7ed 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanTransactionProcessingServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanTransactionProcessingServiceImpl.java
@@ -61,8 +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;
+ private final LoanTransactionService loanTransactionService;
@Override
public boolean canProcessLatestTransactionOnly(Loan loan, LoanTransaction
loanTransaction,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 43b64bf748..1dabf678f5 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -594,8 +594,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
}
if (loan.getLoanProduct().isMultiDisburseLoan() ||
loan.isProgressiveSchedule()) {
- final List<LoanTransaction>
allNonContraTransactionsPostDisbursement = loanTransactionService
- .retrieveListOfTransactionsForReprocessing(loan);
+ final List<LoanTransaction>
allNonContraTransactionsPostDisbursement = loanTransactionRepository
+ .findNonReversedTransactionsForReprocessingByLoan(loan);
if (!allNonContraTransactionsPostDisbursement.isEmpty()) {
reprocessLoanTransactionsService.reprocessTransactions(loan);
}
@@ -2246,7 +2246,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
throw new
MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName,
errorMessage);
}
} else {
- if (disbursementDataArray == null || disbursementDataArray.size()
== 0) {
+ if (disbursementDataArray == null ||
disbursementDataArray.isEmpty()) {
final String errorMessage = "For this loan product,
disbursement details must be provided";
throw new
MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName,
errorMessage);
}
@@ -2821,7 +2821,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
final ScheduleGeneratorDTO scheduleGeneratorDTO =
this.loanUtilService.buildScheduleGeneratorDTO(loan, null, null);
loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan,
scheduleGeneratorDTO);
}
- final List<LoanTransaction> loanTransactions =
loanTransactionService.retrieveListOfTransactionsForReprocessing(loan);
+ final List<LoanTransaction> loanTransactions =
loanTransactionRepository.findNonReversedTransactionsForReprocessingByLoan(loan);
loanTransactions.add(chargeOffTransaction);
reprocessLoanTransactionsService.reprocessParticularTransactions(loan,
loanTransactions);
loan.addLoanTransaction(chargeOffTransaction);
@@ -3031,7 +3031,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
final String errorMessage =
"loan.product.does.not.support.multiple.disbursals.cannot.undo.last.disbursal";
throw new LoanMultiDisbursementException(errorMessage);
}
- Integer trancheDisbursedCount = 0;
+ int trancheDisbursedCount = 0;
for (LoanDisbursementDetails disbursementDetails :
loan.getDisbursementDetails()) {
if (disbursementDetails.actualDisbursementDate() != null) {
trancheDisbursedCount++;
@@ -3361,13 +3361,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
final Map<String, Object> actualChanges = new LinkedHashMap<>();
List<LoanTransaction> loanTransactions =
loan.retrieveListOfTransactionsByType(LoanTransactionType.DISBURSEMENT);
loanTransactions.sort(Comparator.comparing(LoanTransaction::getId));
- final LoanTransaction lastDisbursalTransaction =
loanTransactions.get(loanTransactions.size() - 1);
+ final LoanTransaction lastDisbursalTransaction =
loanTransactions.getLast();
final LocalDate lastTransactionDate =
lastDisbursalTransaction.getTransactionDate();
existingTransactionIds.addAll(loanTransactionRepository.findTransactionIdsByLoan(loan));
existingReversedTransactionIds.addAll(loanTransactionRepository.findReversedTransactionIdsByLoan(loan));
- loanTransactions = loan.retrieveListOfTransactionsExcludeAccruals();
+ loanTransactions =
loanTransactionRepository.findNonReversedMonetaryTransactionsByLoan(loan);
Collections.reverse(loanTransactions);
for (final LoanTransaction previousTransaction : loanTransactions) {
if (DateUtils.isBefore(lastTransactionDate,
previousTransaction.getTransactionDate())
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
index 3cfcd1cef3..2606174fdc 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
@@ -36,6 +36,7 @@ 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;
@@ -53,7 +54,7 @@ public class ProgressiveLoanSummaryDataProvider extends
CommonLoanSummaryDataPro
private final AdvancedPaymentScheduleTransactionProcessor
advancedPaymentScheduleTransactionProcessor;
private final EMICalculator emiCalculator;
private final LoanRepositoryWrapper loanRepository;
- private final LoanTransactionService loanTransactionService;
+ private final LoanTransactionRepository loanTransactionRepository;
private final InterestScheduleModelRepositoryWrapper modelRepository;
@Override
@@ -81,8 +82,8 @@ public class ProgressiveLoanSummaryDataProvider extends
CommonLoanSummaryDataPro
}
private ProgressiveLoanInterestScheduleModel calculateModel(Loan loan,
LocalDate businessDate) {
- final List<LoanTransaction> transactionsToReprocess =
loanTransactionService.retrieveListOfTransactionsForReprocessing(loan)
- .stream().filter(t -> !t.isAccrualActivity()).toList();
+ 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());
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ReprocessLoanTransactionsServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ReprocessLoanTransactionsServiceImpl.java
index 5092c3a62d..acf391aab5 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ReprocessLoanTransactionsServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ReprocessLoanTransactionsServiceImpl.java
@@ -22,8 +22,6 @@ 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;
@@ -37,7 +35,6 @@ 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;
@@ -55,26 +52,18 @@ public class ReprocessLoanTransactionsServiceImpl
implements ReprocessLoanTransa
private final InterestScheduleModelRepositoryWrapper
interestScheduleModelRepositoryWrapper;
private final LoanBalanceService loanBalanceService;
private final LoanTransactionRepository loanTransactionRepository;
+ private final LoanTransactionService loanTransactionService;
@Override
public void reprocessTransactions(final Loan loan) {
- final List<LoanTransaction> allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsForReprocessing(loan);
+ final List<LoanTransaction> allNonContraTransactionsPostDisbursement =
loanTransactionService
+ .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() ||
transaction.isContractTermination());
- }
-
@Override
public void reprocessParticularTransactions(final Loan loan, final
List<LoanTransaction> loanTransactions) {
final ChangedTransactionDetail changedTransactionDetail =
reprocessTransactionsAndFetchChangedTransactions(loan, loanTransactions);
@@ -83,7 +72,7 @@ public class ReprocessLoanTransactionsServiceImpl implements
ReprocessLoanTransa
@Override
public void reprocessTransactionsWithPostTransactionChecks(final Loan
loan, final LocalDate transactionDate) {
- final List<LoanTransaction> transactions =
retrieveListOfTransactionsForReprocessing(loan);
+ final List<LoanTransaction> transactions =
loanTransactionRepository.findNonReversedTransactionsForReprocessingByLoan(loan);
final ChangedTransactionDetail changedTransactionDetail =
reprocessTransactionsAndFetchChangedTransactions(loan, transactions);
handleChangedDetail(changedTransactionDetail);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/contracttermination/LoanContractTerminationServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/contracttermination/LoanContractTerminationServiceImpl.java
index 28ee5ba502..b9cb527976 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/contracttermination/LoanContractTerminationServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/contracttermination/LoanContractTerminationServiceImpl.java
@@ -70,10 +70,10 @@ public class LoanContractTerminationServiceImpl {
private final LoanUtilService loanUtilService;
private final ExternalIdFactory externalIdFactory;
private final BusinessEventNotifierService businessEventNotifierService;
- private final LoanTransactionService loanTransactionService;
private final LoanScheduleService loanScheduleService;
private final LoanChargeValidator loanChargeValidator;
private final ProgressiveLoanTransactionValidator loanTransactionValidator;
+ private final LoanTransactionService loanTransactionService;
public CommandProcessingResult applyContractTermination(final JsonCommand
command) {
final Loan loan = loanAssembler.assembleFrom(command.getLoanId());
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java
index 04dd3aecb8..e3f52a4d73 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java
@@ -22,6 +22,7 @@ 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;
@@ -35,7 +36,6 @@ import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.imp
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;
@@ -138,9 +138,9 @@ public class LoanAccountAutoStarter {
final LoanRepositoryWrapper loanRepositoryWrapper,
final @Lazy ProgressiveLoanInterestRefundServiceImpl
progressiveLoanInterestRefundService,
final ExternalIdFactory externalIdFactory, final
LoanScheduleComponent loanSchedule,
- final LoanTransactionService loanTransactionService, final
LoanChargeValidator loanChargeValidator,
+ final LoanTransactionRepository loanTransactionRepository, final
LoanChargeValidator loanChargeValidator,
final LoanBalanceService loanBalanceService) {
return new AdvancedPaymentScheduleTransactionProcessor(emiCalculator,
loanRepositoryWrapper, progressiveLoanInterestRefundService,
- externalIdFactory, loanSchedule, loanTransactionService,
loanChargeValidator, loanBalanceService);
+ externalIdFactory, loanSchedule, loanTransactionRepository,
loanChargeValidator, loanBalanceService);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
index 15a96513ef..ae9d3b255f 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
@@ -457,9 +457,9 @@ public class LoanAccountConfiguration {
@ConditionalOnMissingBean(LoanDisbursementService.class)
public LoanDisbursementService loanDisbursementService(LoanChargeValidator
loanChargeValidator,
LoanDisbursementValidator loanDisbursementValidator,
ReprocessLoanTransactionsService reprocessLoanTransactionsService,
- LoanChargeService loanChargeService) {
+ LoanChargeService loanChargeService, LoanBalanceService
loanBalanceService) {
return new LoanDisbursementService(loanChargeValidator,
loanDisbursementValidator, reprocessLoanTransactionsService,
- loanChargeService);
+ loanChargeService, loanBalanceService);
}
@Bean
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
index a909e638a0..9d41557b70 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
@@ -363,7 +363,7 @@ public class LoanAccountDelinquencyRangeEventSerializerTest
{
DelinquencyReadPlatformService delinquencyReadPlatformService = new
DelinquencyReadPlatformServiceImpl(repositoryRange,
repositoryBucket, repositoryLoanDelinquencyTagHistory,
mapperRange, mapperBucket, mapperLoanDelinquencyTagHistory,
loanRepository, loanDelinquencyDomainService,
repositoryLoanInstallmentDelinquencyTag, loanDelinquencyActionRepository,
- delinquencyEffectivePauseHelper, configurationDomainService);
+ delinquencyEffectivePauseHelper, configurationDomainService,
Mockito.mock(LoanTransactionRepository.class));
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
when(loanProduct.isMultiDisburseLoan()).thenReturn(false);
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanBuilder.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanBuilder.java
index fa78079574..fc5a720942 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanBuilder.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanBuilder.java
@@ -40,7 +40,6 @@ import org.apache.fineract.portfolio.group.domain.Group;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
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;
@@ -80,7 +79,6 @@ public class LoanBuilder {
private BigDecimal fixedPrincipalPercentagePerInstallment;
private ExternalId externalId = ExternalId.empty();
private LoanApplicationTerms loanApplicationTerms =
mock(LoanApplicationTerms.class);
- private LoanScheduleModel loanScheduleModel =
mock(LoanScheduleModel.class);
private Boolean enableInstallmentLevelDelinquency = false;
private LocalDate submittedOnDate = LocalDate.now(ZoneId.systemDefault());
private LocalDate approvedOnDate;
@@ -116,8 +114,8 @@ public class LoanBuilder {
Loan loan = Loan.newIndividualLoanApplication(accountNo, client,
loanType, loanProduct, fund, loanOfficer, loanPurpose,
transactionProcessor, loanRepaymentScheduleDetail,
charges, collateral, fixedEmiAmount, disbursementDetails,
maxOutstandingLoanBalance,
createStandingInstructionAtDisbursement, isFloatingInterestRate,
interestRateDifferential,
- rates, fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, loanScheduleModel,
- enableInstallmentLevelDelinquency, submittedOnDate);
+ rates, fixedPrincipalPercentagePerInstallment, externalId,
loanApplicationTerms, enableInstallmentLevelDelinquency,
+ submittedOnDate);
if (id != null) {
loan.setId(id);
@@ -335,11 +333,6 @@ public class LoanBuilder {
return this;
}
- public LoanBuilder withLoanScheduleModel(LoanScheduleModel
loanScheduleModel) {
- this.loanScheduleModel = loanScheduleModel;
- return this;
- }
-
public LoanBuilder withEnableInstallmentLevelDelinquency(Boolean
enableInstallmentLevelDelinquency) {
this.enableInstallmentLevelDelinquency =
enableInstallmentLevelDelinquency;
return this;