FINERACT-2354: handle reamortization error code 500 issue on same disbursement day
This commit is contained in:
+39
@@ -105,6 +105,31 @@ public class LoanReAmortizationStepDef extends AbstractStepDef {
|
||||
testContext().set(TestContextKey.LOAN_REAMORTIZATION_UNDO_RESPONSE, response);
|
||||
}
|
||||
|
||||
@When("Admin creates a Loan re-amortization transaction on current business date but fails with {int} error")
|
||||
public void createLoanReAmortizationFailsWithError(int errorCode) {
|
||||
final PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
final Long loanId = loanResponse.getLoanId();
|
||||
|
||||
final PostLoansLoanIdTransactionsRequest reAmortizationRequest = LoanRequestFactory.defaultLoanReAmortizationRequest();
|
||||
|
||||
CallFailedRuntimeException exception = fail(() -> fineractClient.loanTransactions().executeLoanTransaction(loanId,
|
||||
reAmortizationRequest, Map.of("command", "reAmortize")));
|
||||
assertThat(exception.getStatus()).as(ErrorMessageHelper.dateFailureErrorCodeMsg()).isEqualTo(errorCode);
|
||||
}
|
||||
|
||||
@When("Admin creates a Loan re-amortization transaction on current business date with reAmortizationInterestHandling {string} but fails with {int} error")
|
||||
public void createLoanReAmortizationWithInterestHandlingFailsWithError(final String reAmortizationInterestHandling, int errorCode) {
|
||||
final PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
final Long loanId = loanResponse.getLoanId();
|
||||
|
||||
final PostLoansLoanIdTransactionsRequest reAmortizationRequest = LoanRequestFactory.defaultLoanReAmortizationRequest()
|
||||
.reAmortizationInterestHandling(reAmortizationInterestHandling);
|
||||
|
||||
CallFailedRuntimeException exception = fail(() -> fineractClient.loanTransactions().executeLoanTransaction(loanId,
|
||||
reAmortizationRequest, Map.of("command", "reAmortize")));
|
||||
assertThat(exception.getStatus()).as(ErrorMessageHelper.dateFailureErrorCodeMsg()).isEqualTo(errorCode);
|
||||
}
|
||||
|
||||
@When("Admin creates a Loan re-amortization transaction on current business date is forbidden as loan was charged-off")
|
||||
public void reAmortizationChargedOffLoanFailure() {
|
||||
reAmortizationFailure(ErrorMessageHelper.reAmortizeChargedOffLoanFailure());
|
||||
@@ -170,6 +195,20 @@ public class LoanReAmortizationStepDef extends AbstractStepDef {
|
||||
testContext().set(TestContextKey.LOAN_REAMORTIZATION_PREVIEW_RESPONSE, response);
|
||||
}
|
||||
|
||||
@When("Admin creates a Loan re-amortization preview by Loan external ID with the following data, but fails with {int} error code:")
|
||||
public void createReAmortizedPreviewByLoanExternalIdFailsWithErrorCode(int errorCode, final DataTable table) {
|
||||
final PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
final String loanExternalId = loanResponse.getResourceExternalId();
|
||||
|
||||
final List<String> data = table.asLists().get(1);
|
||||
final String reAmortizationInterestHandling = data.getFirst();
|
||||
|
||||
final Map<String, Object> queryParams = Map.of("reAmortizationInterestHandling", reAmortizationInterestHandling);
|
||||
CallFailedRuntimeException exception = fail(
|
||||
() -> fineractClient.loanTransactions().previewReAmortizationSchedule1(loanExternalId, queryParams));
|
||||
assertThat(exception.getStatus()).isEqualTo(errorCode);
|
||||
}
|
||||
|
||||
@Then("Loan Re-Amortization Repayment schedule preview has the following data in Total row:")
|
||||
public void loanRepaymentDScheduleAmountCheck(final DataTable table) {
|
||||
final List<List<String>> data = table.asLists();
|
||||
|
||||
@@ -5101,9 +5101,8 @@ Feature: LoanReAmortization
|
||||
When Loan Pay-off is made on "02 April 2024"
|
||||
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
|
||||
|
||||
@Skip
|
||||
@TestRailId:C4510 @AdvancedPaymentAllocation
|
||||
Scenario: Verify allowing re-amortization on same day as disbursement - interest bearing loan with default interest handling - UC5.1
|
||||
Scenario: Verify re-amortization on same day as disbursement is rejected when no overdue exists - interest bearing loan with default interest handling - UC5.1
|
||||
When Admin sets the business date to "01 January 2024"
|
||||
When Admin creates a client with random data
|
||||
When Admin set "LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
|
||||
@@ -5127,31 +5126,14 @@ Feature: LoanReAmortization
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
|
||||
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false |
|
||||
# --- re-amortization transaction --- 500 error!!
|
||||
And Admin creates a Loan re-amortization transaction on current business date
|
||||
Then Loan Repayment schedule has 6 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
Then Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 |
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false |
|
||||
| 15 March 2024 | Re-amortize | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
# --- re-amortization transaction - fails with 403 because no overdue installments exist on disbursement day ---
|
||||
And Admin creates a Loan re-amortization transaction on current business date but fails with 403 error
|
||||
# --- close the loan --- #
|
||||
When Loan Pay-off is made on "01 January 2024"
|
||||
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
|
||||
|
||||
@Skip
|
||||
@TestRailId:C4511 @AdvancedPaymentAllocation
|
||||
Scenario: Verify allowing re-amortization on same day as disbursement - interest bearing loan with equal amortization + interest split - UC5.2
|
||||
Scenario: Verify re-amortization on same day as disbursement is rejected when no overdue exists - interest bearing loan with equal amortization + interest split - UC5.2
|
||||
When Admin sets the business date to "01 January 2024"
|
||||
When Admin creates a client with random data
|
||||
When Admin set "LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
|
||||
@@ -5175,24 +5157,8 @@ Feature: LoanReAmortization
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
|
||||
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false |
|
||||
# --- re-amortization transaction --- 500 error!!
|
||||
And Admin creates a Loan re-amortization transaction on current business date with reAmortizationInterestHandling "EQUAL_AMORTIZATION_INTEREST_SPLIT"
|
||||
Then Loan Repayment schedule has 6 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
Then Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 |
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false |
|
||||
| 15 March 2024 | Re-amortize | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
# --- re-amortization transaction - fails with 403 because no overdue installments exist on disbursement day ---
|
||||
And Admin creates a Loan re-amortization transaction on current business date with reAmortizationInterestHandling "EQUAL_AMORTIZATION_INTEREST_SPLIT" but fails with 403 error
|
||||
# --- close the loan --- #
|
||||
When Loan Pay-off is made on "01 January 2024"
|
||||
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
|
||||
|
||||
+2
-14
@@ -705,21 +705,9 @@ Feature: LoanReAmortizationPreview
|
||||
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false |
|
||||
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false |
|
||||
| 01 March 2024 | Repayment | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 67.05 | false | false |
|
||||
# --- Re-amortization repayment schedule preview ---
|
||||
And Admin creates a Loan re-amortization preview by Loan external ID with the following data:
|
||||
# --- Re-amortization repayment schedule preview - should fail because no overdue principal exists ---
|
||||
And Admin creates a Loan re-amortization preview by Loan external ID with the following data, but fails with 403 error code:
|
||||
| reAmortizationInterestHandling |
|
||||
| DEFAULT |
|
||||
Then Loan Re-Amortization Repayment schedule preview has 6 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2024 | | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 10.0 | 27.01 | 17.01 | 0.0 | 0.0 | 10.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.05 | 0.0 | 10.0 | 112.05 | 34.02 | 0.0 | 0.0 | 78.03 |
|
||||
When Loan Pay-off is made on "15 March 2024"
|
||||
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
|
||||
+9
@@ -131,6 +131,15 @@ public class LoanReAmortizationValidator {
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.loan.reamortize.not.allowed.on.contract.terminated",
|
||||
"Loan re-amortization is not allowed on contract terminated loan.", loan.getId());
|
||||
}
|
||||
|
||||
// validate there are overdue installments to re-amortize
|
||||
boolean hasOverdueInstallments = loan.getRepaymentScheduleInstallments().stream()
|
||||
.anyMatch(installment -> installment.getDueDate().isBefore(getBusinessLocalDate())
|
||||
&& installment.getPrincipalOutstanding(loan.getCurrency()).isGreaterThanZero());
|
||||
if (!hasOverdueInstallments) {
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.loan.reamortize.no.overdue.amount",
|
||||
"Re-amortization cannot be executed: no overdue amount exists.", loan.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public LoanTransaction findAndValidateReAmortizeTransactionForUndo(Loan loan) {
|
||||
|
||||
+38
@@ -42,7 +42,10 @@ import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRu
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
@@ -179,6 +182,19 @@ class LoanReAmortizationValidatorTest {
|
||||
.isEqualTo("error.msg.loan.reamortize.reamortize.transaction.already.present.for.today");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateReAmortize_ShouldThrowException_WhenNoOverdueInstallmentsExist() {
|
||||
// given
|
||||
Loan loan = loan(false);
|
||||
JsonCommand command = jsonCommand();
|
||||
// when
|
||||
GeneralPlatformDomainRuleException result = assertThrows(GeneralPlatformDomainRuleException.class,
|
||||
() -> underTest.validateReAmortize(loan, command));
|
||||
// then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.no.overdue.amount");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUndoReAmortize_ShouldThrowException_WhenLoanDoesntHaveReAmortization() {
|
||||
// given
|
||||
@@ -238,6 +254,10 @@ class LoanReAmortizationValidatorTest {
|
||||
}
|
||||
|
||||
private Loan loan() {
|
||||
return loan(true);
|
||||
}
|
||||
|
||||
private Loan loan(boolean withOverdueInstallments) {
|
||||
Loan loan = mock(Loan.class);
|
||||
given(loan.getStatus()).willReturn(LoanStatus.ACTIVE);
|
||||
given(loan.getMaturityDate()).willReturn(actualDate.plusDays(30));
|
||||
@@ -248,6 +268,24 @@ class LoanReAmortizationValidatorTest {
|
||||
given(loanProductRelatedDetail.getLoanScheduleType()).willReturn(LoanScheduleType.PROGRESSIVE);
|
||||
given(loan.isInterestBearing()).willReturn(false);
|
||||
given(loan.getLoanTransactions()).willReturn(List.of());
|
||||
|
||||
MonetaryCurrency currency = new MonetaryCurrency("USD", 2, null);
|
||||
given(loan.getCurrency()).willReturn(currency);
|
||||
|
||||
Money principalOutstanding = mock(Money.class);
|
||||
given(principalOutstanding.isGreaterThanZero()).willReturn(true);
|
||||
|
||||
if (withOverdueInstallments) {
|
||||
LoanRepaymentScheduleInstallment overdueInstallment = mock(LoanRepaymentScheduleInstallment.class);
|
||||
given(overdueInstallment.getDueDate()).willReturn(actualDate.minusDays(5));
|
||||
given(overdueInstallment.getPrincipalOutstanding(currency)).willReturn(principalOutstanding);
|
||||
given(loan.getRepaymentScheduleInstallments()).willReturn(List.of(overdueInstallment));
|
||||
} else {
|
||||
LoanRepaymentScheduleInstallment futureInstallment = mock(LoanRepaymentScheduleInstallment.class);
|
||||
given(futureInstallment.getDueDate()).willReturn(actualDate.plusDays(10));
|
||||
given(futureInstallment.getPrincipalOutstanding(currency)).willReturn(principalOutstanding);
|
||||
given(loan.getRepaymentScheduleInstallments()).willReturn(List.of(futureInstallment));
|
||||
}
|
||||
return loan;
|
||||
}
|
||||
|
||||
|
||||
+125
@@ -18,7 +18,10 @@
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.loan.reamortization;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -27,6 +30,7 @@ import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
import org.apache.fineract.client.models.PostLoansResponse;
|
||||
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
||||
import org.apache.fineract.integrationtests.BaseLoanIntegrationTest;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
@@ -894,6 +898,127 @@ public class LoanReAmortizationIntegrationTest extends BaseLoanIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reAmortizationOnDisbursementDayInterestBearingLoanTest() {
|
||||
runAt("01 January 2024", () -> {
|
||||
// Create Client
|
||||
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
|
||||
|
||||
int numberOfRepayments = 6;
|
||||
int repaymentEvery = 1;
|
||||
|
||||
// Create Interest-Bearing Loan Product with 7% interest (progressive schedule)
|
||||
Long loanProductId = createInterestBearingProgressiveLoanProduct(numberOfRepayments, repaymentEvery);
|
||||
|
||||
// Apply for loan with 200 amount
|
||||
double applyAmount = 200.0;
|
||||
double approveAmount = 100.0;
|
||||
double disburseAmount = 100.0;
|
||||
|
||||
PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "01 January 2024", applyAmount,
|
||||
numberOfRepayments)//
|
||||
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
|
||||
.repaymentEvery(repaymentEvery)//
|
||||
.loanTermFrequency(numberOfRepayments)//
|
||||
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
|
||||
.loanTermFrequencyType(RepaymentFrequencyType.MONTHS)//
|
||||
.interestRatePerPeriod(BigDecimal.valueOf(7.0))//
|
||||
.interestCalculationPeriodType(InterestCalculationPeriodType.DAILY);
|
||||
|
||||
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||
loanId.set(postLoansResponse.getLoanId());
|
||||
|
||||
// Approve with 100 (partial approval)
|
||||
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(), approveLoanRequest(approveAmount, "01 January 2024"));
|
||||
|
||||
// Disburse 100 on Jan 1, 2024
|
||||
disburseLoan(loanId.get(), BigDecimal.valueOf(disburseAmount), "01 January 2024");
|
||||
|
||||
// Verify disbursement transaction exists
|
||||
verifyTransactions(loanId.get(), //
|
||||
transaction(100.0, "Disbursement", "01 January 2024") //
|
||||
);
|
||||
|
||||
// Re-amortize loan on the same day as disbursement should throw exception
|
||||
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> reAmortizeLoan(loanId.get(), LoanReAmortizationInterestHandlingType.DEFAULT.name()));
|
||||
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.reamortize.no.overdue.amount"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reAmortizationOnDisbursementDayEqualInterestSplitTest() {
|
||||
runAt("01 January 2024", () -> {
|
||||
// Create Client
|
||||
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
|
||||
|
||||
int numberOfRepayments = 6;
|
||||
int repaymentEvery = 1;
|
||||
|
||||
// Create Interest-Bearing Loan Product with 7% interest (progressive schedule)
|
||||
Long loanProductId = createInterestBearingProgressiveLoanProduct(numberOfRepayments, repaymentEvery);
|
||||
|
||||
// Apply for loan with 200 amount
|
||||
double applyAmount = 200.0;
|
||||
double approveAmount = 100.0;
|
||||
double disburseAmount = 100.0;
|
||||
|
||||
PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "01 January 2024", applyAmount,
|
||||
numberOfRepayments)//
|
||||
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
|
||||
.repaymentEvery(repaymentEvery)//
|
||||
.loanTermFrequency(numberOfRepayments)//
|
||||
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
|
||||
.loanTermFrequencyType(RepaymentFrequencyType.MONTHS)//
|
||||
.interestRatePerPeriod(BigDecimal.valueOf(7.0))//
|
||||
.interestCalculationPeriodType(InterestCalculationPeriodType.DAILY);
|
||||
|
||||
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||
loanId.set(postLoansResponse.getLoanId());
|
||||
|
||||
// Approve with 100 (partial approval)
|
||||
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(), approveLoanRequest(approveAmount, "01 January 2024"));
|
||||
|
||||
// Disburse 100 on Jan 1, 2024
|
||||
disburseLoan(loanId.get(), BigDecimal.valueOf(disburseAmount), "01 January 2024");
|
||||
|
||||
// Verify disbursement transaction exists
|
||||
verifyTransactions(loanId.get(), //
|
||||
transaction(100.0, "Disbursement", "01 January 2024") //
|
||||
);
|
||||
|
||||
// Re-amortize loan on the same day as disbursement with EQUAL interest split should throw exception
|
||||
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> reAmortizeLoan(loanId.get(), LoanReAmortizationInterestHandlingType.EQUAL_AMORTIZATION_INTEREST_SPLIT.name()));
|
||||
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.reamortize.no.overdue.amount"));
|
||||
});
|
||||
}
|
||||
|
||||
private Long createInterestBearingProgressiveLoanProduct(int numberOfRepayments, int repaymentEvery) {
|
||||
PostLoanProductsRequest product = create4IProgressive()//
|
||||
.numberOfRepayments(numberOfRepayments)//
|
||||
.repaymentEvery(repaymentEvery)//
|
||||
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS_L)//
|
||||
.interestRatePerPeriod(7.0)// 7% annual interest
|
||||
.multiDisburseLoan(true)//
|
||||
.maxTrancheCount(10)//
|
||||
.outstandingLoanBalance(10000.0)//
|
||||
.disallowExpectedDisbursements(true)//
|
||||
.allowApprovedDisbursedAmountsOverApplied(true)//
|
||||
.overAppliedCalculationType("percentage")//
|
||||
.overAppliedNumber(50);
|
||||
|
||||
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||
GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = loanProductHelper
|
||||
.retrieveLoanProductById(loanProductResponse.getResourceId());
|
||||
assertNotNull(getLoanProductsProductIdResponse);
|
||||
return loanProductResponse.getResourceId();
|
||||
}
|
||||
|
||||
private Long createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(int numberOfInstallments, int repaymentEvery) {
|
||||
return createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(numberOfInstallments, repaymentEvery,
|
||||
DOWN_PAYMENT_PERCENTAGE);
|
||||
|
||||
Reference in New Issue
Block a user