FINERACT-2234: Replace in-memory transaction loops with repository queries
This commit is contained in:
committed by
Adam Saghy
parent
dd4ca4d3e2
commit
cb6a15c3d2
+4
-7
@@ -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)) {
|
||||
|
||||
+4
-2
@@ -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
|
||||
|
||||
+15
-85
@@ -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;
|
||||
}
|
||||
|
||||
-4
@@ -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();
|
||||
}
|
||||
|
||||
+96
-6
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
+11
-14
@@ -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;
|
||||
}
|
||||
|
||||
+17
-22
@@ -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());
|
||||
|
||||
+4
-4
@@ -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;
|
||||
}
|
||||
|
||||
+4
-4
@@ -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;
|
||||
}
|
||||
|
||||
+13
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+61
-2
@@ -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) {
|
||||
|
||||
+10
-12
@@ -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(),
|
||||
|
||||
+1
-1
@@ -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");
|
||||
|
||||
+4
-3
@@ -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,
|
||||
|
||||
+2
-2
@@ -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));
|
||||
|
||||
+1
-2
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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,
|
||||
|
||||
+4
-4
@@ -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).");
|
||||
}
|
||||
|
||||
+2
-1
@@ -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();
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+7
-7
@@ -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())
|
||||
|
||||
+4
-3
@@ -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());
|
||||
|
||||
+5
-16
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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());
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+2
-9
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user