From 793255188088f74036b153bc9d01d0fa1ee190ae Mon Sep 17 00:00:00 2001 From: Kristof Jozsa Date: Wed, 26 Jun 2024 14:34:54 +0200 Subject: [PATCH] FINERACT-2090: restructure loan disbursements --- .../portfolio/loanaccount/domain/Loan.java | 11 +- .../LoanTransactionValidator.java | 143 +++++++++++++----- ...WritePlatformServiceJpaRepositoryImpl.java | 77 ++-------- ...RepaymentRescheduleAtDisbursementTest.java | 21 ++- 4 files changed, 137 insertions(+), 115 deletions(-) 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 4ef74ff9c04..981e4eb1ad1 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 @@ -1993,8 +1993,12 @@ private void removeDisbursementDetail() { private boolean isDisbursementAllowed() { List disbursementDetails = getDisbursementDetails(); - return disbursementDetails == null || disbursementDetails.isEmpty() + boolean isSingleDisburseLoanDisbursementAllowed = disbursementDetails == null || disbursementDetails.isEmpty() || disbursementDetails.stream().anyMatch(it -> it.actualDisbursementDate() == null); + boolean isMultiDisburseLoanDisbursementAllowed = isMultiDisburmentLoan() + && (disbursementDetails == null || disbursementDetails.stream().filter(it -> it.actualDisbursementDate() != null) + .count() < loanProduct.getLoanProductTrancheDetails().maxTrancheCount()); + return isSingleDisburseLoanDisbursementAllowed || isMultiDisburseLoanDisbursementAllowed; } private boolean atLeastOnceDisbursed() { @@ -3210,8 +3214,9 @@ public boolean isOpen() { public boolean isAllTranchesNotDisbursed() { LoanStatus actualLoanStatus = LoanStatus.fromInt(this.loanStatus); - return this.loanProduct.isMultiDisburseLoan() && (actualLoanStatus.isActive() || actualLoanStatus.isApproved() - || actualLoanStatus.isClosedObligationsMet() || actualLoanStatus.isOverpaid()) && isDisbursementAllowed(); + boolean isInRightStatus = actualLoanStatus.isActive() || actualLoanStatus.isApproved() || actualLoanStatus.isClosedObligationsMet() + || actualLoanStatus.isOverpaid(); + return this.loanProduct.isMultiDisburseLoan() && isInRightStatus && isDisbursementAllowed(); } private boolean hasDisbursementTransaction() { 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 4ff6935bc06..8ce70919d19 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 @@ -38,11 +38,15 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; import org.apache.fineract.organisation.holiday.domain.Holiday; import org.apache.fineract.organisation.holiday.service.HolidayUtil; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; @@ -57,21 +61,27 @@ import org.apache.fineract.portfolio.calendar.service.CalendarUtils; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; +import org.apache.fineract.portfolio.collateralmanagement.exception.LoanCollateralAmountNotSufficientException; import org.apache.fineract.portfolio.group.domain.Group; 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.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement; import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; +import org.apache.fineract.portfolio.loanaccount.exception.DateMismatchException; import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanStateTransitionException; import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationDateException; import org.apache.fineract.portfolio.loanaccount.exception.LoanChargeRefundException; import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException; import org.apache.fineract.portfolio.loanaccount.exception.LoanRepaymentScheduleNotFoundException; import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; @Component @@ -81,8 +91,10 @@ public final class LoanTransactionValidator { private final FromJsonHelper fromApiJsonHelper; private final LoanApplicationValidator fromApiJsonDeserializer; private final LoanRepository loanRepository; + private final LoanRepositoryWrapper loanRepositoryWrapper; private final ApplicationCurrencyRepository applicationCurrencyRepository; private final LoanUtilService loanUtilService; + private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { if (!dataValidationErrors.isEmpty()) { @@ -91,13 +103,105 @@ private void throwExceptionIfValidationWarningsExist(final List disbursementParameters = null; + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, getDisbursementParameters(isAccountTransfer)); + + LoanApplicationValidator.validateOrThrow("loan.disbursement", baseDataValidator -> { + final JsonElement element = this.fromApiJsonHelper.parse(json); + final LocalDate actualDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("actualDisbursementDate", element); + baseDataValidator.reset().parameter("actualDisbursementDate").value(actualDisbursementDate).notNull(); + + final String note = this.fromApiJsonHelper.extractStringNamed("note", element); + baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000); + + final BigDecimal principal = this.fromApiJsonHelper + .extractBigDecimalWithLocaleNamed(LoanApiConstants.principalDisbursedParameterName, element); + baseDataValidator.reset().parameter(LoanApiConstants.principalDisbursedParameterName).value(principal).ignoreIfNull() + .positiveAmount(); + + final BigDecimal netDisbursalAmount = this.fromApiJsonHelper + .extractBigDecimalWithLocaleNamed(LoanApiConstants.disbursementNetDisbursalAmountParameterName, element); + baseDataValidator.reset().parameter(LoanApiConstants.disbursementNetDisbursalAmountParameterName).value(netDisbursalAmount) + .ignoreIfNull().positiveAmount(); + + final BigDecimal emiAmount = this.fromApiJsonHelper + .extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedEmiAmountParameterName, element); + baseDataValidator.reset().parameter(LoanApiConstants.fixedEmiAmountParameterName).value(emiAmount).ignoreIfNull() + .positiveAmount().notGreaterThanMax(principal); + + validatePaymentDetails(baseDataValidator, element); + + if (command.parameterExists("postDatedChecks")) { + this.validateDisbursementWithPostDatedChecks(command.json(), loanId); + } + + final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true); + validateLoanClientIsActive(loan); + validateLoanGroupIsActive(loan); + + if (loan.isChargedOff() && DateUtils.isBefore(actualDisbursementDate, loan.getChargedOffOnDate())) { + throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: " + + loan.getId() + + " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan", + loan.getId()); + } + + boolean isSingleDisburseLoan = !loan.getLoanProduct().isMultiDisburseLoan(); + boolean isSingleDisburseNotApprovedOrDisbursedAlready = isSingleDisburseLoan && !(loan.isApproved() && loan.isNotDisbursed()); + boolean isMultiDisburseLoanAndAllTranchesDisbursed = loan.getLoanProduct().isMultiDisburseLoan() + && !loan.isAllTranchesNotDisbursed(); + if (isSingleDisburseNotApprovedOrDisbursedAlready || isMultiDisburseLoanAndAllTranchesDisbursed) { + final String defaultUserMessage = "Loan Disbursal is not allowed. Loan Account is not in approved and not disbursed state."; + final ApiParameterError error = ApiParameterError + .generalError("error.msg.loan.disbursal.account.is.not.approve.not.disbursed.state", defaultUserMessage); + baseDataValidator.getDataValidationErrors().add(error); + } + + final BigDecimal disbursedAmount = loan.getDisbursedAmount(); + final Set loanCollateralManagements = loan.getLoanCollateralManagements(); + + if ((loanCollateralManagements != null && !loanCollateralManagements.isEmpty()) && loan.getLoanType().isIndividualAccount()) { + BigDecimal totalCollateral = collectTotalCollateral(loanCollateralManagements); + + // Validate the loan collateral value against the disbursedAmount + if (disbursedAmount.compareTo(totalCollateral) > 0) { + throw new LoanCollateralAmountNotSufficientException(disbursedAmount); + } + } + + // validate ActualDisbursement Date Against Expected Disbursement Date + LoanProduct loanProduct = loan.loanProduct(); + if (loanProduct.isSyncExpectedWithDisbursementDate()) { + if (!loan.getExpectedDisbursedOnLocalDate().equals(actualDisbursementDate)) { + throw new DateMismatchException(actualDisbursementDate, loan.getExpectedDisbursedOnLocalDate()); + } + } + + entityDatatableChecksWritePlatformService.runTheCheckForProduct(loan.getId(), EntityTables.LOAN.getName(), + StatusEnum.DISBURSE.getValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); + }); + } + + private static @NotNull BigDecimal collectTotalCollateral(Set loanCollateralManagements) { + BigDecimal totalCollateral = BigDecimal.ZERO; + + for (LoanCollateralManagement loanCollateralManagement : loanCollateralManagements) { + BigDecimal quantity = loanCollateralManagement.getQuantity(); + BigDecimal pctToBase = loanCollateralManagement.getClientCollateralManagement().getCollaterals().getPctToBase(); + BigDecimal basePrice = loanCollateralManagement.getClientCollateralManagement().getCollaterals().getBasePrice(); + totalCollateral = totalCollateral.add(quantity.multiply(basePrice).multiply(pctToBase).divide(BigDecimal.valueOf(100))); + } + return totalCollateral; + } + + private static @NotNull Set getDisbursementParameters(boolean isAccountTransfer) { + Set disbursementParameters; if (isAccountTransfer) { disbursementParameters = new HashSet<>(Arrays.asList("actualDisbursementDate", "externalId", "note", "locale", "dateFormat", @@ -109,38 +213,7 @@ public void validateDisbursement(final String json, boolean isAccountTransfer) { LoanApiConstants.principalDisbursedParameterName, LoanApiConstants.fixedEmiAmountParameterName, LoanApiConstants.postDatedChecks, LoanApiConstants.disbursementNetDisbursalAmountParameterName)); } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.disbursement"); - - final JsonElement element = this.fromApiJsonHelper.parse(json); - final LocalDate actualDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("actualDisbursementDate", element); - baseDataValidator.reset().parameter("actualDisbursementDate").value(actualDisbursementDate).notNull(); - - final String note = this.fromApiJsonHelper.extractStringNamed("note", element); - baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000); - - final BigDecimal principal = this.fromApiJsonHelper - .extractBigDecimalWithLocaleNamed(LoanApiConstants.principalDisbursedParameterName, element); - baseDataValidator.reset().parameter(LoanApiConstants.principalDisbursedParameterName).value(principal).ignoreIfNull() - .positiveAmount(); - - final BigDecimal netDisbursalAmount = this.fromApiJsonHelper - .extractBigDecimalWithLocaleNamed(LoanApiConstants.disbursementNetDisbursalAmountParameterName, element); - baseDataValidator.reset().parameter(LoanApiConstants.disbursementNetDisbursalAmountParameterName).value(netDisbursalAmount) - .ignoreIfNull().positiveAmount(); - - final BigDecimal emiAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedEmiAmountParameterName, - element); - baseDataValidator.reset().parameter(LoanApiConstants.fixedEmiAmountParameterName).value(emiAmount).ignoreIfNull().positiveAmount() - .notGreaterThanMax(principal); - - validatePaymentDetails(baseDataValidator, element); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); + return disbursementParameters; } public void validateDisbursementWithPostDatedChecks(final String json, final Long loanId) { 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 aeec4b9a700..c7e64b39b6f 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 @@ -135,7 +135,6 @@ import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement; -import org.apache.fineract.portfolio.collateralmanagement.exception.LoanCollateralAmountNotSufficientException; import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand; import org.apache.fineract.portfolio.collectionsheet.command.SingleDisbursalCommand; @@ -294,28 +293,9 @@ public CommandProcessingResult disburseLoan(Long loanId, JsonCommand command, Bo @Override public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand command, Boolean isAccountTransfer, Boolean isWithoutAutoPayment) { + loanTransactionValidator.validateDisbursement(command, isAccountTransfer, loanId); - final AppUser currentUser = getAppUserIfPresent(); - - this.loanTransactionValidator.validateDisbursement(command.json(), isAccountTransfer); - - if (command.parameterExists("postDatedChecks")) { - // validate with post dated checks for the disbursement - this.loanTransactionValidator.validateDisbursementWithPostDatedChecks(command.json(), loanId); - } - - Loan loan = this.loanAssembler.assembleFrom(loanId); - // Fail fast if client/group is not active or actual loan status disallows disbursal - checkClientOrGroupActive(loan); - - final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); - - if (loan.isChargedOff() && DateUtils.isBefore(actualDisbursementDate, loan.getChargedOffOnDate())) { - throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: " - + loanId - + " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan", - loanId); - } + Loan loan = loanAssembler.assembleFrom(loanId); if (loan.loanProduct().isDisallowExpectedDisbursements()) { List filteredList = loan.getDisbursementDetails().stream() @@ -323,8 +303,7 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand // Check whether a new LoanDisbursementDetails is required if (filteredList.isEmpty()) { // create artificial 'tranche/expected disbursal' as current disburse code expects it for - // multi-disbursal - // products + // multi-disbursal products final LocalDate artificialExpectedDate = loan.getExpectedDisbursedOnLocalDate(); LoanDisbursementDetails disbursementDetail = new LoanDisbursementDetails(artificialExpectedDate, null, loan.getDisbursedAmount(), null, false); @@ -332,49 +311,16 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand loan.getAllDisbursementDetails().add(disbursementDetail); } } - loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED); - - // Get disbursedAmount - final BigDecimal disbursedAmount = loan.getDisbursedAmount(); - final Set loanCollateralManagements = loan.getLoanCollateralManagements(); - - // Get relevant loan collateral modules - if ((loanCollateralManagements != null && !loanCollateralManagements.isEmpty()) && loan.getLoanType().isIndividualAccount()) { - - BigDecimal totalCollateral = BigDecimal.valueOf(0); - - for (LoanCollateralManagement loanCollateralManagement : loanCollateralManagements) { - BigDecimal quantity = loanCollateralManagement.getQuantity(); - BigDecimal pctToBase = loanCollateralManagement.getClientCollateralManagement().getCollaterals().getPctToBase(); - BigDecimal basePrice = loanCollateralManagement.getClientCollateralManagement().getCollaterals().getBasePrice(); - totalCollateral = totalCollateral.add(quantity.multiply(basePrice).multiply(pctToBase).divide(BigDecimal.valueOf(100))); - } - - // Validate the loan collateral value against the disbursedAmount - if (disbursedAmount.compareTo(totalCollateral) > 0) { - throw new LoanCollateralAmountNotSufficientException(disbursedAmount); - } - } - - // validate ActualDisbursement Date Against Expected Disbursement Date - LoanProduct loanProduct = loan.loanProduct(); - if (loanProduct.isSyncExpectedWithDisbursementDate()) { - syncExpectedDateWithActualDisbursementDate(loan, actualDisbursementDate); - } final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling(); final LocalDate rescheduledRepaymentDate = command.localDateValueOfParameterNamed("adjustRepaymentDate"); - - entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), StatusEnum.DISBURSE.getValue(), - EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); - - LocalDate recalculateFrom = null; + final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); if (!loan.isMultiDisburmentLoan()) { loan.setActualDisbursementDate(actualDisbursementDate); } - ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); // 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()) { @@ -387,6 +333,7 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand final List existingTransactionIds = new ArrayList<>(); final List existingReversedTransactionIds = new ArrayList<>(); + final AppUser currentUser = getAppUserIfPresent(); final Map changes = new LinkedHashMap<>(); final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); @@ -400,12 +347,10 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand // Recalculate first repayment date based in actual disbursement date. updateLoanCounters(loan, actualDisbursementDate); Money amountBeforeAdjust = loan.getPrincipal(); - boolean canDisburse = loan.canDisburse(actualDisbursementDate); - ChangedTransactionDetail changedTransactionDetail = null; final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale); - if (canDisburse) { + if (loan.canDisburse(actualDisbursementDate)) { // Get netDisbursalAmount from disbursal screen field. final BigDecimal netDisbursalAmount = command .bigDecimalValueOfParameterNamed(LoanApiConstants.disbursementNetDisbursalAmountParameterName); @@ -441,9 +386,9 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand } amountToDisburse = disburseAmount.minus(loanOutstanding); - disburseLoanToLoan(loan, command, loanOutstanding); } + LoanTransaction disbursementTransaction = null; if (isAccountTransfer) { disburseLoanToSavings(loan, command, amountToDisburse, paymentDetail); @@ -463,12 +408,15 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand */ recalculateSchedule = true; } + regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate, rescheduledRepaymentDate); boolean downPaymentEnabled = loan.repaymentScheduleDetail().isEnableDownPayment(); if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || downPaymentEnabled) { createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO); } + + ChangedTransactionDetail changedTransactionDetail; if (isPaymentTypeApplicableForDisbursementCharge) { changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, paymentDetail); } else { @@ -2083,7 +2031,6 @@ public CommandProcessingResult closeAsRescheduled(final Long loanId, final JsonC } private void disburseLoanToLoan(final Loan loan, final JsonCommand command, final BigDecimal amount) { - final LocalDate transactionDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); final ExternalId txnExternalId = externalIdFactory.createFromCommand(command, LoanApiConstants.externalIdParameterName); @@ -2098,7 +2045,6 @@ private void disburseLoanToLoan(final Loan loan, final JsonCommand command, fina } private void disburseLoanToSavings(final Loan loan, final JsonCommand command, final Money amount, final PaymentDetail paymentDetail) { - final LocalDate transactionDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); final ExternalId txnExternalId = externalIdFactory.createFromCommand(command, LoanApiConstants.externalIdParameterName); @@ -2118,7 +2064,6 @@ private void disburseLoanToSavings(final Loan loan, final JsonCommand command, f LoanTransactionType.DISBURSEMENT.getValue(), null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, txnExternalId, loan, null, fromSavingsAccount, isRegularTransaction, isExceptionForBalanceCheck); this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO); - } @Transactional diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java index 9928f492c32..a8e3ffe1cca 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java @@ -130,22 +130,21 @@ public void testLoanRepaymentRescheduleAtDisbursement() { this.loanTransactionHelper.disburseLoanWithRepaymentReschedule(disbursementDate, loanID, adjustRepaymentDate); loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); - ArrayList loanRepaymnetSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, generalResponseSpec, + ArrayList loanRepaymentSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, generalResponseSpec, loanID); - HashMap firstInstallement = loanRepaymnetSchedule.get(1); - Map expectedvalues = new HashMap<>(3); + HashMap firstInstallment = loanRepaymentSchedule.get(1); + Map expectedValues = new HashMap<>(3); Calendar date = Calendar.getInstance(Utils.getTimeZoneOfTenant()); date.set(2015, Calendar.MARCH, 16); - expectedvalues.put("dueDate", getDateAsArray(date, 0)); - expectedvalues.put("principalDue", "834.71"); - expectedvalues.put("interestDue", "49.32"); - expectedvalues.put("feeChargesDue", "0"); - expectedvalues.put("penaltyChargesDue", "0"); - expectedvalues.put("totalDueForPeriod", "884.03"); + expectedValues.put("dueDate", getDateAsArray(date, 0)); + expectedValues.put("principalDue", "834.71"); + expectedValues.put("interestDue", "49.32"); + expectedValues.put("feeChargesDue", "0"); + expectedValues.put("penaltyChargesDue", "0"); + expectedValues.put("totalDueForPeriod", "884.03"); // VALIDATE REPAYMENT SCHEDULE - verifyLoanRepaymentSchedule(firstInstallement, expectedvalues); - + verifyLoanRepaymentSchedule(firstInstallment, expectedValues); } private void addCollaterals(List collaterals, Integer collateralId, BigDecimal quantity) {