diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java b/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java index 99b9c8ef8a0..f58aff5812b 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java @@ -158,15 +158,13 @@ private ExternalAssetOwnerTransferDetails createAssetOwnerTransferDetails(Loan l ExternalAssetOwnerTransfer externalAssetOwnerTransfer) { ExternalAssetOwnerTransferDetails details = new ExternalAssetOwnerTransferDetails(); details.setExternalAssetOwnerTransfer(externalAssetOwnerTransfer); - details.setTotalOutstanding(Objects.requireNonNullElse(loan.getLoanSummary().getTotalOutstanding(), BigDecimal.ZERO)); - details.setTotalPrincipalOutstanding( - Objects.requireNonNullElse(loan.getLoanSummary().getTotalPrincipalOutstanding(), BigDecimal.ZERO)); - details.setTotalInterestOutstanding( - Objects.requireNonNullElse(loan.getLoanSummary().getTotalInterestOutstanding(), BigDecimal.ZERO)); + details.setTotalOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalOutstanding(), BigDecimal.ZERO)); + details.setTotalPrincipalOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalPrincipalOutstanding(), BigDecimal.ZERO)); + details.setTotalInterestOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalInterestOutstanding(), BigDecimal.ZERO)); details.setTotalFeeChargesOutstanding( - Objects.requireNonNullElse(loan.getLoanSummary().getTotalFeeChargesOutstanding(), BigDecimal.ZERO)); + Objects.requireNonNullElse(loan.getSummary().getTotalFeeChargesOutstanding(), BigDecimal.ZERO)); details.setTotalPenaltyChargesOutstanding( - Objects.requireNonNullElse(loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), BigDecimal.ZERO)); + Objects.requireNonNullElse(loan.getSummary().getTotalPenaltyChargesOutstanding(), BigDecimal.ZERO)); details.setTotalOverpaid(Objects.requireNonNullElse(loan.getTotalOverpaid(), BigDecimal.ZERO)); return details; } @@ -179,7 +177,7 @@ private void createActiveMapping(Long loanId, ExternalAssetOwnerTransfer externa } private boolean isTransferable(final Loan loan) { - return MathUtil.nullToDefault(loan.getLoanSummary().getTotalOutstanding(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) > 0; + return MathUtil.nullToDefault(loan.getSummary().getTotalOutstanding(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) > 0; } private void handleSameDaySaleAndBuyback(final LocalDate settlementDate, final List transferDataList, diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/AccountingServiceImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/AccountingServiceImpl.java index 09416e5b021..394c53111f7 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/AccountingServiceImpl.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/AccountingServiceImpl.java @@ -80,10 +80,10 @@ private List createJournalEntries(Loan loan, ExternalAssetOwnerTra // transaction properties final Long transactionId = transfer.getId(); final LocalDate transactionDate = transfer.getSettlementDate(); - final BigDecimal principalAmount = loan.getLoanSummary().getTotalPrincipalOutstanding(); - final BigDecimal interestAmount = loan.getLoanSummary().getTotalInterestOutstanding(); - final BigDecimal feesAmount = loan.getLoanSummary().getTotalFeeChargesOutstanding(); - final BigDecimal penaltiesAmount = loan.getLoanSummary().getTotalPenaltyChargesOutstanding(); + final BigDecimal principalAmount = loan.getSummary().getTotalPrincipalOutstanding(); + final BigDecimal interestAmount = loan.getSummary().getTotalInterestOutstanding(); + final BigDecimal feesAmount = loan.getSummary().getTotalFeeChargesOutstanding(); + final BigDecimal penaltiesAmount = loan.getSummary().getTotalPenaltyChargesOutstanding(); final BigDecimal overPaymentAmount = loan.getTotalOverpaid(); // Moving money to asset transfer account diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceImpl.java index df211085f68..98d15141069 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceImpl.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceImpl.java @@ -61,6 +61,7 @@ public class LoanAccountOwnerTransferServiceImpl implements LoanAccountOwnerTran private final AccountingService accountingService; private final BusinessEventNotifierService businessEventNotifierService; + @Override public void handleLoanClosedOrOverpaid(Loan loan) { Long loanId = loan.getId(); @@ -165,15 +166,13 @@ private ExternalAssetOwnerTransferDetails createAssetOwnerTransferDetails(Loan l ExternalAssetOwnerTransfer externalAssetOwnerTransfer) { ExternalAssetOwnerTransferDetails details = new ExternalAssetOwnerTransferDetails(); details.setExternalAssetOwnerTransfer(externalAssetOwnerTransfer); - details.setTotalOutstanding(Objects.requireNonNullElse(loan.getLoanSummary().getTotalOutstanding(), BigDecimal.ZERO)); - details.setTotalPrincipalOutstanding( - Objects.requireNonNullElse(loan.getLoanSummary().getTotalPrincipalOutstanding(), BigDecimal.ZERO)); - details.setTotalInterestOutstanding( - Objects.requireNonNullElse(loan.getLoanSummary().getTotalInterestOutstanding(), BigDecimal.ZERO)); + details.setTotalOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalOutstanding(), BigDecimal.ZERO)); + details.setTotalPrincipalOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalPrincipalOutstanding(), BigDecimal.ZERO)); + details.setTotalInterestOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalInterestOutstanding(), BigDecimal.ZERO)); details.setTotalFeeChargesOutstanding( - Objects.requireNonNullElse(loan.getLoanSummary().getTotalFeeChargesOutstanding(), BigDecimal.ZERO)); + Objects.requireNonNullElse(loan.getSummary().getTotalFeeChargesOutstanding(), BigDecimal.ZERO)); details.setTotalPenaltyChargesOutstanding( - Objects.requireNonNullElse(loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), BigDecimal.ZERO)); + Objects.requireNonNullElse(loan.getSummary().getTotalPenaltyChargesOutstanding(), BigDecimal.ZERO)); details.setTotalOverpaid(Objects.requireNonNullElse(loan.getTotalOverpaid(), BigDecimal.ZERO)); return details; } diff --git a/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java b/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java index 02643749b13..81500a08f49 100644 --- a/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java +++ b/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java @@ -203,7 +203,7 @@ public void givenLoanBuyback() { final Loan loanForProcessing = Mockito.mock(Loan.class); when(loanForProcessing.getId()).thenReturn(1L); LoanSummary loanSummary = Mockito.mock(LoanSummary.class); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); ExternalAssetOwnerTransfer firstResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class); ExternalAssetOwnerTransfer secondResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class); when(firstResponseItem.getStatus()).thenReturn(ExternalTransferStatus.BUYBACK); @@ -248,7 +248,7 @@ public void givenLoanSale() { ExternalAssetOwnerTransfer newTransfer = Mockito.mock(ExternalAssetOwnerTransfer.class); when(externalAssetOwnerTransferRepository.save(any())).thenReturn(firstResponseItem).thenReturn(newTransfer); LoanSummary loanSummary = Mockito.mock(LoanSummary.class); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.ONE); when(newTransfer.getStatus()).thenReturn(ExternalTransferStatus.ACTIVE); // when @@ -296,7 +296,7 @@ public void givenLoanSaleButBalanceIsZero() { ExternalAssetOwnerTransfer newTransfer = Mockito.mock(ExternalAssetOwnerTransfer.class); when(externalAssetOwnerTransferRepository.save(any())).thenReturn(firstResponseItem).thenReturn(newTransfer); LoanSummary loanSummary = Mockito.mock(LoanSummary.class); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.ZERO); when(loanForProcessing.getTotalOverpaid()).thenReturn(BigDecimal.ZERO); when(newTransfer.getStatus()).thenReturn(ExternalTransferStatus.DECLINED); @@ -340,7 +340,7 @@ public void givenLoanSaleButBalanceIsNegative() { ExternalAssetOwnerTransfer newTransfer = Mockito.mock(ExternalAssetOwnerTransfer.class); when(externalAssetOwnerTransferRepository.save(any())).thenReturn(firstResponseItem).thenReturn(newTransfer); LoanSummary loanSummary = Mockito.mock(LoanSummary.class); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.ONE.negate()); when(loanForProcessing.getTotalOverpaid()).thenReturn(BigDecimal.ONE.negate()); when(newTransfer.getStatus()).thenReturn(ExternalTransferStatus.DECLINED); @@ -389,7 +389,7 @@ public void givenLoanSaleAnsBuyBackButBalanceIsNegative() { final Loan loanForProcessing = Mockito.mock(Loan.class); when(loanForProcessing.getId()).thenReturn(1L); LoanSummary loanSummary = Mockito.mock(LoanSummary.class); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.ZERO); when(loanForProcessing.getTotalOverpaid()).thenReturn(BigDecimal.ONE); ExternalAssetOwnerTransfer firstResponseItem = Mockito.mock(ExternalAssetOwnerTransfer.class); diff --git a/fineract-investor/src/test/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceTest.java b/fineract-investor/src/test/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceTest.java index adf33d889a6..74b1991a239 100644 --- a/fineract-investor/src/test/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceTest.java +++ b/fineract-investor/src/test/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceTest.java @@ -133,7 +133,7 @@ public void verifyWhenExecutePendingBuybackTransferThenBusinessEventIsSent() { final Loan loanForProcessing = Mockito.mock(Loan.class); when(loanForProcessing.getId()).thenReturn(1L); LoanSummary loanSummary = Mockito.mock(LoanSummary.class); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); ExternalAssetOwnerTransfer pendingBuybackTransfer = Mockito.mock(ExternalAssetOwnerTransfer.class); when(pendingBuybackTransfer.getStatus()).thenReturn(BUYBACK); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java index 26eb2980f2e..52b84de3572 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java @@ -85,7 +85,7 @@ private LoanStatus getNextStatus(LoanEvent loanEvent, Loan loan) { if (anyOfAllowedWhenComingFrom(from, LoanStatus.APPROVED, LoanStatus.CLOSED_OBLIGATIONS_MET)) { newState = activeTransition(); } else if (from.isOverpaid() && loan.getTotalOverpaidAsMoney().isZero()) { - if (loan.getLoanSummary().getTotalOutstanding(loan.getCurrency()).isZero()) { + if (loan.getSummary().getTotalOutstanding(loan.getCurrency()).isZero()) { newState = closeObligationsMetTransition(); } else { newState = activeTransition(); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index 981e4eb1ad1..bbc3c3d1fa7 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -613,7 +613,7 @@ public Integer getNumberOfRepayments() { return this.loanRepaymentScheduleDetail.getNumberOfRepayments(); } - private LoanSummary updateSummaryWithTotalFeeChargesDueAtDisbursement(final BigDecimal feeChargesDueAtDisbursement) { + public LoanSummary updateSummaryWithTotalFeeChargesDueAtDisbursement(final BigDecimal feeChargesDueAtDisbursement) { if (this.summary == null) { this.summary = LoanSummary.create(feeChargesDueAtDisbursement); } else { @@ -634,7 +634,7 @@ public void updateLoanSummaryForUndoWaiveCharge(final BigDecimal amountWaived, f this.summary.updateTotalWaived(this.summary.getTotalWaived().subtract(amountWaived)); } - private BigDecimal deriveSumTotalOfChargesDueAtDisbursement() { + public BigDecimal deriveSumTotalOfChargesDueAtDisbursement() { return getActiveCharges().stream() // .filter(LoanCharge::isDueAtDisbursement) // .map(LoanCharge::amount) // @@ -1721,108 +1721,12 @@ public List findExistingReversedTransactionIds() { .collect(Collectors.toList()); } - public ChangedTransactionDetail disburse(final AppUser currentUser, final JsonCommand command, final Map actualChanges, - final ScheduleGeneratorDTO scheduleGeneratorDTO, final PaymentDetail paymentDetail) { - final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed(ACTUAL_DISBURSEMENT_DATE); - - this.disbursedBy = currentUser; - updateLoanScheduleDependentDerivedFields(); - - actualChanges.put(LOCALE, command.locale()); - actualChanges.put(DATE_FORMAT, command.dateFormat()); - actualChanges.put(ACTUAL_DISBURSEMENT_DATE, command.stringValueOfParameterNamed(ACTUAL_DISBURSEMENT_DATE)); - - HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO(); - - // validate if disbursement date is a holiday or a non-working day - validateDisbursementDateIsOnNonWorkingDay(holidayDetailDTO.getWorkingDays(), holidayDetailDTO.isAllowTransactionsOnNonWorkingDay()); - validateDisbursementDateIsOnHoliday(holidayDetailDTO.isAllowTransactionsOnHoliday(), holidayDetailDTO.getHolidays()); - - regenerateRepaymentScheduleWithInterestRecalculationIfNeeded(this.repaymentScheduleDetail().isInterestRecalculationEnabled(), - isDisbursementMissed(), scheduleGeneratorDTO); - - updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement()); - updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate); - handleDisbursementTransaction(actualDisbursementDate, paymentDetail); - updateLoanSummaryDerivedFields(); - final Money interestApplied = Money.of(getCurrency(), this.summary.getTotalInterestCharged()); - - /* - * Add an interest applied transaction of the interest is accrued upfront (Up front accrual), no accounting or - * cash based accounting is selected - */ - if (((isMultiDisburmentLoan() && getDisbursedLoanDisbursementDetails().size() == 1) || !isMultiDisburmentLoan()) - && isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) { - ExternalId externalId = ExternalId.empty(); - if (TemporaryConfigurationServiceContainer.isExternalIdAutoGenerationEnabled()) { - externalId = ExternalId.generate(); - } - final LoanTransaction interestAppliedTransaction = LoanTransaction.accrueInterest(getOffice(), this, interestApplied, - actualDisbursementDate, externalId); - addLoanTransaction(interestAppliedTransaction); - } - - ChangedTransactionDetail result = reprocessTransactionForDisbursement(); - this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, this); - actualChanges.put(PARAM_STATUS, LoanEnumerations.status(this.loanStatus)); - return result; - } - - private void regenerateRepaymentScheduleWithInterestRecalculationIfNeeded(boolean interestRecalculationEnabledParam, - boolean disbursementMissedParam, ScheduleGeneratorDTO scheduleGeneratorDTO) { - LocalDate firstInstallmentDueDate = fetchRepaymentScheduleInstallment(1).getDueDate(); - if ((interestRecalculationEnabledParam && (DateUtils.isBeforeBusinessDate(firstInstallmentDueDate) || disbursementMissedParam))) { - regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); - } - } - - private List getDisbursedLoanDisbursementDetails() { + public List getDisbursedLoanDisbursementDetails() { return getDisbursementDetails().stream() // .filter(it -> it.actualDisbursementDate() != null) // .collect(Collectors.toList()); } - public void regenerateScheduleOnDisbursement(final ScheduleGeneratorDTO scheduleGeneratorDTO, final boolean recalculateSchedule, - final LocalDate actualDisbursementDate, BigDecimal emiAmount, LocalDate nextPossibleRepaymentDate, - LocalDate rescheduledRepaymentDate) { - boolean isEmiAmountChanged = false; - if ((this.loanProduct.isMultiDisburseLoan() || this.loanProduct.isCanDefineInstallmentAmount()) && emiAmount != null - && emiAmount.compareTo(retriveLastEmiAmount()) != 0) { - if (this.loanProduct.isMultiDisburseLoan()) { - final LocalDate dateValue = null; - final boolean isSpecificToInstallment = false; - final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled = scheduleGeneratorDTO - .isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled(); - LocalDate effectiveDateFrom = actualDisbursementDate; - if (!isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled && actualDisbursementDate.equals(nextPossibleRepaymentDate)) { - effectiveDateFrom = nextPossibleRepaymentDate.plusDays(1); - } - LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(), - effectiveDateFrom, emiAmount, dateValue, isSpecificToInstallment, this, LoanStatus.ACTIVE.getValue()); - this.loanTermVariations.add(loanVariationTerms); - } else { - this.fixedEmiAmount = emiAmount; - } - isEmiAmountChanged = true; - } - if (rescheduledRepaymentDate != null && this.loanProduct.isMultiDisburseLoan()) { - final boolean isSpecificToInstallment = false; - LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.DUE_DATE.getValue(), - nextPossibleRepaymentDate, emiAmount, rescheduledRepaymentDate, isSpecificToInstallment, this, - LoanStatus.ACTIVE.getValue()); - this.loanTermVariations.add(loanVariationTerms); - } - - if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged - || rescheduledRepaymentDate != null) { - if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { - regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); - } else { - regenerateRepaymentSchedule(scheduleGeneratorDTO); - } - } - } - public boolean canDisburse(final LocalDate actualDisbursementDate) { LocalDate loanSubmittedOnDate = this.submittedOnDate; final LoanStatus statusEnum = this.loanLifecycleStateMachine.dryTransition(LoanEvent.LOAN_DISBURSED, this); @@ -1918,25 +1822,6 @@ private void compareDisbursedToApprovedOrProposedPrincipal(BigDecimal disbursedA } } - private ChangedTransactionDetail reprocessTransactionForDisbursement() { - ChangedTransactionDetail changedTransactionDetail = null; - if (this.loanProduct.isMultiDisburseLoan()) { - final List allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsForReprocessing(); - if (!allNonContraTransactionsPostDisbursement.isEmpty()) { - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory - .determineProcessor(this.transactionProcessingStrategyCode); - changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTransactions(getDisbursementDate(), - allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges()); - for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - mapEntry.getValue().updateLoan(this); - } - this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values()); - } - updateLoanSummaryDerivedFields(); - } - return changedTransactionDetail; - } - private Collection fetchUndisbursedDetail() { Collection disbursementDetails = new ArrayList<>(); LocalDate date = null; @@ -2005,7 +1890,7 @@ private boolean atLeastOnceDisbursed() { return getDisbursementDetails().stream().anyMatch(it -> it.actualDisbursementDate() != null); } - private void updateLoanRepaymentPeriodsDerivedFields(final LocalDate actualDisbursementDate) { + public void updateLoanRepaymentPeriodsDerivedFields(final LocalDate actualDisbursementDate) { List installments = getRepaymentScheduleInstallments(); for (final LoanRepaymentScheduleInstallment repaymentPeriod : installments) { repaymentPeriod.updateDerivedFields(loanCurrency(), actualDisbursementDate); @@ -2079,7 +1964,7 @@ private BigDecimal constructFloatingInterestRates(final BigDecimal annualNominal return interestRate; } - private void handleDisbursementTransaction(final LocalDate disbursedOn, final PaymentDetail paymentDetail) { + public void handleDisbursementTransaction(final LocalDate disbursedOn, final PaymentDetail paymentDetail) { // add repayment transaction to track incoming money from client to mfi // for (charges due at time of disbursement) @@ -2102,12 +1987,11 @@ private void handleDisbursementTransaction(final LocalDate disbursedOn, final Pa /* * create a Charge applied transaction if Up front Accrual, None or Cash based accounting is enabled */ - if ((charge.getCharge().getChargeTimeType().equals(ChargeTimeType.DISBURSEMENT.getValue()) - && disbursedOn.equals(actualDisbursementDate) && (actualDisbursementDate != null) && !charge.isWaived() - && !charge.isFullyPaid()) - || (charge.getCharge().getChargeTimeType().equals(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue()) - && disbursedOn.equals(actualDisbursementDate) && (actualDisbursementDate != null) && !charge.isWaived() - && !charge.isFullyPaid())) { + if (charge.getCharge().getChargeTimeType().equals(ChargeTimeType.DISBURSEMENT.getValue()) + && disbursedOn.equals(actualDisbursementDate) && !charge.isWaived() && !charge.isFullyPaid() + || charge.getCharge().getChargeTimeType().equals(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue()) + && disbursedOn.equals(actualDisbursementDate) && actualDisbursementDate != null && !charge.isWaived() + && !charge.isFullyPaid()) { if (totalFeeChargesDueAtDisbursement.isGreaterThanZero() && !charge.getChargePaymentMode().isPaymentModeAccountTransfer()) { charge.markAsFullyPaid(); // Add "Loan Charge Paid By" details to this transaction @@ -2248,7 +2132,7 @@ public Map undoDisbursal(final ScheduleGeneratorDTO scheduleGene actualChanges.put(PARAM_STATUS, LoanEnumerations.status(this.loanStatus)); final LocalDate actualDisbursementDate = getDisbursementDate(); - final boolean isScheduleRegenerateRequired = isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate); + final boolean isScheduleRegenerateRequired = isActualDisbursedOnDateEarlierOrLaterThanExpected(actualDisbursementDate); this.actualDisbursementDate = null; this.disbursedBy = null; boolean isDisbursedAmountChanged = !MathUtil.isEqualTo(approvedPrincipal, @@ -2465,7 +2349,7 @@ private ChangedTransactionDetail handleRepaymentOrRecoveryOrWaiverTransaction(fi } if (loanTransaction.isRecoveryRepayment() - && loanTransaction.getAmount(loanCurrency()).getAmount().compareTo(getLoanSummary().getTotalWrittenOff()) > 0) { + && loanTransaction.getAmount(loanCurrency()).getAmount().compareTo(getSummary().getTotalWrittenOff()) > 0) { final String errorMessage = "The transaction amount cannot greater than the remaining written off amount."; throw new InvalidLoanStateTransitionException("transaction", "cannot.be.greater.than.total.written.off", errorMessage); } @@ -3268,7 +3152,7 @@ public BigDecimal getDisburseAmountForTemplate() { return principal; } - private boolean isActualDisbursedOnDateEarlierOrLaterThanExpected(final LocalDate actualDisbursedOnDate) { + public boolean isActualDisbursedOnDateEarlierOrLaterThanExpected(final LocalDate actualDisbursedOnDate) { boolean isRegenerationRequired = false; if (this.loanProduct.isMultiDisburseLoan()) { LoanDisbursementDetails details = fetchLastDisburseDetail(); @@ -3279,10 +3163,6 @@ private boolean isActualDisbursedOnDateEarlierOrLaterThanExpected(final LocalDat return isRegenerationRequired || !DateUtils.isEqual(actualDisbursedOnDate, this.expectedDisbursementDate); } - private boolean isRepaymentScheduleRegenerationRequiredForDisbursement(final LocalDate actualDisbursementDate) { - return isActualDisbursedOnDateEarlierOrLaterThanExpected(actualDisbursementDate); - } - private Money getTotalPaidInRepayments() { Money cumulativePaid = Money.zero(loanCurrency()); @@ -3819,20 +3699,6 @@ private LocalDate getMaxDateLimitForNewRepayment(final PeriodFrequencyType perio return dueRepaymentPeriodDate.minusDays(1);// get 2n-1 range date from startDate } - private void validateDisbursementDateIsOnNonWorkingDay(final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) { - if (!allowTransactionsOnNonWorkingDay && !WorkingDaysUtil.isWorkingDay(workingDays, getDisbursementDate())) { - final String errorMessage = "Expected disbursement date cannot be on a non working day"; - throw new LoanApplicationDateException("disbursement.date.on.non.working.day", errorMessage, getExpectedDisbursedOnLocalDate()); - } - } - - private void validateDisbursementDateIsOnHoliday(final boolean allowTransactionsOnHoliday, final List holidays) { - if (!allowTransactionsOnHoliday && HolidayUtil.isHoliday(getDisbursementDate(), holidays)) { - final String errorMessage = "Expected disbursement date cannot be on a holiday"; - throw new LoanApplicationDateException("disbursement.date.on.holiday", errorMessage, getExpectedDisbursedOnLocalDate()); - } - } - public void validateRepaymentDateIsOnNonWorkingDay(final LocalDate repaymentDate, final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) { if (!allowTransactionsOnNonWorkingDay && !WorkingDaysUtil.isWorkingDay(workingDays, repaymentDate)) { @@ -4843,13 +4709,6 @@ false, this.fixedPrincipalPercentagePerInstallment, false, repaymentStartDateTyp loanProduct.getLoanProductRelatedDetail().isEnableAccrualActivityPosting()); } - /** - * @return Loan summary embedded object - **/ - public LoanSummary getLoanSummary() { - return this.summary; - } - public void updateRescheduledByUser(AppUser rescheduledByUser) { this.rescheduledByUser = rescheduledByUser; } @@ -5250,7 +5109,7 @@ public void updateWriteOffReason(CodeValue writeOffReason) { public LoanRepaymentScheduleInstallment fetchLoanForeclosureDetail(final LocalDate closureDate) { Money[] receivables = retriveIncomeOutstandingTillDate(closureDate); - Money totalPrincipal = Money.of(getCurrency(), this.getLoanSummary().getTotalPrincipalOutstanding()); + Money totalPrincipal = Money.of(getCurrency(), this.getSummary().getTotalPrincipalOutstanding()); totalPrincipal = totalPrincipal.minus(receivables[3]); final Set compoundingDetails = null; final LocalDate currentDate = DateUtils.getBusinessLocalDate(); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java index b2f20684a24..eb7548fd74d 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java @@ -262,25 +262,25 @@ public static LoanTransaction accrueTransaction(final Loan loan, final Office of public static LoanTransaction initiateTransfer(final Office office, final Loan loan, final LocalDate transferDate, final ExternalId externalId) { return new LoanTransaction(loan, office, LoanTransactionType.INITIATE_TRANSFER.getValue(), transferDate, - loan.getLoanSummary().getTotalOutstanding(), loan.getLoanSummary().getTotalPrincipalOutstanding(), - loan.getLoanSummary().getTotalInterestOutstanding(), loan.getLoanSummary().getTotalFeeChargesOutstanding(), - loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId); + loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), + loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), + loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId); } public static LoanTransaction approveTransfer(final Office office, final Loan loan, final LocalDate transferDate, final ExternalId externalId) { return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate, - loan.getLoanSummary().getTotalOutstanding(), loan.getLoanSummary().getTotalPrincipalOutstanding(), - loan.getLoanSummary().getTotalInterestOutstanding(), loan.getLoanSummary().getTotalFeeChargesOutstanding(), - loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId); + loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), + loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), + loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId); } public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate, final ExternalId externalId) { return new LoanTransaction(loan, office, LoanTransactionType.WITHDRAW_TRANSFER.getValue(), transferDate, - loan.getLoanSummary().getTotalOutstanding(), loan.getLoanSummary().getTotalPrincipalOutstanding(), - loan.getLoanSummary().getTotalInterestOutstanding(), loan.getLoanSummary().getTotalFeeChargesOutstanding(), - loan.getLoanSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId); + loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), + loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), + loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId); } public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail, @@ -369,19 +369,19 @@ public static LoanTransaction writeoff(final Loan loan, final Office office, fin } public static LoanTransaction chargeOff(final Loan loan, final LocalDate chargeOffDate, final ExternalId externalId) { - BigDecimal principalPortion = loan.getLoanSummary().getTotalPrincipalOutstanding().compareTo(BigDecimal.ZERO) != 0 - ? loan.getLoanSummary().getTotalPrincipalOutstanding() + BigDecimal principalPortion = loan.getSummary().getTotalPrincipalOutstanding().compareTo(BigDecimal.ZERO) != 0 + ? loan.getSummary().getTotalPrincipalOutstanding() : null; - BigDecimal interestPortion = loan.getLoanSummary().getTotalInterestOutstanding().compareTo(BigDecimal.ZERO) != 0 - ? loan.getLoanSummary().getTotalInterestOutstanding() + BigDecimal interestPortion = loan.getSummary().getTotalInterestOutstanding().compareTo(BigDecimal.ZERO) != 0 + ? loan.getSummary().getTotalInterestOutstanding() : null; - BigDecimal feePortion = loan.getLoanSummary().getTotalFeeChargesOutstanding().compareTo(BigDecimal.ZERO) != 0 - ? loan.getLoanSummary().getTotalFeeChargesOutstanding() + BigDecimal feePortion = loan.getSummary().getTotalFeeChargesOutstanding().compareTo(BigDecimal.ZERO) != 0 + ? loan.getSummary().getTotalFeeChargesOutstanding() : null; - BigDecimal penaltyPortion = loan.getLoanSummary().getTotalPenaltyChargesOutstanding().compareTo(BigDecimal.ZERO) != 0 - ? loan.getLoanSummary().getTotalPenaltyChargesOutstanding() + BigDecimal penaltyPortion = loan.getSummary().getTotalPenaltyChargesOutstanding().compareTo(BigDecimal.ZERO) != 0 + ? loan.getSummary().getTotalPenaltyChargesOutstanding() : null; - BigDecimal totalOutstanding = loan.getLoanSummary().getTotalOutstanding(); + BigDecimal totalOutstanding = loan.getSummary().getTotalOutstanding(); return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.CHARGE_OFF.getValue(), chargeOffDate, totalOutstanding, principalPortion, interestPortion, feePortion, penaltyPortion, null, false, null, externalId); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java index fbe32e9b9df..b68e5d5f91a 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java @@ -2494,7 +2494,7 @@ private LoanScheduleDTO rescheduleNextInstallments(final MathContext mc, final L currency, applyInterestRecalculation); retainedInstallments.addAll(newRepaymentScheduleInstallments); loanScheduleParams.getCompoundingDateVariations().putAll(compoundingDateVariations); - loanApplicationTerms.updateTotalInterestDue(Money.of(currency, loan.getLoanSummary().getTotalInterestCharged())); + loanApplicationTerms.updateTotalInterestDue(Money.of(currency, loan.getSummary().getTotalInterestCharged())); } else { loanApplicationTerms.getLoanTermVariations().resetVariations(); periods.clear(); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java index 795bbec22c2..d4169fb8086 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java @@ -105,7 +105,7 @@ public void updateLoanArrearsAgeingDetailsWithOriginalSchedule(final Loan loan) Map> scheduleDate = this.jdbcTemplate.query(originalScheduleExtractor.schema, originalScheduleExtractor); if (scheduleDate.size() > 0) { - List> transactions = getLoanSummary(loan.getId(), loan.getLoanSummary()); + List> transactions = getLoanSummary(loan.getId(), loan.getSummary()); updateScheduleWithPaidDetail(scheduleDate, transactions); createInsertStatements(updateStatement, scheduleDate, count == 0); if (updateStatement.size() == 1) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStep.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStep.java index fc815f93741..8f6d45e3cfe 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStep.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStep.java @@ -80,7 +80,7 @@ private static boolean isDueEventNeededToBeSent(Loan loan, Long numberOfDaysBefo LoanRepaymentScheduleInstallment repaymentScheduleInstallment, LocalDate repaymentDate, List nonDisbursedStatuses) { return repaymentDate.minusDays(numberOfDaysBeforeDueDateToRaiseEvent).equals(currentDate) && !nonDisbursedStatuses.contains(loan.getStatus()) - && loan.getLoanSummary().getTotalOutstanding().compareTo(BigDecimal.ZERO) > 0 + && loan.getSummary().getTotalOutstanding().compareTo(BigDecimal.ZERO) > 0 && repaymentScheduleInstallment.getTotalOutstanding(loan.getCurrency()).isGreaterThanZero(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStep.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStep.java index 9d51055d1e1..d3714a381b2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStep.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStep.java @@ -45,8 +45,7 @@ public class CheckLoanRepaymentOverdueBusinessStep implements LoanCOBBusinessSte public Loan execute(Loan loan) { List nonDisbursedStatuses = Arrays.asList(LoanStatus.INVALID, LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, LoanStatus.APPROVED); - if (!nonDisbursedStatuses.contains(loan.getStatus()) - && loan.getLoanSummary().getTotalOutstanding().compareTo(BigDecimal.ZERO) > 0) { + if (!nonDisbursedStatuses.contains(loan.getStatus()) && loan.getSummary().getTotalOutstanding().compareTo(BigDecimal.ZERO) > 0) { log.debug("start processing loan repayment overdue business step for loan with Id [{}]", loan.getId()); Long numberOfDaysAfterDueDateToRaiseEvent = configurationDomainService.retrieveRepaymentOverdueDays(); if (loan.getLoanProduct().getOverDueDaysForRepaymentEvent() != null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java index dce06fdf98b..0f4dd818f60 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java @@ -97,8 +97,8 @@ public void updateFutureSchedule(LoanScheduleData loanScheduleData, final Long l if (loan.loanProduct().isMultiDisburseLoan()) { BigDecimal disbursedAmount = loan.getDisbursedAmount(); - BigDecimal principalRepaid = loan.getLoanSummary().getTotalPrincipalRepaid(); - BigDecimal principalWrittenOff = loan.getLoanSummary().getTotalPrincipalWrittenOff(); + BigDecimal principalRepaid = loan.getSummary().getTotalPrincipalRepaid(); + BigDecimal principalWrittenOff = loan.getSummary().getTotalPrincipalWrittenOff(); if (disbursedAmount.subtract(principalWrittenOff).subtract(principalRepaid).compareTo(BigDecimal.ZERO) <= 0) { return; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidator.java index 8ce70919d19..feb50685519 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidator.java @@ -56,7 +56,9 @@ import org.apache.fineract.organisation.workingdays.domain.WorkingDays; import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil; import org.apache.fineract.portfolio.calendar.domain.Calendar; +import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType; import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; +import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; import org.apache.fineract.portfolio.calendar.exception.NotValidRecurringDateException; import org.apache.fineract.portfolio.calendar.service.CalendarUtils; import org.apache.fineract.portfolio.client.domain.Client; @@ -66,6 +68,7 @@ import org.apache.fineract.portfolio.group.exception.GroupNotActiveException; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; +import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement; import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails; @@ -95,6 +98,7 @@ public final class LoanTransactionValidator { private final ApplicationCurrencyRepository applicationCurrencyRepository; private final LoanUtilService loanUtilService; private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; + private final CalendarInstanceRepository calendarInstanceRepository; private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { if (!dataValidationErrors.isEmpty()) { @@ -185,6 +189,30 @@ public void validateDisbursement(JsonCommand command, boolean isAccountTransfer, entityDatatableChecksWritePlatformService.runTheCheckForProduct(loan.getId(), EntityTables.LOAN.getName(), StatusEnum.DISBURSE.getValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); + + ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, null); + final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(), + CalendarEntityType.LOANS.getValue()); + if (loan.isSyncDisbursementWithMeeting()) { + validateDisbursementDateWithMeetingDate(actualDisbursementDate, calendarInstance, + scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), scheduleGeneratorDTO.getNumberOfdays()); + } + + // validate if disbursement date is a holiday or a non-working day + HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO(); + if (!holidayDetailDTO.isAllowTransactionsOnNonWorkingDay() + && !WorkingDaysUtil.isWorkingDay(holidayDetailDTO.getWorkingDays(), loan.getDisbursementDate())) { + final String errorMessage = "Expected disbursement date cannot be on a non working day"; + throw new LoanApplicationDateException("disbursement.date.on.non.working.day", errorMessage, + loan.getExpectedDisbursedOnLocalDate()); + } + if (!holidayDetailDTO.isAllowTransactionsOnHoliday() + && HolidayUtil.isHoliday(loan.getDisbursementDate(), holidayDetailDTO.getHolidays())) { + final String errorMessage = "Expected disbursement date cannot be on a holiday"; + throw new LoanApplicationDateException("disbursement.date.on.holiday", errorMessage, + loan.getExpectedDisbursedOnLocalDate()); + } + }); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index c7e64b39b6f..df76140dc55 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -46,6 +46,7 @@ import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; +import org.apache.fineract.infrastructure.configuration.service.TemporaryConfigurationServiceContainer; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; @@ -163,6 +164,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus; import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationRepository; @@ -193,6 +196,7 @@ import org.apache.fineract.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; +import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations; import org.apache.fineract.portfolio.note.domain.Note; import org.apache.fineract.portfolio.note.domain.NoteRepository; import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; @@ -212,6 +216,7 @@ @RequiredArgsConstructor public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService { + private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory; private final PlatformSecurityContext context; private final LoanTransactionValidator loanTransactionValidator; private final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer; @@ -250,7 +255,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler; private final PostDatedChecksRepository postDatedChecksRepository; private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository; - private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine; + private final LoanLifecycleStateMachine loanLifecycleStateMachine; private final LoanAccountLockService loanAccountLockService; private final ExternalIdFactory externalIdFactory; private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService; @@ -321,12 +326,6 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand // validate actual disbursement date against meeting date ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, null); - final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(), - CalendarEntityType.LOANS.getValue()); - if (loan.isSyncDisbursementWithMeeting()) { - this.loanTransactionValidator.validateDisbursementDateWithMeetingDate(actualDisbursementDate, calendarInstance, - scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), scheduleGeneratorDTO.getNumberOfdays()); - } businessEventNotifierService.notifyPreBusinessEvent(new LoanDisbursalBusinessEvent(loan)); @@ -415,13 +414,8 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || downPaymentEnabled) { createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO); } - - ChangedTransactionDetail changedTransactionDetail; - if (isPaymentTypeApplicableForDisbursementCharge) { - changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, paymentDetail); - } else { - changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, null); - } + ChangedTransactionDetail changedTransactionDetail = disburseLoan(command, isPaymentTypeApplicableForDisbursementCharge, + paymentDetail, loan, currentUser, changes, scheduleGeneratorDTO); loan.adjustNetDisbursalAmount(amountToDisburse.getAmount()); loanAccrualsProcessingService.reprocessExistingAccruals(loan); @@ -560,6 +554,69 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand .build(); } + private ChangedTransactionDetail disburseLoan(JsonCommand command, boolean isPaymentTypeApplicableForDisbursementCharge, + PaymentDetail paymentDetail, Loan loan, AppUser currentUser, Map changes, + ScheduleGeneratorDTO scheduleGeneratorDTO) { + final PaymentDetail paymentDetail1 = isPaymentTypeApplicableForDisbursementCharge ? paymentDetail : null; + final LocalDate actualDisbursementDate1 = command.localDateValueOfParameterNamed(Loan.ACTUAL_DISBURSEMENT_DATE); + + loan.setDisbursedBy(currentUser); + loan.updateLoanScheduleDependentDerivedFields(); + + changes.put(Loan.LOCALE, command.locale()); + changes.put(Loan.DATE_FORMAT, command.dateFormat()); + changes.put(Loan.ACTUAL_DISBURSEMENT_DATE, command.stringValueOfParameterNamed(Loan.ACTUAL_DISBURSEMENT_DATE)); + + boolean disbursementMissedParam = loan.isDisbursementMissed(); + LocalDate firstInstallmentDueDate = loan.fetchRepaymentScheduleInstallment(1).getDueDate(); + if ((loan.repaymentScheduleDetail().isInterestRecalculationEnabled() + && (DateUtils.isBeforeBusinessDate(firstInstallmentDueDate) || disbursementMissedParam))) { + loan.regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); + } + + loan.updateSummaryWithTotalFeeChargesDueAtDisbursement(loan.deriveSumTotalOfChargesDueAtDisbursement()); + loan.updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate1); + loan.handleDisbursementTransaction(actualDisbursementDate1, paymentDetail1); + loan.updateLoanSummaryDerivedFields(); + final Money interestApplied = Money.of(loan.getCurrency(), loan.getSummary().getTotalInterestCharged()); + + /* + * Add an interest applied transaction of the interest is accrued upfront (Up front accrual), no accounting or + * cash based accounting is selected + */ + if (((loan.isMultiDisburmentLoan() && loan.getDisbursedLoanDisbursementDetails().size() == 1) || !loan.isMultiDisburmentLoan()) + && loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) { + ExternalId externalId = ExternalId.empty(); + if (TemporaryConfigurationServiceContainer.isExternalIdAutoGenerationEnabled()) { + externalId = ExternalId.generate(); + } + final LoanTransaction interestAppliedTransaction = LoanTransaction.accrueInterest(loan.getOffice(), loan, interestApplied, + actualDisbursementDate1, externalId); + loan.addLoanTransaction(interestAppliedTransaction); + } + + ChangedTransactionDetail changedTransactionDetail = null; + if (loan.getLoanProduct().isMultiDisburseLoan()) { + final List allNonContraTransactionsPostDisbursement = loan.retrieveListOfTransactionsForReprocessing(); + if (!allNonContraTransactionsPostDisbursement.isEmpty()) { + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = transactionProcessorFactory + .determineProcessor(loan.getTransactionProcessingStrategyCode()); + changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTransactions(loan.getDisbursementDate(), + allNonContraTransactionsPostDisbursement, loan.getCurrency(), loan.getRepaymentScheduleInstallments(), + loan.getActiveCharges()); + for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { + mapEntry.getValue().updateLoan(loan); + } + loan.getLoanTransactions().addAll(changedTransactionDetail.getNewTransactionMappings().values()); + } + loan.updateLoanSummaryDerivedFields(); + } + + loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, loan); + changes.put(Loan.PARAM_STATUS, LoanEnumerations.status(loan.getLoanStatus())); + return changedTransactionDetail; + } + private void updatePostDatedChecks(Set postDatedChecks) { this.postDatedChecksRepository.saveAll(postDatedChecks); } @@ -747,11 +804,8 @@ public Map bulkLoanDisbursal(final JsonCommand command, final Co if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || downPaymentEnabled) { createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO); } - if (configurationDomainService.isPaymentTypeApplicableForDisbursementCharge()) { - changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, paymentDetail); - } else { - changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, null); - } + changedTransactionDetail = disburseLoan(command, configurationDomainService.isPaymentTypeApplicableForDisbursementCharge(), + paymentDetail, loan, currentUser, changes, scheduleGeneratorDTO); loanAccrualsProcessingService.reprocessExistingAccruals(loan); @@ -1080,7 +1134,7 @@ private ChangedTransactionDetail recalculateLoanWithInterestPaymentWaiverTxn(Loa loan.updateLoanSummaryDerivedFields(); - doPostLoanTransactionChecks(loan, newInterestPaymentWaiverTransaction.getTransactionDate(), defaultLoanLifecycleStateMachine); + doPostLoanTransactionChecks(loan, newInterestPaymentWaiverTransaction.getTransactionDate(), loanLifecycleStateMachine); return changedTransactionDetail; } @@ -1467,7 +1521,7 @@ public CommandProcessingResult adjustLoanTransaction(final Long loanId, final Lo ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail, - defaultLoanLifecycleStateMachine, transactionToAdjust, existingTransactionIds, existingReversedTransactionIds, + loanLifecycleStateMachine, transactionToAdjust, existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO, reversalTxnExternalId); loanAccrualsProcessingService.reprocessExistingAccruals(loan); @@ -1629,7 +1683,7 @@ public CommandProcessingResult chargebackLoanTransaction(final Long loanId, fina newTransaction = this.loanTransactionRepository.saveAndFlush(newTransaction); - loan.handleChargebackTransaction(newTransaction, defaultLoanLifecycleStateMachine); + loan.handleChargebackTransaction(newTransaction, loanLifecycleStateMachine); loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan); @@ -1713,8 +1767,8 @@ public CommandProcessingResult waiveInterestOnLoan(final Long loanId, final Json } ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); - final ChangedTransactionDetail changedTransactionDetail = loan.waiveInterest(waiveInterestTransaction, - defaultLoanLifecycleStateMachine, existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO); + final ChangedTransactionDetail changedTransactionDetail = loan.waiveInterest(waiveInterestTransaction, loanLifecycleStateMachine, + existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO); if (loan.getLoanRepaymentScheduleDetail().isInterestRecalculationEnabled()) { loanAccrualsProcessingService.reprocessExistingAccruals(loan); @@ -1811,7 +1865,7 @@ public CommandProcessingResult writeOff(final Long loanId, final JsonCommand com ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); - final ChangedTransactionDetail changedTransactionDetail = loan.closeAsWrittenOff(command, defaultLoanLifecycleStateMachine, changes, + final ChangedTransactionDetail changedTransactionDetail = loan.closeAsWrittenOff(command, loanLifecycleStateMachine, changes, existingTransactionIds, existingReversedTransactionIds, currentUser, scheduleGeneratorDTO); loanAccrualsProcessingService.reprocessExistingAccruals(loan); @@ -1885,8 +1939,8 @@ public CommandProcessingResult closeLoan(final Long loanId, final JsonCommand co } ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); - ChangedTransactionDetail changedTransactionDetail = loan.close(command, defaultLoanLifecycleStateMachine, changes, - existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO); + ChangedTransactionDetail changedTransactionDetail = loan.close(command, loanLifecycleStateMachine, changes, existingTransactionIds, + existingReversedTransactionIds, scheduleGeneratorDTO); loanAccrualsProcessingService.reprocessExistingAccruals(loan); if (loan.getLoanRepaymentScheduleDetail().isInterestRecalculationEnabled()) { @@ -1987,7 +2041,7 @@ public CommandProcessingResult closeAsRescheduled(final Long loanId, final JsonC changes.put("locale", command.locale()); changes.put("dateFormat", command.dateFormat()); - loan.closeAsMarkedForReschedule(command, defaultLoanLifecycleStateMachine, changes); + loan.closeAsMarkedForReschedule(command, loanLifecycleStateMachine, changes); saveLoanWithDataIntegrityViolationChecks(loan); @@ -2081,7 +2135,7 @@ public LoanTransaction initiateLoanTransfer(final Loan loan, final LocalDate tra ExternalId externalId = externalIdFactory.create(); final LoanTransaction newTransferTransaction = LoanTransaction.initiateTransfer(loan.getOffice(), loan, transferDate, externalId); loan.addLoanTransaction(newTransferTransaction); - LoanLifecycleStateMachine loanLifecycleStateMachine = defaultLoanLifecycleStateMachine; + LoanLifecycleStateMachine loanLifecycleStateMachine = this.loanLifecycleStateMachine; loanLifecycleStateMachine.transition(LoanEvent.LOAN_INITIATE_TRANSFER, loan); this.loanTransactionRepository.saveAndFlush(newTransferTransaction); @@ -2104,7 +2158,7 @@ public LoanTransaction acceptLoanTransfer(final Loan loan, final LocalDate trans final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.approveTransfer(acceptedInOffice, loan, transferDate, externalId); loan.addLoanTransaction(newTransferAcceptanceTransaction); - LoanLifecycleStateMachine loanLifecycleStateMachine = defaultLoanLifecycleStateMachine; + LoanLifecycleStateMachine loanLifecycleStateMachine = this.loanLifecycleStateMachine; if (loan.getTotalOverpaid() != null) { loanLifecycleStateMachine.transition(LoanEvent.LOAN_OVERPAYMENT, loan); } else { @@ -2137,7 +2191,7 @@ public LoanTransaction withdrawLoanTransfer(final Loan loan, final LocalDate tra final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.withdrawTransfer(loan.getOffice(), loan, transferDate, externalId); loan.addLoanTransaction(newTransferAcceptanceTransaction); - LoanLifecycleStateMachine loanLifecycleStateMachine = defaultLoanLifecycleStateMachine; + LoanLifecycleStateMachine loanLifecycleStateMachine = this.loanLifecycleStateMachine; loanLifecycleStateMachine.transition(LoanEvent.LOAN_WITHDRAW_TRANSFER, loan); this.loanTransactionRepository.saveAndFlush(newTransferAcceptanceTransaction); @@ -2154,7 +2208,7 @@ public LoanTransaction withdrawLoanTransfer(final Loan loan, final LocalDate tra public void rejectLoanTransfer(final Loan loan) { this.loanAssembler.setHelpers(loan); businessEventNotifierService.notifyPreBusinessEvent(new LoanRejectTransferBusinessEvent(loan)); - LoanLifecycleStateMachine loanLifecycleStateMachine = defaultLoanLifecycleStateMachine; + LoanLifecycleStateMachine loanLifecycleStateMachine = this.loanLifecycleStateMachine; loanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECT_TRANSFER, loan); saveLoanWithDataIntegrityViolationChecks(loan); businessEventNotifierService.notifyPostBusinessEvent(new LoanRejectTransferBusinessEvent(loan)); @@ -2555,7 +2609,7 @@ public CommandProcessingResult undoWriteOff(Long loanId) { ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); - ChangedTransactionDetail changedTransactionDetail = loan.undoWrittenOff(defaultLoanLifecycleStateMachine, existingTransactionIds, + ChangedTransactionDetail changedTransactionDetail = loan.undoWrittenOff(loanLifecycleStateMachine, existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO); loanAccrualsProcessingService.reprocessExistingAccruals(loan); if (loan.getLoanRepaymentScheduleDetail().isInterestRecalculationEnabled()) { @@ -2830,8 +2884,44 @@ private void regenerateScheduleOnDisbursement(final JsonCommand command, final L final LocalDate rescheduledRepaymentDate) { final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.fixedEmiAmountParameterName); - loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount, - nextPossibleRepaymentDate, rescheduledRepaymentDate); + + boolean isEmiAmountChanged = false; + LoanProduct loanProduct = loan.getLoanProduct(); + if ((loanProduct.isMultiDisburseLoan() || loanProduct.isCanDefineInstallmentAmount()) && emiAmount != null + && emiAmount.compareTo(loan.retriveLastEmiAmount()) != 0) { + if (loanProduct.isMultiDisburseLoan()) { + final LocalDate dateValue = null; + final boolean isSpecificToInstallment = false; + final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled = scheduleGeneratorDTO + .isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled(); + LocalDate effectiveDateFrom = actualDisbursementDate; + if (!isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled && actualDisbursementDate.equals(nextPossibleRepaymentDate)) { + effectiveDateFrom = nextPossibleRepaymentDate.plusDays(1); + } + LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(), + effectiveDateFrom, emiAmount, dateValue, isSpecificToInstallment, loan, LoanStatus.ACTIVE.getValue()); + loan.getLoanTermVariations().add(loanVariationTerms); + } else { + loan.setFixedEmiAmount(emiAmount); + } + isEmiAmountChanged = true; + } + if (rescheduledRepaymentDate != null && loanProduct.isMultiDisburseLoan()) { + final boolean isSpecificToInstallment = false; + LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.DUE_DATE.getValue(), + nextPossibleRepaymentDate, emiAmount, rescheduledRepaymentDate, isSpecificToInstallment, loan, + LoanStatus.ACTIVE.getValue()); + loan.getLoanTermVariations().add(loanVariationTerms); + } + + if (loan.isActualDisbursedOnDateEarlierOrLaterThanExpected(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged + || rescheduledRepaymentDate != null) { + if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) { + loan.regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); + } else { + loan.regenerateRepaymentSchedule(scheduleGeneratorDTO); + } + } loanAccrualsProcessingService.reprocessExistingAccruals(loan); if (loan.getLoanRepaymentScheduleDetail().isInterestRecalculationEnabled()) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java index 71828af657f..18287ad9354 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java @@ -346,8 +346,8 @@ public LoanUtilService loanUtilService(ApplicationCurrencyRepositoryWrapper appl @Bean @ConditionalOnMissingBean(LoanWritePlatformService.class) - public LoanWritePlatformService loanWritePlatformService(PlatformSecurityContext context, - LoanTransactionValidator loanTransactionValidator, + public LoanWritePlatformService loanWritePlatformService(LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory, + PlatformSecurityContext context, LoanTransactionValidator loanTransactionValidator, LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer, LoanRepositoryWrapper loanRepositoryWrapper, LoanAccountDomainService loanAccountDomainService, NoteRepository noteRepository, LoanTransactionRepository loanTransactionRepository, LoanTransactionRelationRepository loanTransactionRelationRepository, @@ -373,17 +373,18 @@ public LoanWritePlatformService loanWritePlatformService(PlatformSecurityContext LoanAccrualTransactionBusinessEventService loanAccrualTransactionBusinessEventService, ErrorHandler errorHandler, LoanDownPaymentHandlerService loanDownPaymentHandlerService, AccountTransferRepository accountTransferRepository, LoanTransactionAssembler loanTransactionAssembler, LoanAccrualsProcessingService loanAccrualsProcessingService) { - return new LoanWritePlatformServiceJpaRepositoryImpl(context, loanTransactionValidator, loanUpdateCommandFromApiJsonDeserializer, - loanRepositoryWrapper, loanAccountDomainService, noteRepository, loanTransactionRepository, - loanTransactionRelationRepository, loanAssembler, journalEntryWritePlatformService, calendarInstanceRepository, - paymentDetailWritePlatformService, holidayRepository, configurationDomainService, workingDaysRepository, - accountTransfersWritePlatformService, accountTransfersReadPlatformService, accountAssociationsReadPlatformService, - loanReadPlatformService, fromApiJsonHelper, calendarRepository, loanScheduleHistoryWritePlatformService, - loanApplicationValidator, accountAssociationRepository, accountTransferDetailRepository, businessEventNotifierService, - guarantorDomainService, loanUtilService, loanSummaryWrapper, entityDatatableChecksWritePlatformService, - transactionProcessingStrategy, codeValueRepository, cashierTransactionDataValidator, glimRepository, loanRepository, - repaymentWithPostDatedChecksAssembler, postDatedChecksRepository, loanRepaymentScheduleInstallmentRepository, - defaultLoanLifecycleStateMachine, loanAccountLockService, externalIdFactory, replayedTransactionBusinessEventService, + return new LoanWritePlatformServiceJpaRepositoryImpl(transactionProcessorFactory, context, loanTransactionValidator, + loanUpdateCommandFromApiJsonDeserializer, loanRepositoryWrapper, loanAccountDomainService, noteRepository, + loanTransactionRepository, loanTransactionRelationRepository, loanAssembler, journalEntryWritePlatformService, + calendarInstanceRepository, paymentDetailWritePlatformService, holidayRepository, configurationDomainService, + workingDaysRepository, accountTransfersWritePlatformService, accountTransfersReadPlatformService, + accountAssociationsReadPlatformService, loanReadPlatformService, fromApiJsonHelper, calendarRepository, + loanScheduleHistoryWritePlatformService, loanApplicationValidator, accountAssociationRepository, + accountTransferDetailRepository, businessEventNotifierService, guarantorDomainService, loanUtilService, loanSummaryWrapper, + entityDatatableChecksWritePlatformService, transactionProcessingStrategy, codeValueRepository, + cashierTransactionDataValidator, glimRepository, loanRepository, repaymentWithPostDatedChecksAssembler, + postDatedChecksRepository, loanRepaymentScheduleInstallmentRepository, defaultLoanLifecycleStateMachine, + loanAccountLockService, externalIdFactory, replayedTransactionBusinessEventService, loanAccrualTransactionBusinessEventService, errorHandler, loanDownPaymentHandlerService, accountTransferRepository, loanTransactionAssembler, loanAccrualsProcessingService); } diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java index 727cbdd51fa..a59677ac3ba 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java @@ -95,8 +95,8 @@ public void givenLoanWithInstallmentDueAfterConfiguredDaysWhenStepExecutionThenB when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct); when(loanProduct.getDueDaysForRepaymentEvent()).thenReturn(null); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); - when(loanForProcessing.getLoanSummary().getTotalOutstanding()).thenReturn(BigDecimal.ONE); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary().getTotalOutstanding()).thenReturn(BigDecimal.ONE); when(loanForProcessing.getCurrency()).thenReturn(currency); when(repaymentInstallment.getTotalOutstanding(currency)).thenReturn(money); when(money.isGreaterThanZero()).thenReturn(true); @@ -153,8 +153,8 @@ public void givenLoanWithInstallmentDueAfterConfiguredDaysInLoanProductWhenStepE // Loan Product setting overrides global settings when(loanProduct.getDueDaysForRepaymentEvent()).thenReturn(1); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); - when(loanForProcessing.getLoanSummary().getTotalOutstanding()).thenReturn(BigDecimal.ONE); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary().getTotalOutstanding()).thenReturn(BigDecimal.ONE); when(loanForProcessing.getCurrency()).thenReturn(currency); when(repaymentInstallment.getTotalOutstanding(currency)).thenReturn(money); when(money.isGreaterThanZero()).thenReturn(true); diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java index ab8b8ae1e73..345e23c3350 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java @@ -111,8 +111,8 @@ public void givenLoanWithInstallmentOverdueAfterConfiguredDaysWhenStepExecutionT List loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment); when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct); when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(null); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); - when(loanForProcessing.getLoanSummary().getTotalOutstanding()).thenReturn(BigDecimal.valueOf(100)); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary().getTotalOutstanding()).thenReturn(BigDecimal.valueOf(100)); when(loanForProcessing.getCurrency()).thenReturn(currency); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); @@ -138,8 +138,8 @@ public void givenLoanWithNoInstallmentOverdueAfterConfiguredDaysWhenStepExecutio loanInstallmentRepaymentDueDateBefore5Days, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0))); when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); - when(loanForProcessing.getLoanSummary().getTotalOutstanding()).thenReturn(BigDecimal.valueOf(100)); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary().getTotalOutstanding()).thenReturn(BigDecimal.valueOf(100)); when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(null); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); // when @@ -166,8 +166,8 @@ public void givenLoanWithInstallmentOverdueAfterConfiguredDaysButInstallmentPaid List loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallmentPaidOff); when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); - when(loanForProcessing.getLoanSummary().getTotalOutstanding()).thenReturn(BigDecimal.valueOf(100)); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary().getTotalOutstanding()).thenReturn(BigDecimal.valueOf(100)); when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(null); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); @@ -196,8 +196,8 @@ public void givenLoanWithInstallmentOverdueAfterConfiguredDaysInLoanProductWhenS when(loanForProcessing.getStatus()).thenReturn(LoanStatus.ACTIVE); // product configuration overrides global configuration when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(1); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); - when(loanForProcessing.getLoanSummary().getTotalOutstanding()).thenReturn(BigDecimal.valueOf(100)); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary().getTotalOutstanding()).thenReturn(BigDecimal.valueOf(100)); when(loanForProcessing.getCurrency()).thenReturn(currency); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); @@ -216,8 +216,8 @@ public void givenActiveLoanWithZeroOutstandingWhenStepExecutionThenNoBusinessEve Loan loanForProcessing = Mockito.mock(Loan.class); LoanSummary loanSummary = Mockito.mock(LoanSummary.class); when(loanForProcessing.getStatus()).thenReturn(LoanStatus.ACTIVE); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); - when(loanForProcessing.getLoanSummary().getTotalOutstanding()).thenReturn(BigDecimal.ZERO); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary().getTotalOutstanding()).thenReturn(BigDecimal.ZERO); // when Loan processedLoan = underTest.execute(loanForProcessing); // then - No Business Event raised @@ -240,8 +240,8 @@ public void givenActiveLoanWithNonZeroOutstandingWhenStepExecutionThenBusinessEv BigDecimal.valueOf(1.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0))); when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct); when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(1); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); - when(loanForProcessing.getLoanSummary().getTotalOutstanding()).thenReturn(BigDecimal.ONE); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary().getTotalOutstanding()).thenReturn(BigDecimal.ONE); when(loanForProcessing.getCurrency()).thenReturn(currency); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); // when diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java index 5e50faa2e7f..3728a6bd94c 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java @@ -117,7 +117,7 @@ public void testLoanRepaymentEventPayloadSerialization() throws IOException { when(loanForProcessing.getId()).thenReturn(1L); when(loanForProcessing.getAccountNumber()).thenReturn("0001"); when(loanForProcessing.getExternalId()).thenReturn(ExternalIdFactory.produce("externalId")); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.valueOf(0.0)); when(loanForProcessing.getCurrency()).thenReturn(loanCurrency); when(loanCurrency.getCode()).thenReturn("CODE"); @@ -168,7 +168,7 @@ public void testLoanRepaymentEventLoanIdMandatoryFieldValidation() { when(loanForProcessing.getId()).thenReturn(null); when(loanForProcessing.getAccountNumber()).thenReturn("0001"); when(loanForProcessing.getExternalId()).thenReturn(ExternalIdFactory.produce("externalId")); - when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanForProcessing.getSummary()).thenReturn(loanSummary); when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.valueOf(0.0)); when(loanForProcessing.getCurrency()).thenReturn(loanCurrency); when(loanCurrency.getCode()).thenReturn("CODE"); diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachineTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachineTest.java index 111893c3eca..98034716ff4 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachineTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachineTest.java @@ -143,7 +143,7 @@ public void testTransitionShouldWorkProperlyForLoanDisbursementWhenLoanIsOverpai Mockito.when(loan.getPlainStatus()).thenReturn(LoanStatus.OVERPAID.getValue()); Mockito.when(loan.getStatus()).thenReturn(LoanStatus.OVERPAID); Mockito.when(loan.getTotalOverpaidAsMoney()).thenReturn(zero); - Mockito.when(loan.getLoanSummary()).thenReturn(loanSummary); + Mockito.when(loan.getSummary()).thenReturn(loanSummary); Mockito.when(loanSummary.getTotalOutstanding(eq(currency))).thenReturn(one); // when underTest.transition(LoanEvent.LOAN_DISBURSED, loan); @@ -163,7 +163,7 @@ public void testTransitionShouldWorkProperlyForLoanDisbursementWhenLoanIsOverpai Mockito.when(loan.getPlainStatus()).thenReturn(LoanStatus.OVERPAID.getValue()); Mockito.when(loan.getStatus()).thenReturn(LoanStatus.OVERPAID); Mockito.when(loan.getTotalOverpaidAsMoney()).thenReturn(zero); - Mockito.when(loan.getLoanSummary()).thenReturn(loanSummary); + Mockito.when(loan.getSummary()).thenReturn(loanSummary); Mockito.when(loanSummary.getTotalOutstanding(currency)).thenReturn(zero); // when underTest.transition(LoanEvent.LOAN_DISBURSED, loan);