FINERACT-2081: fix disburse error scenario
This commit is contained in:
committed by
Adam Saghy
parent
bd19f28cb6
commit
ec1c55d022
+4
@@ -66,6 +66,10 @@ public final class ErrorMessageHelper {
|
||||
return "Loan disbursal amount can't be greater than maximum applied loan amount calculation. Total disbursed amount: [0-9]* Maximum disbursal amount: [0-9]*";
|
||||
}
|
||||
|
||||
public static String disbursePastDateFailure(Integer loanId, String actualDisbursementDate) {
|
||||
return String.format("The date on which a loan is disbursed cannot be before its approval date: %s", actualDisbursementDate);
|
||||
}
|
||||
|
||||
public static String loanSubmitDateInFutureFailureMsg() {
|
||||
return "The date on which a loan is submitted cannot be in the future.";
|
||||
}
|
||||
|
||||
+17
@@ -1892,6 +1892,23 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
assertThat(fixedLengthactual).as(ErrorMessageHelper.wrongfixedLength(fixedLengthactual, fieldValue)).isEqualTo(fieldValue);
|
||||
}
|
||||
|
||||
@Then("Admin fails to disburse the loan on {string} with {string} EUR transaction amount because disbursement date is earlier than {string}")
|
||||
public void disburseLoanFailureWithPastDate(String actualDisbursementDate, String transactionAmount, String futureApproveDate)
|
||||
throws IOException {
|
||||
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
long loanId = loanResponse.body().getLoanId();
|
||||
PostLoansLoanIdRequest disburseRequest = LoanRequestFactory.defaultLoanDisburseRequest()
|
||||
.actualDisbursementDate(actualDisbursementDate).transactionAmount(new BigDecimal(transactionAmount));
|
||||
|
||||
String futureApproveDateISO = FORMATTER_EVENTS.format(FORMATTER.parse(futureApproveDate));
|
||||
Response<PostLoansLoanIdResponse> loanDisburseResponse = loansApi.stateTransitions(loanId, disburseRequest, "disburse").execute();
|
||||
testContext().set(TestContextKey.LOAN_DISBURSE_RESPONSE, loanDisburseResponse);
|
||||
ErrorResponse errorDetails = ErrorResponse.from(loanDisburseResponse);
|
||||
assertThat(errorDetails.getHttpStatusCode()).as(ErrorMessageHelper.dateFailureErrorCodeMsg()).isEqualTo(403);
|
||||
assertThat(errorDetails.getSingleError().getDeveloperMessage())
|
||||
.isEqualTo(ErrorMessageHelper.disbursePastDateFailure((int) loanId, futureApproveDateISO));
|
||||
}
|
||||
|
||||
private LoanStatusEnumDataV1 getExpectedStatus(String loanStatus) {
|
||||
LoanStatusEnumDataV1 result = new LoanStatusEnumDataV1();
|
||||
switch (loanStatus) {
|
||||
|
||||
@@ -5508,3 +5508,17 @@ Feature: Loan
|
||||
And Admin successfully approves the loan on "01 February 2024" with "1000" amount and expected disbursement date on "01 February 2024"
|
||||
When Admin successfully disburse the loan on "01 February 2024" with "1000" EUR transaction amount
|
||||
Then LoanDetails has fixedLength field with int value: 60
|
||||
|
||||
|
||||
Scenario: Actual disbursement date is in the past with advanced payment allocation product + submitted on date repaymentStartDateType
|
||||
When Admin sets repaymentStartDateType for "LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION" loan product to "SUBMITTED_ON_DATE"
|
||||
When Admin set "LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
|
||||
When Admin sets the business date to "01 January 2023"
|
||||
And Admin creates a client with random data
|
||||
When Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION | 01 January 2023 | 500 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 45 | DAYS | 15 | DAYS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "01 January 2023" with "500" amount and expected disbursement date on "01 January 2023"
|
||||
Then Loan status has changed to "Approved"
|
||||
Then Admin fails to disburse the loan on "31 December 2022" with "500" EUR transaction amount because disbursement date is earlier than "01 January 2023"
|
||||
When Admin sets repaymentStartDateType for "LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION" loan product to "DISBURSEMENT_DATE"
|
||||
|
||||
+2
-16
@@ -1727,19 +1727,13 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
.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 class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
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);
|
||||
}
|
||||
|
||||
+17
@@ -80,6 +80,7 @@ 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.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 final class LoanTransactionValidator {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -349,7 +349,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
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 class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
// 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();
|
||||
|
||||
-2
@@ -765,7 +765,6 @@ public class LoanAccountBackdatedDisbursementTest {
|
||||
@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 class LoanAccountBackdatedDisbursementTest {
|
||||
} finally {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user