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 aff66589ff3..e6c59a5d75f 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 @@ -1727,19 +1727,13 @@ public List getDisbursedLoanDisbursementDetails() { .collect(Collectors.toList()); } - public boolean canDisburse(final LocalDate actualDisbursementDate) { - LocalDate loanSubmittedOnDate = this.submittedOnDate; + public boolean canDisburse() { final LoanStatus statusEnum = this.loanLifecycleStateMachine.dryTransition(LoanEvent.LOAN_DISBURSED, this); boolean isMultiTrancheDisburse = false; LoanStatus actualLoanStatus = LoanStatus.fromInt(this.loanStatus); if ((actualLoanStatus.isActive() || actualLoanStatus.isClosedObligationsMet() || actualLoanStatus.isOverpaid()) && isAllTranchesNotDisbursed()) { - if (DateUtils.isBefore(actualDisbursementDate, loanSubmittedOnDate)) { - final String errorMsg = "Loan can't be disbursed before " + loanSubmittedOnDate; - throw new LoanDisbursalException(errorMsg, "actualdisbursementdate.before.submittedDate", loanSubmittedOnDate, - actualDisbursementDate); - } isMultiTrancheDisburse = true; } return !statusEnum.hasStateOf(actualLoanStatus) || isMultiTrancheDisburse; @@ -2012,18 +2006,10 @@ public void handleDisbursementTransaction(final LocalDate disbursedOn, final Pay updateLoanOutstandingBalances(); } - if (getApprovedOnDate() != null && DateUtils.isBefore(disbursedOn, getApprovedOnDate())) { - final String errorMessage = "The date on which a loan is disbursed cannot be before its approval date: " - + getApprovedOnDate().toString(); - throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.before.approval.date", errorMessage, disbursedOn, - getApprovedOnDate()); - } - LocalDate expectedDate = getExpectedFirstRepaymentOnDate(); if (expectedDate != null && (DateUtils.isAfter(disbursedOn, this.fetchRepaymentScheduleInstallment(1).getDueDate()) || DateUtils.isAfter(disbursedOn, expectedDate)) && DateUtils.isEqual(disbursedOn, this.actualDisbursementDate)) { - final String errorMessage = "submittedOnDate cannot be after the loans expectedFirstRepaymentOnDate: " - + expectedDate.toString(); + final String errorMessage = "submittedOnDate cannot be after the loans expectedFirstRepaymentOnDate: " + expectedDate; throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.after.expected.first.repayment.date", errorMessage, disbursedOn, expectedDate); } 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 feb50685519..de1f979221d 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 @@ -80,6 +80,7 @@ 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.LoanDisbursalException; import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException; import org.apache.fineract.portfolio.loanaccount.exception.LoanRepaymentScheduleNotFoundException; import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService; @@ -213,6 +214,22 @@ public void validateDisbursement(JsonCommand command, boolean isAccountTransfer, loan.getExpectedDisbursedOnLocalDate()); } + if ((loan.getStatus().isActive() || loan.getStatus().isClosedObligationsMet() || loan.getStatus().isOverpaid()) + && loan.isAllTranchesNotDisbursed()) { + LocalDate submittedOnDate = loan.getSubmittedOnDate(); + if (DateUtils.isBefore(actualDisbursementDate, submittedOnDate)) { + final String errorMsg = "Loan can't be disbursed before " + submittedOnDate; + throw new LoanDisbursalException(errorMsg, "actualdisbursementdate.before.submittedDate", submittedOnDate, + actualDisbursementDate); + } + } + + LocalDate approvedOnDate = loan.getApprovedOnDate(); + if (DateUtils.isBefore(actualDisbursementDate, approvedOnDate)) { + final String errorMessage = "The date on which a loan is disbursed cannot be before its approval date: " + approvedOnDate; + throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.before.approval.date", errorMessage, + actualDisbursementDate, approvedOnDate); + } }); } 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 51f1d04f286..823a992010a 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 @@ -349,7 +349,7 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale); - if (loan.canDisburse(actualDisbursementDate)) { + if (loan.canDisburse()) { // Get netDisbursalAmount from disbursal screen field. final BigDecimal netDisbursalAmount = command .bigDecimalValueOfParameterNamed(LoanApiConstants.disbursementNetDisbursalAmountParameterName); @@ -774,7 +774,7 @@ public Map bulkLoanDisbursal(final JsonCommand command, final Co // disbursement and actual disbursement happens on same date loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED); updateLoanCounters(loan, actualDisbursementDate); - boolean canDisburse = loan.canDisburse(actualDisbursementDate); + boolean canDisburse = loan.canDisburse(); ChangedTransactionDetail changedTransactionDetail = null; if (canDisburse) { Money amountBeforeAdjust = loan.getPrincipal(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountBackdatedDisbursementTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountBackdatedDisbursementTest.java index 1c5da42c252..e367b68c121 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountBackdatedDisbursementTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountBackdatedDisbursementTest.java @@ -765,7 +765,6 @@ public void loanAccountBackDatedDisbursementAfterTwoRepaymentsForLoanProductWith @Test public void loanAccountBackDatedDisbursementWithDisbursementDateBeforeLoanSubmittedOnDateValidationTest() { try { - final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(403).build(); final LoanTransactionHelper validationErrorHelper = new LoanTransactionHelper(this.requestSpec, errorResponse); @@ -867,7 +866,6 @@ public void loanAccountBackDatedDisbursementWithDisbursementDateBeforeLoanSubmit } finally { GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); } - } @Test