Skip to content

Commit 104ad76

Browse files
oleksii-novikov-onixadamsaghy
authored andcommitted
FINERACT-2234: Replace in-memory transaction loops with repository queries
1 parent 4c3da5b commit 104ad76

File tree

29 files changed

+281
-228
lines changed

29 files changed

+281
-228
lines changed

fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
5959
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
6060
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
61+
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
6162
import org.springframework.lang.NonNull;
6263
import org.springframework.transaction.annotation.Transactional;
6364

@@ -77,6 +78,7 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
7778
private final LoanDelinquencyActionRepository loanDelinquencyActionRepository;
7879
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
7980
private final ConfigurationDomainService configurationDomainService;
81+
private final LoanTransactionRepository loanTransactionRepository;
8082

8183
@Override
8284
public List<DelinquencyRangeData> retrieveAllDelinquencyRanges() {
@@ -174,7 +176,7 @@ public CollectionData calculateLoanCollectionData(final Long loanId) {
174176
private void addInstallmentLevelDelinquencyData(CollectionData collectionData, Long loanId) {
175177
Collection<LoanInstallmentDelinquencyTagData> loanInstallmentDelinquencyTagData = retrieveLoanInstallmentsCurrentDelinquencyTag(
176178
loanId);
177-
if (loanInstallmentDelinquencyTagData != null && loanInstallmentDelinquencyTagData.size() > 0) {
179+
if (loanInstallmentDelinquencyTagData != null && !loanInstallmentDelinquencyTagData.isEmpty()) {
178180

179181
// installment level delinquency grouped by rangeId, and summed up the delinquent amount
180182
Collection<InstallmentLevelDelinquency> installmentLevelDelinquencies = loanInstallmentDelinquencyTagData.stream()
@@ -254,12 +256,7 @@ private LocalDate getEarliestUnpaidInstallmentDate(final Loan loan) {
254256
}
255257
}
256258

257-
LocalDate lastTransactionDate = null;
258-
for (final LoanTransaction transaction : loan.getLoanTransactions()) {
259-
if (transaction.isRepaymentLikeType() && transaction.isGreaterThanZero()) {
260-
lastTransactionDate = transaction.getTransactionDate();
261-
}
262-
}
259+
final LocalDate lastTransactionDate = loanTransactionRepository.findLastRepaymentLikeTransactionDate(loan).orElse(null);
263260

264261
LocalDate possibleNextRepaymentDate = earliestUnpaidInstallmentDate;
265262
if (DateUtils.isAfter(lastTransactionDate, earliestUnpaidInstallmentDate)) {

fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
4343
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
4444
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
45+
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
4546
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionReadService;
4647
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
4748
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -60,11 +61,12 @@ public DelinquencyReadPlatformService delinquencyReadPlatformService(Delinquency
6061
LoanDelinquencyDomainService loanDelinquencyDomainService,
6162
LoanInstallmentDelinquencyTagRepository repositoryLoanInstallmentDelinquencyTag,
6263
LoanDelinquencyActionRepository loanDelinquencyActionRepository,
63-
DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper, ConfigurationDomainService configurationDomainService) {
64+
DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper, ConfigurationDomainService configurationDomainService,
65+
LoanTransactionRepository loanTransactionRepository) {
6466
return new DelinquencyReadPlatformServiceImpl(repositoryRange, repositoryBucket, repositoryLoanDelinquencyTagHistory, mapperRange,
6567
mapperBucket, mapperLoanDelinquencyTagHistory, loanRepository, loanDelinquencyDomainService,
6668
repositoryLoanInstallmentDelinquencyTag, loanDelinquencyActionRepository, delinquencyEffectivePauseHelper,
67-
configurationDomainService);
69+
configurationDomainService, loanTransactionRepository);
6870
}
6971

7072
@Bean

fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java

Lines changed: 15 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
6060
import org.apache.fineract.infrastructure.core.domain.ExternalId;
6161
import org.apache.fineract.infrastructure.core.service.DateUtils;
62-
import org.apache.fineract.infrastructure.core.service.MathUtil;
6362
import org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator;
6463
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
6564
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -74,7 +73,6 @@
7473
import org.apache.fineract.portfolio.group.domain.Group;
7574
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
7675
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
77-
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
7876
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
7977
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
8078
import org.apache.fineract.portfolio.loanproduct.domain.LoanSupportedInterestRefundTypes;
@@ -433,13 +431,13 @@ public static Loan newIndividualLoanApplication(final String accountNo, final Cl
433431
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
434432
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
435433
final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment,
436-
final ExternalId externalId, final LoanApplicationTerms loanApplicationTerms, final LoanScheduleModel loanScheduleModel,
437-
final Boolean enableInstallmentLevelDelinquency, final LocalDate submittedOnDate) {
434+
final ExternalId externalId, final LoanApplicationTerms loanApplicationTerms, final Boolean enableInstallmentLevelDelinquency,
435+
final LocalDate submittedOnDate) {
438436
return new Loan(accountNo, client, null, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
439437
loanRepaymentScheduleDetail, null, loanCharges, collateral, null, fixedEmiAmount, disbursementDetails,
440438
maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates,
441-
fixedPrincipalPercentagePerInstallment, externalId, loanApplicationTerms, loanScheduleModel,
442-
enableInstallmentLevelDelinquency, submittedOnDate);
439+
fixedPrincipalPercentagePerInstallment, externalId, loanApplicationTerms, enableInstallmentLevelDelinquency,
440+
submittedOnDate);
443441
}
444442

445443
public static Loan newGroupLoanApplication(final String accountNo, final Group group, final AccountType loanType,
@@ -450,13 +448,13 @@ public static Loan newGroupLoanApplication(final String accountNo, final Group g
450448
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
451449
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
452450
final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment,
453-
final ExternalId externalId, final LoanApplicationTerms loanApplicationTerms, final LoanScheduleModel loanScheduleModel,
454-
final Boolean enableInstallmentLevelDelinquency, final LocalDate submittedOnDate) {
451+
final ExternalId externalId, final LoanApplicationTerms loanApplicationTerms, final Boolean enableInstallmentLevelDelinquency,
452+
final LocalDate submittedOnDate) {
455453
return new Loan(accountNo, null, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
456454
loanRepaymentScheduleDetail, null, loanCharges, null, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails,
457455
maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates,
458-
fixedPrincipalPercentagePerInstallment, externalId, loanApplicationTerms, loanScheduleModel,
459-
enableInstallmentLevelDelinquency, submittedOnDate);
456+
fixedPrincipalPercentagePerInstallment, externalId, loanApplicationTerms, enableInstallmentLevelDelinquency,
457+
submittedOnDate);
460458
}
461459

462460
public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group,
@@ -467,13 +465,13 @@ public static Loan newIndividualLoanApplicationFromGroup(final String accountNo,
467465
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
468466
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
469467
final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment,
470-
final ExternalId externalId, final LoanApplicationTerms loanApplicationTerms, final LoanScheduleModel loanScheduleModel,
471-
final Boolean enableInstallmentLevelDelinquency, final LocalDate submittedOnDate) {
468+
final ExternalId externalId, final LoanApplicationTerms loanApplicationTerms, final Boolean enableInstallmentLevelDelinquency,
469+
final LocalDate submittedOnDate) {
472470
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
473471
loanRepaymentScheduleDetail, null, loanCharges, null, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails,
474472
maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates,
475-
fixedPrincipalPercentagePerInstallment, externalId, loanApplicationTerms, loanScheduleModel,
476-
enableInstallmentLevelDelinquency, submittedOnDate);
473+
fixedPrincipalPercentagePerInstallment, externalId, loanApplicationTerms, enableInstallmentLevelDelinquency,
474+
submittedOnDate);
477475
}
478476

479477
protected Loan() {
@@ -488,8 +486,8 @@ private Loan(final String accountNo, final Client client, final Group group, fin
488486
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
489487
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
490488
final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment,
491-
final ExternalId externalId, final LoanApplicationTerms loanApplicationTerms, final LoanScheduleModel loanScheduleModel,
492-
final Boolean enableInstallmentLevelDelinquency, final LocalDate submittedOnDate) {
489+
final ExternalId externalId, final LoanApplicationTerms loanApplicationTerms, final Boolean enableInstallmentLevelDelinquency,
490+
final LocalDate submittedOnDate) {
493491
this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
494492

495493
this.isFloatingInterestRate = isFloatingInterestRate;
@@ -850,17 +848,6 @@ public void removePostDatedChecks() {
850848
this.postDatedChecks = new ArrayList<>();
851849
}
852850

853-
public List<LoanTransaction> retrieveListOfTransactionsExcludeAccruals() {
854-
final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
855-
for (final LoanTransaction transaction : this.loanTransactions) {
856-
if (transaction.isNotReversed() && !transaction.isNonMonetaryTransaction()) {
857-
repaymentsOrWaivers.add(transaction);
858-
}
859-
}
860-
repaymentsOrWaivers.sort(LoanTransactionComparator.INSTANCE);
861-
return repaymentsOrWaivers;
862-
}
863-
864851
public List<LoanTransaction> retrieveListOfTransactionsByType(final LoanTransactionType transactionType) {
865852
return this.loanTransactions.stream()
866853
.filter(transaction -> transaction.isNotReversed() && transaction.getTypeOf().equals(transactionType))
@@ -880,11 +867,6 @@ public LoanTransaction findWriteOffTransaction() {
880867
.orElse(null);
881868
}
882869

883-
public Money calculateTotalRecoveredPayments() {
884-
// in case logic for reversing recovered payment is implemented handle subtraction from totalRecoveredPayments
885-
return getTotalRecoveredPayments();
886-
}
887-
888870
public MonetaryCurrency loanCurrency() {
889871
return this.loanRepaymentScheduleDetail.getCurrency();
890872
}
@@ -1033,17 +1015,6 @@ public Money getTotalPaidInRepayments() {
10331015
return cumulativePaid;
10341016
}
10351017

1036-
public Money getTotalRecoveredPayments() {
1037-
Money cumulativePaid = Money.zero(getCurrency());
1038-
1039-
for (final LoanTransaction recoveredPayment : this.loanTransactions) {
1040-
if (recoveredPayment.isRecoveryRepayment()) {
1041-
cumulativePaid = cumulativePaid.plus(recoveredPayment.getAmount(getCurrency()));
1042-
}
1043-
}
1044-
return cumulativePaid;
1045-
}
1046-
10471018
public Money getTotalPrincipalOutstandingUntil(LocalDate date) {
10481019
return getRepaymentScheduleInstallments().stream()
10491020
.filter(installment -> installment.getDueDate().isBefore(date) || installment.getDueDate().isEqual(date))
@@ -1236,7 +1207,7 @@ public LocalDate getLastUserTransactionDate() {
12361207
.filter(date -> DateUtils.isBefore(getDisbursementDate(), date)).max(LocalDate::compareTo).orElse(getDisbursementDate());
12371208
}
12381209

1239-
private boolean isUserTransaction(LoanTransaction transaction) {
1210+
public boolean isUserTransaction(LoanTransaction transaction) {
12401211
return !(transaction.isReversed() || transaction.isAccrualRelated() || transaction.isIncomePosting());
12411212
}
12421213

@@ -1391,47 +1362,6 @@ public LocalDate fetchInterestRecalculateFromDate() {
13911362
return recalculatedOn;
13921363
}
13931364

1394-
public void updateLoanOutstandingBalances() {
1395-
Money outstanding = Money.zero(getCurrency());
1396-
List<LoanTransaction> loanTransactions = retrieveListOfTransactionsExcludeAccruals();
1397-
for (LoanTransaction loanTransaction : loanTransactions) {
1398-
if (loanTransaction.isDisbursement() || loanTransaction.isIncomePosting() || loanTransaction.isCapitalizedIncome()) {
1399-
outstanding = outstanding.plus(loanTransaction.getAmount(getCurrency()))
1400-
.minus(loanTransaction.getOverPaymentPortion(getCurrency()));
1401-
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
1402-
} else if (loanTransaction.isChargeback() || loanTransaction.isCreditBalanceRefund()) {
1403-
Money transactionOutstanding = loanTransaction.getPrincipalPortion(getCurrency());
1404-
if (loanTransaction.isOverPaid()) {
1405-
// in case of advanced payment strategy and creditAllocations the full amount is recognized first
1406-
if (this.getCreditAllocationRules() != null && !this.getCreditAllocationRules().isEmpty()) {
1407-
Money payedPrincipal = loanTransaction.getLoanTransactionToRepaymentScheduleMappings().stream() //
1408-
.map(mapping -> mapping.getPrincipalPortion(getCurrency())) //
1409-
.reduce(Money.zero(getCurrency()), Money::plus);
1410-
transactionOutstanding = loanTransaction.getPrincipalPortion(getCurrency()).minus(payedPrincipal);
1411-
} else {
1412-
// in case legacy payment strategy
1413-
transactionOutstanding = loanTransaction.getAmount(getCurrency())
1414-
.minus(loanTransaction.getOverPaymentPortion(getCurrency()));
1415-
}
1416-
if (transactionOutstanding.isLessThanZero()) {
1417-
transactionOutstanding = Money.zero(getCurrency());
1418-
}
1419-
}
1420-
outstanding = outstanding.plus(transactionOutstanding);
1421-
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
1422-
} else if (!loanTransaction.isAccrualActivity()) {
1423-
if (this.loanInterestRecalculationDetails != null
1424-
&& this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()
1425-
&& !loanTransaction.isRepaymentAtDisbursement()) {
1426-
outstanding = outstanding.minus(loanTransaction.getAmount(getCurrency()));
1427-
} else {
1428-
outstanding = outstanding.minus(loanTransaction.getPrincipalPortion(getCurrency()));
1429-
}
1430-
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
1431-
}
1432-
}
1433-
}
1434-
14351365
public String transactionProcessingStrategy() {
14361366
return this.transactionProcessingStrategyCode;
14371367
}

fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -911,10 +911,6 @@ public boolean isPaymentTransaction() {
911911
|| this.isIncomePosting());
912912
}
913913

914-
public boolean hasLoanTransactionRelations() {
915-
return !loanTransactionRelations.isEmpty();
916-
}
917-
918914
public List<LoanTransactionRelation> getLoanTransactionRelations(Predicate<LoanTransactionRelation> predicate) {
919915
return loanTransactionRelations.stream().filter(predicate).toList();
920916
}

0 commit comments

Comments
 (0)