FINERACT-2081: Fix Accrual Activity Reversal on Installment Due Date.
* Accrual Activity is not recalculated during reopen transaction recalculation * integration tests cover reverse replay verification and extra use cases
This commit is contained in:
+10
-3
@@ -185,7 +185,10 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
* Check if the transaction amounts have changed. If so, reverse the original transaction and update
|
* Check if the transaction amounts have changed. If so, reverse the original transaction and update
|
||||||
* changedTransactionDetail accordingly
|
* changedTransactionDetail accordingly
|
||||||
**/
|
**/
|
||||||
if (LoanTransaction.transactionAmountsMatch(currency, loanTransaction, newLoanTransaction)) {
|
if (newLoanTransaction.isReversed()) {
|
||||||
|
loanTransaction.reverse();
|
||||||
|
changedTransactionDetail.getNewTransactionMappings().put(loanTransaction.getId(), loanTransaction);
|
||||||
|
} else if (LoanTransaction.transactionAmountsMatch(currency, loanTransaction, newLoanTransaction)) {
|
||||||
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(
|
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(
|
||||||
newLoanTransaction.getLoanTransactionToRepaymentScheduleMappings());
|
newLoanTransaction.getLoanTransactionToRepaymentScheduleMappings());
|
||||||
} else {
|
} else {
|
||||||
@@ -225,8 +228,12 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
.filter(installment -> LoanRepaymentScheduleProcessingWrapper.isInPeriod(loanTransaction.getTransactionDate(), installment,
|
.filter(installment -> LoanRepaymentScheduleProcessingWrapper.isInPeriod(loanTransaction.getTransactionDate(), installment,
|
||||||
installment.getInstallmentNumber().equals(firstNormalInstallmentNumber)))
|
installment.getInstallmentNumber().equals(firstNormalInstallmentNumber)))
|
||||||
.findFirst().orElseThrow();
|
.findFirst().orElseThrow();
|
||||||
if (loanTransaction.getDateOf().isEqual(currentInstallment.getDueDate()) || installments.stream()
|
|
||||||
.filter(i -> !i.isAdditional() && !i.isDownPayment()).noneMatch(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)) {
|
if (currentInstallment.isNotFullyPaidOff() && (currentInstallment.getDueDate().isAfter(loanTransaction.getTransactionDate())
|
||||||
|
|| (currentInstallment.getDueDate().isEqual(loanTransaction.getTransactionDate())
|
||||||
|
&& loanTransaction.getTransactionDate().equals(DateUtils.getBusinessLocalDate())))) {
|
||||||
|
loanTransaction.reverse();
|
||||||
|
} else {
|
||||||
loanTransaction.resetDerivedComponents();
|
loanTransaction.resetDerivedComponents();
|
||||||
final Money principalPortion = Money.zero(currency);
|
final Money principalPortion = Money.zero(currency);
|
||||||
Money interestPortion = currentInstallment.getInterestCharged(currency);
|
Money interestPortion = currentInstallment.getInterestCharged(currency);
|
||||||
|
|||||||
+28
@@ -50,6 +50,7 @@ import java.util.Optional;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
@@ -62,6 +63,7 @@ import org.apache.fineract.client.models.BusinessDateRequest;
|
|||||||
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
|
import org.apache.fineract.client.models.GetLoansLoanIdStatus;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
||||||
import org.apache.fineract.client.models.JournalEntryTransactionItem;
|
import org.apache.fineract.client.models.JournalEntryTransactionItem;
|
||||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||||
@@ -238,6 +240,32 @@ public abstract class BaseLoanIntegrationTest {
|
|||||||
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the loan status by applying the given extractor function to the status of the loan details. This method
|
||||||
|
* ensures that the loan details, loan status, and the result of the extractor are not null and asserts that the
|
||||||
|
* result of the extractor function is true.
|
||||||
|
*
|
||||||
|
* @param loanDetails
|
||||||
|
* the loan details object containing the loan status
|
||||||
|
* @param extractor
|
||||||
|
* a function that extracts a boolean value from the loan status for verification
|
||||||
|
* @throws AssertionError
|
||||||
|
* if any of the following conditions are not met:
|
||||||
|
* <ul>
|
||||||
|
* <li>The loan details object is not null</li>
|
||||||
|
* <li>The loan status in the loan details is not null</li>
|
||||||
|
* <li>The value extracted by the extractor function is not null</li>
|
||||||
|
* <li>The value extracted by the extractor function is true</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
protected void verifyLoanStatus(GetLoansLoanIdResponse loanDetails, Function<GetLoansLoanIdStatus, Boolean> extractor) {
|
||||||
|
Assertions.assertNotNull(loanDetails);
|
||||||
|
Assertions.assertNotNull(loanDetails.getStatus());
|
||||||
|
Boolean actualValue = extractor.apply(loanDetails.getStatus());
|
||||||
|
Assertions.assertNotNull(actualValue);
|
||||||
|
Assertions.assertTrue(actualValue);
|
||||||
|
}
|
||||||
|
|
||||||
private String getNonByPassUserAuthKey(RequestSpecification requestSpec, ResponseSpecification responseSpec) {
|
private String getNonByPassUserAuthKey(RequestSpecification requestSpec, ResponseSpecification responseSpec) {
|
||||||
// creates the user
|
// creates the user
|
||||||
UserHelper.getSimpleUserWithoutBypassPermission(requestSpec, responseSpec);
|
UserHelper.getSimpleUserWithoutBypassPermission(requestSpec, responseSpec);
|
||||||
|
|||||||
+78
@@ -42,6 +42,8 @@ import lombok.NoArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
|
import org.apache.fineract.client.models.GetLoansLoanIdStatus;
|
||||||
import org.apache.fineract.client.models.GlobalConfigurationPropertyData;
|
import org.apache.fineract.client.models.GlobalConfigurationPropertyData;
|
||||||
import org.apache.fineract.client.models.PostClientsResponse;
|
import org.apache.fineract.client.models.PostClientsResponse;
|
||||||
import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
|
import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
|
||||||
@@ -53,6 +55,7 @@ import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse;
|
|||||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||||
import org.apache.fineract.client.models.PostLoansRequest;
|
import org.apache.fineract.client.models.PostLoansRequest;
|
||||||
|
import org.apache.fineract.client.models.PostLoansResponse;
|
||||||
import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest;
|
import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest;
|
||||||
import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants;
|
import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants;
|
||||||
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventDTO;
|
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventDTO;
|
||||||
@@ -715,6 +718,81 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using Interest bearing Progressive Loan, Accrual Activity Posting, InterestRecalculation, 25% yearly interest 6
|
||||||
|
* repayment 450 USD principal.
|
||||||
|
* <li>apply, approve and disburse backdated on 17 August 2024</li>
|
||||||
|
* <li>repay 600 on 17 January 2025</li>
|
||||||
|
* <li>verify Accrual and Accrual Activity transaction creation</li>
|
||||||
|
* <li>verify that the loan become overpaid</li>
|
||||||
|
* <li>reverse repayment on same day</li>
|
||||||
|
* <li>verify there is no reverse replayed transaction during reversing the repayment</li>
|
||||||
|
* <li>verify transaction reversals</li>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInterestBearingProgressiveInterestRecalculationReopenDueReverseRepayment() {
|
||||||
|
runAt("17 January 2025", () -> {
|
||||||
|
externalEventHelper.enableBusinessEvent("LoanAdjustTransactionBusinessEvent");
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive() //
|
||||||
|
.description("Interest bearing Progressive Loan USD, Accrual Activity Posting, NO InterestRecalculation") //
|
||||||
|
.enableAccrualActivityPosting(true) //
|
||||||
|
.daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||||
|
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||||
|
.isInterestRecalculationEnabled(false));//
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applyLP2ProgressiveLoanRequest(client.getClientId(),
|
||||||
|
loanProductsResponse.getResourceId(), "17 August 2024", 450.0, 25.0, 6, null));
|
||||||
|
Long loanId = postLoansResponse.getLoanId();
|
||||||
|
Assertions.assertNotNull(loanId);
|
||||||
|
loanTransactionHelper.approveLoan(loanId, approveLoanRequest(450.0, "17 August 2024"));
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(450.0), "17 August 2024");
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024") //
|
||||||
|
);
|
||||||
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("17 January 2025", 600.0f, loanId.intValue()).getResourceId();
|
||||||
|
Assertions.assertNotNull(repaymentId);
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getOverpaid);
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(600.0, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(33.52, "Accrual", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(4.99, "Accrual Activity", "17 January 2025")); //
|
||||||
|
deleteAllExternalEvents();
|
||||||
|
loanTransactionHelper.reverseRepayment(loanId.intValue(), repaymentId.intValue(), "17 January 2025");
|
||||||
|
|
||||||
|
List<ExternalEventDTO> allExternalEvents = ExternalEventHelper.getAllExternalEvents(requestSpec, responseSpec);
|
||||||
|
// Verify that there were no reverse-replay event
|
||||||
|
List<ExternalEventDTO> list = allExternalEvents.stream() //
|
||||||
|
.filter(x -> "LoanAdjustTransactionBusinessEvent".equals(x.getType()) //
|
||||||
|
&& x.getPayLoad().get("newTransactionDetail") != null //
|
||||||
|
&& x.getPayLoad().get("transactionToAdjust") != null) //
|
||||||
|
.toList(); //
|
||||||
|
Assertions.assertEquals(0, list.size());
|
||||||
|
|
||||||
|
// verify that there were 2 transaction reversal event
|
||||||
|
list = allExternalEvents.stream() //
|
||||||
|
.filter(x -> "LoanAdjustTransactionBusinessEvent".equals(x.getType()) //
|
||||||
|
&& x.getPayLoad().get("newTransactionDetail") == null //
|
||||||
|
&& x.getPayLoad().get("transactionToAdjust") != null) //
|
||||||
|
.toList(); //
|
||||||
|
Assertions.assertEquals(2, list.size());
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getActive);
|
||||||
|
verifyTransactions(loanId, transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(33.52, "Accrual", "17 January 2025"), //
|
||||||
|
reversedTransaction(600.0, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024")); //
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void verifyInterestRefundPostBusinessEventCreatedForMerchantIssuedRefundWithInterestRefund() {
|
public void verifyInterestRefundPostBusinessEventCreatedForMerchantIssuedRefundWithInterestRefund() {
|
||||||
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||||
|
|||||||
+323
-20
@@ -43,6 +43,7 @@ import org.apache.fineract.client.models.ChargeToGLAccountMapper;
|
|||||||
import org.apache.fineract.client.models.GetLoanFeeToIncomeAccountMappings;
|
import org.apache.fineract.client.models.GetLoanFeeToIncomeAccountMappings;
|
||||||
import org.apache.fineract.client.models.GetLoanPaymentChannelToFundSourceMappings;
|
import org.apache.fineract.client.models.GetLoanPaymentChannelToFundSourceMappings;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
|
import org.apache.fineract.client.models.GetLoansLoanIdStatus;
|
||||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||||
import org.apache.fineract.client.models.PostChargesRequest;
|
import org.apache.fineract.client.models.PostChargesRequest;
|
||||||
import org.apache.fineract.client.models.PostChargesResponse;
|
import org.apache.fineract.client.models.PostChargesResponse;
|
||||||
@@ -108,6 +109,323 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
|||||||
"EXTERNAL_ASSET_OWNER_TRANSFER", "ACCRUAL_ACTIVITY_POSTING");
|
"EXTERNAL_ASSET_OWNER_TRANSFER", "ACCRUAL_ACTIVITY_POSTING");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using Interest bearing Progressive Loan, Accrual Activity Posting, NO InterestRecalculation, 25% yearly interest
|
||||||
|
* 6 repayment 450 USD principal.
|
||||||
|
* <li>apply, approve and disburse backdated on 17 August 2024</li>
|
||||||
|
* <li>repay 600 on 17 January 2025</li>
|
||||||
|
* <li>verify Accrual and Accrual Activity transaction creation</li>
|
||||||
|
* <li>verify that the loan become overpaid</li>
|
||||||
|
* <li>reverse repayment on same day</li>
|
||||||
|
* <li>verify transaction reversals</li>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInterestBearingProgressiveNoInterestRecalculationReopenDueReverseRepayment1() {
|
||||||
|
runAt("17 January 2025", () -> {
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive() //
|
||||||
|
.description("Interest bearing Progressive Loan USD, Accrual Activity Posting, NO InterestRecalculation") //
|
||||||
|
.enableAccrualActivityPosting(true) //
|
||||||
|
.daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||||
|
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||||
|
.isInterestRecalculationEnabled(false));//
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applyLP2ProgressiveLoanRequest(client.getClientId(),
|
||||||
|
loanProductsResponse.getResourceId(), "17 August 2024", 450.0, 25.0, 6, null));
|
||||||
|
Long loanId = postLoansResponse.getLoanId();
|
||||||
|
Assertions.assertNotNull(loanId);
|
||||||
|
loanTransactionHelper.approveLoan(loanId, approveLoanRequest(450.0, "17 August 2024"));
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(450.0), "17 August 2024");
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024") //
|
||||||
|
);
|
||||||
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("17 January 2025", 600.0f, loanId.intValue()).getResourceId();
|
||||||
|
Assertions.assertNotNull(repaymentId);
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getOverpaid);
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(600.0, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(33.52, "Accrual", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(4.99, "Accrual Activity", "17 January 2025")); //
|
||||||
|
loanTransactionHelper.reverseRepayment(loanId.intValue(), repaymentId.intValue(), "17 January 2025");
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getActive);
|
||||||
|
verifyTransactions(loanId, transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(33.52, "Accrual", "17 January 2025"), //
|
||||||
|
reversedTransaction(600.0, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024")); //
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using Interest bearing Progressive Loan, Accrual Activity Posting, InterestRecalculation, 25% yearly interest 6
|
||||||
|
* repayment 450 USD principal.
|
||||||
|
* <li>apply, approve and disburse backdated on 17 August 2024</li>
|
||||||
|
* <li>repay 600 on 17 January 2025</li>
|
||||||
|
* <li>verify Accrual and Accrual Activity transaction creation</li>
|
||||||
|
* <li>verify that the loan become overpaid</li>
|
||||||
|
* <li>reverse repayment on same day</li>
|
||||||
|
* <li>verify transaction reversals</li>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInterestBearingProgressiveInterestRecalculationReopenDueReverseRepayment() {
|
||||||
|
runAt("17 January 2025", () -> {
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive() //
|
||||||
|
.description("Interest bearing Progressive Loan USD, Accrual Activity Posting, NO InterestRecalculation") //
|
||||||
|
.enableAccrualActivityPosting(true) //
|
||||||
|
.daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||||
|
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||||
|
.isInterestRecalculationEnabled(false));//
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applyLP2ProgressiveLoanRequest(client.getClientId(),
|
||||||
|
loanProductsResponse.getResourceId(), "17 August 2024", 450.0, 25.0, 6, null));
|
||||||
|
Long loanId = postLoansResponse.getLoanId();
|
||||||
|
Assertions.assertNotNull(loanId);
|
||||||
|
loanTransactionHelper.approveLoan(loanId, approveLoanRequest(450.0, "17 August 2024"));
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(450.0), "17 August 2024");
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024") //
|
||||||
|
);
|
||||||
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("17 January 2025", 600.0f, loanId.intValue()).getResourceId();
|
||||||
|
Assertions.assertNotNull(repaymentId);
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getOverpaid);
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(600.0, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(33.52, "Accrual", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(4.99, "Accrual Activity", "17 January 2025")); //
|
||||||
|
loanTransactionHelper.reverseRepayment(loanId.intValue(), repaymentId.intValue(), "17 January 2025");
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getActive);
|
||||||
|
verifyTransactions(loanId, transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(33.52, "Accrual", "17 January 2025"), //
|
||||||
|
reversedTransaction(600.0, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024")); //
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using Interest bearing Progressive Loan, Accrual Activity Posting, NO InterestRecalculation, 25% yearly interest
|
||||||
|
* 6 repayment 450 USD principal.
|
||||||
|
* <li>apply, approve and disburse backdated on 17 August 2024</li>
|
||||||
|
* <li>repay 600 on 17 January 2025</li>
|
||||||
|
* <li>verify Accrual and Accrual Activity transaction creation</li>
|
||||||
|
* <li>verify that the loan become overpaid</li>
|
||||||
|
* <li>reverse repayment on same day</li>
|
||||||
|
* <li>verify transaction reversals</li>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInterestBearingProgressiveNoInterestRecalculationReopenDueReverseRepayment1b() {
|
||||||
|
runAt("18 January 2025", () -> {
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive() //
|
||||||
|
.description("Interest bearing Progressive Loan USD, Accrual Activity Posting, NO InterestRecalculation") //
|
||||||
|
.enableAccrualActivityPosting(true) //
|
||||||
|
.daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||||
|
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||||
|
.isInterestRecalculationEnabled(false));//
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applyLP2ProgressiveLoanRequest(client.getClientId(),
|
||||||
|
loanProductsResponse.getResourceId(), "17 August 2024", 450.0, 25.0, 6, null));
|
||||||
|
Long loanId = postLoansResponse.getLoanId();
|
||||||
|
Assertions.assertNotNull(loanId);
|
||||||
|
loanTransactionHelper.approveLoan(loanId, approveLoanRequest(450.0, "17 August 2024"));
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(450.0), "17 August 2024");
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024") //
|
||||||
|
);
|
||||||
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("17 January 2025", 600.0f, loanId.intValue()).getResourceId();
|
||||||
|
Assertions.assertNotNull(repaymentId);
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getOverpaid);
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(600.0, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(33.52, "Accrual", "18 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(4.99, "Accrual Activity", "17 January 2025")); //
|
||||||
|
loanTransactionHelper.reverseRepayment(loanId.intValue(), repaymentId.intValue(), "17 January 2025");
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getActive);
|
||||||
|
verifyTransactions(loanId, transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(33.52, "Accrual", "18 January 2025"), //
|
||||||
|
reversedTransaction(600.0, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(3.31, "Accrual Activity", "17 January 2025")); //
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAccrualActivityPostingAndReversalsInterestBearingProgressiveInterestRecalculationMerchantIssuedRefund() {
|
||||||
|
runAt("17 January 2025", () -> {
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive() //
|
||||||
|
.description("Interest bearing Progressive Loan USD, Accrual Activity Posting, InterestRecalculation") //
|
||||||
|
.enableAccrualActivityPosting(true) //
|
||||||
|
.currencyCode("USD") //
|
||||||
|
.daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||||
|
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||||
|
.isInterestRecalculationEnabled(true));//
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applyLP2ProgressiveLoanRequest(client.getClientId(),
|
||||||
|
loanProductsResponse.getResourceId(), "17 August 2024", 450.0, 25.0, 6, null));
|
||||||
|
Long loanId = postLoansResponse.getLoanId();
|
||||||
|
Assertions.assertNotNull(loanId);
|
||||||
|
loanTransactionHelper.approveLoan(loanId, approveLoanRequest(450.0, "17 August 2024"));
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(450.0), "17 August 2024");
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024") //
|
||||||
|
);
|
||||||
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("17 January 2025", 497.04f, loanId.intValue()).getResourceId();
|
||||||
|
Assertions.assertNotNull(repaymentId);
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getClosedObligationsMet);
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(497.04, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(47.04, "Accrual", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(9.22, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(9.22, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(9.54, "Accrual Activity", "17 January 2025")); //
|
||||||
|
loanTransactionHelper.makeLoanRepayment("MerchantIssuedRefund", "17 August 2024", 450.0f, loanId.intValue()).getResourceId();
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getOverpaid);
|
||||||
|
verifyTransactions(loanId, transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(450.0, "Merchant Issued Refund", "17 August 2024"), //
|
||||||
|
transaction(497.04, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(47.04, "Accrual", "17 January 2025"), //
|
||||||
|
transaction(47.04, "Accrual Adjustment", "17 January 2025")); //
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using Interest bearing Progressive Loan, Accrual Activity Posting, NO InterestRecalculation, 25% yearly interest
|
||||||
|
* 6 repayment 450 USD principal.
|
||||||
|
* <li>apply, approve and disburse backdated on 17 August 2024</li>
|
||||||
|
* <li>repay 600 on 17 January 2025</li>
|
||||||
|
* <li>verify Accrual and Accrual Activity transaction creation</li>
|
||||||
|
* <li>verify that the loan become overpaid</li>
|
||||||
|
* <li>reverse repayment on same day verify transaction reversals</li>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInterestBearingProgressiveNoInterestRecalculationReopenDueReverseRepayment2b() {
|
||||||
|
runAt("17 January 2025", () -> {
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive() //
|
||||||
|
.description("Interest bearing Progressive Loan USD, Accrual Activity Posting, NO InterestRecalculation") //
|
||||||
|
.enableAccrualActivityPosting(true) //
|
||||||
|
.currencyCode("USD") //
|
||||||
|
.daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||||
|
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||||
|
.isInterestRecalculationEnabled(false));//
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applyLP2ProgressiveLoanRequest(client.getClientId(),
|
||||||
|
loanProductsResponse.getResourceId(), "17 August 2024", 450.0, 25.0, 6, null));
|
||||||
|
Long loanId = postLoansResponse.getLoanId();
|
||||||
|
Assertions.assertNotNull(loanId);
|
||||||
|
loanTransactionHelper.approveLoan(loanId, approveLoanRequest(450.0, "17 August 2024"));
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(450.0), "17 August 2024");
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024") //
|
||||||
|
);
|
||||||
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("17 January 2025", 483.52f, loanId.intValue()).getResourceId();
|
||||||
|
Assertions.assertNotNull(repaymentId);
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getClosedObligationsMet);
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(483.52, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(33.52, "Accrual", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(4.99, "Accrual Activity", "17 January 2025")); //
|
||||||
|
addCharge(loanId, false, 15.0, "15 January 2025");
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getActive);
|
||||||
|
verifyTransactions(loanId, transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(33.52, "Accrual", "17 January 2025"), //
|
||||||
|
transaction(483.52, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024")); //
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using Interest bearing Progressive Loan, Accrual Activity Posting, NO InterestRecalculation, 25% yearly interest
|
||||||
|
* 6 repayment 450 USD principal.
|
||||||
|
* <li>apply, approve and disburse backdated on 17 August 2024</li>
|
||||||
|
* <li>repay 600 on 17 January 2025</li>
|
||||||
|
* <li>verify Accrual and Accrual Activity transaction creation</li>
|
||||||
|
* <li>verify that the loan become overpaid</li>
|
||||||
|
* <li>reverse repayment on same day verify transaction reversals</li>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInterestBearingProgressiveNoInterestRecalculationReopenDueReverseRepayment2c() {
|
||||||
|
runAt("18 January 2025", () -> {
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive() //
|
||||||
|
.description("Interest bearing Progressive Loan USD, Accrual Activity Posting, NO InterestRecalculation") //
|
||||||
|
.enableAccrualActivityPosting(true) //
|
||||||
|
.currencyCode("USD") //
|
||||||
|
.daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||||
|
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||||
|
.isInterestRecalculationEnabled(false));//
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applyLP2ProgressiveLoanRequest(client.getClientId(),
|
||||||
|
loanProductsResponse.getResourceId(), "17 August 2024", 450.0, 25.0, 6, null));
|
||||||
|
Long loanId = postLoansResponse.getLoanId();
|
||||||
|
Assertions.assertNotNull(loanId);
|
||||||
|
loanTransactionHelper.approveLoan(loanId, approveLoanRequest(450.0, "17 August 2024"));
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(450.0), "17 August 2024");
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024") //
|
||||||
|
);
|
||||||
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("17 January 2025", 483.52f, loanId.intValue()).getResourceId();
|
||||||
|
Assertions.assertNotNull(repaymentId);
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getClosedObligationsMet);
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(483.52, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(33.52, "Accrual", "18 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(4.99, "Accrual Activity", "17 January 2025")); //
|
||||||
|
addCharge(loanId, false, 15.0, "15 January 2025");
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getActive);
|
||||||
|
verifyTransactions(loanId, transaction(450.0, "Disbursement", "17 August 2024"), //
|
||||||
|
transaction(33.52, "Accrual", "18 January 2025"), //
|
||||||
|
transaction(483.52, "Repayment", "17 January 2025"), //
|
||||||
|
transaction(9.53, "Accrual Activity", "17 September 2024"), //
|
||||||
|
transaction(7.77, "Accrual Activity", "17 October 2024"), //
|
||||||
|
transaction(6.48, "Accrual Activity", "17 November 2024"), //
|
||||||
|
transaction(4.75, "Accrual Activity", "17 December 2024"), //
|
||||||
|
transaction(18.31, "Accrual Activity", "17 January 2025")); //
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Create Loan with Interest and enabled Accrual Activity Posting
|
// Create Loan with Interest and enabled Accrual Activity Posting
|
||||||
// Approve and disburse loan
|
// Approve and disburse loan
|
||||||
// charge penalty with due date as 1st installment
|
// charge penalty with due date as 1st installment
|
||||||
@@ -955,10 +1273,7 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
|||||||
Long repaymentId = loanTransactionHelper.makeLoanRepayment("02 January 2024", 370.0f, loanId.intValue()).getResourceId();
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("02 January 2024", 370.0f, loanId.intValue()).getResourceId();
|
||||||
Assertions.assertNotNull(repaymentId);
|
Assertions.assertNotNull(repaymentId);
|
||||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
Assertions.assertNotNull(loanDetails);
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getOverpaid);
|
||||||
Assertions.assertNotNull(loanDetails.getStatus());
|
|
||||||
Assertions.assertNotNull(loanDetails.getStatus().getOverpaid());
|
|
||||||
Assertions.assertTrue(loanDetails.getStatus().getOverpaid());
|
|
||||||
|
|
||||||
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
||||||
transaction(100.0, "Down Payment", "01 January 2024"), transaction(8.76, "Accrual", "02 January 2024"),
|
transaction(100.0, "Down Payment", "01 January 2024"), transaction(8.76, "Accrual", "02 January 2024"),
|
||||||
@@ -991,10 +1306,7 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
|||||||
Long repaymentId = loanTransactionHelper.makeLoanRepayment("01 January 2024", 370.0f, loanId.intValue()).getResourceId();
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("01 January 2024", 370.0f, loanId.intValue()).getResourceId();
|
||||||
Assertions.assertNotNull(repaymentId);
|
Assertions.assertNotNull(repaymentId);
|
||||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
Assertions.assertNotNull(loanDetails);
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getOverpaid);
|
||||||
Assertions.assertNotNull(loanDetails.getStatus());
|
|
||||||
Assertions.assertNotNull(loanDetails.getStatus().getOverpaid());
|
|
||||||
Assertions.assertTrue(loanDetails.getStatus().getOverpaid());
|
|
||||||
|
|
||||||
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
||||||
transaction(100.0, "Down Payment", "01 January 2024"), transaction(8.76, "Accrual", "01 January 2024"),
|
transaction(100.0, "Down Payment", "01 January 2024"), transaction(8.76, "Accrual", "01 January 2024"),
|
||||||
@@ -1002,10 +1314,7 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
|||||||
|
|
||||||
loanTransactionHelper.reverseRepayment(loanId.intValue(), repaymentId.intValue(), "01 January 2024");
|
loanTransactionHelper.reverseRepayment(loanId.intValue(), repaymentId.intValue(), "01 January 2024");
|
||||||
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
Assertions.assertNotNull(loanDetails);
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getActive);
|
||||||
Assertions.assertNotNull(loanDetails.getStatus());
|
|
||||||
Assertions.assertNotNull(loanDetails.getStatus().getActive());
|
|
||||||
Assertions.assertTrue(loanDetails.getStatus().getActive());
|
|
||||||
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
||||||
transaction(100.0, "Down Payment", "01 January 2024"), transaction(8.76, "Accrual", "01 January 2024"),
|
transaction(100.0, "Down Payment", "01 January 2024"), transaction(8.76, "Accrual", "01 January 2024"),
|
||||||
reversedTransaction(370.0, "Repayment", "01 January 2024"));
|
reversedTransaction(370.0, "Repayment", "01 January 2024"));
|
||||||
@@ -1038,20 +1347,14 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
|||||||
Long repaymentId = loanTransactionHelper.makeLoanRepayment("01 January 2024", 370.0f, loanId.intValue()).getResourceId();
|
Long repaymentId = loanTransactionHelper.makeLoanRepayment("01 January 2024", 370.0f, loanId.intValue()).getResourceId();
|
||||||
Assertions.assertNotNull(repaymentId);
|
Assertions.assertNotNull(repaymentId);
|
||||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
Assertions.assertNotNull(loanDetails);
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getOverpaid);
|
||||||
Assertions.assertNotNull(loanDetails.getStatus());
|
|
||||||
Assertions.assertNotNull(loanDetails.getStatus().getOverpaid());
|
|
||||||
Assertions.assertTrue(loanDetails.getStatus().getOverpaid());
|
|
||||||
|
|
||||||
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
||||||
transaction(100.0, "Down Payment", "01 January 2024"), transaction(38.76, "Accrual", "01 January 2024"),
|
transaction(100.0, "Down Payment", "01 January 2024"), transaction(38.76, "Accrual", "01 January 2024"),
|
||||||
transaction(38.76, "Accrual Activity", "01 January 2024"), transaction(370.0, "Repayment", "01 January 2024"));
|
transaction(38.76, "Accrual Activity", "01 January 2024"), transaction(370.0, "Repayment", "01 January 2024"));
|
||||||
loanTransactionHelper.reverseRepayment(loanId.intValue(), repaymentId.intValue(), "01 January 2024");
|
loanTransactionHelper.reverseRepayment(loanId.intValue(), repaymentId.intValue(), "01 January 2024");
|
||||||
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
Assertions.assertNotNull(loanDetails);
|
verifyLoanStatus(loanDetails, GetLoansLoanIdStatus::getActive);
|
||||||
Assertions.assertNotNull(loanDetails.getStatus());
|
|
||||||
Assertions.assertNotNull(loanDetails.getStatus().getActive());
|
|
||||||
Assertions.assertTrue(loanDetails.getStatus().getActive());
|
|
||||||
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
verifyTransactions(loanId, transaction(400.0, "Disbursement", "01 January 2024"),
|
||||||
transaction(100.0, "Down Payment", "01 January 2024"), transaction(38.76, "Accrual", "01 January 2024"),
|
transaction(100.0, "Down Payment", "01 January 2024"), transaction(38.76, "Accrual", "01 January 2024"),
|
||||||
reversedTransaction(370.0, "Repayment", "01 January 2024"));
|
reversedTransaction(370.0, "Repayment", "01 January 2024"));
|
||||||
|
|||||||
+11
-2
@@ -100,6 +100,7 @@ import org.apache.poi.ss.usermodel.Workbook;
|
|||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
public class LoanTransactionHelper extends IntegrationTest {
|
public class LoanTransactionHelper extends IntegrationTest {
|
||||||
|
|
||||||
|
public static final String DATE_FORMAT = "d MMMM yyyy";
|
||||||
public static final String DATE_TIME_FORMAT = "dd MMMM yyyy HH:mm";
|
public static final String DATE_TIME_FORMAT = "dd MMMM yyyy HH:mm";
|
||||||
private static final String LOAN_PRODUCTS_URL = "/fineract-provider/api/v1/loanproducts";
|
private static final String LOAN_PRODUCTS_URL = "/fineract-provider/api/v1/loanproducts";
|
||||||
private static final String CREATE_LOAN_PRODUCT_URL = "/fineract-provider/api/v1/loanproducts?" + Utils.TENANT_IDENTIFIER;
|
private static final String CREATE_LOAN_PRODUCT_URL = "/fineract-provider/api/v1/loanproducts?" + Utils.TENANT_IDENTIFIER;
|
||||||
@@ -871,9 +872,10 @@ public class LoanTransactionHelper extends IntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public PostLoansLoanIdTransactionsResponse makeLoanRepayment(final Long loanId, final String command, final String date,
|
public PostLoansLoanIdTransactionsResponse makeLoanRepayment(final Long loanId, final String command, final String date,
|
||||||
final Double amountToBePaid) {
|
final Double amount) {
|
||||||
|
log.info("Make {} with amount {} in {} for Loan {}", command, amount, date, loanId);
|
||||||
return ok(fineract().loanTransactions.executeLoanTransaction(loanId, new PostLoansLoanIdTransactionsRequest()
|
return ok(fineract().loanTransactions.executeLoanTransaction(loanId, new PostLoansLoanIdTransactionsRequest()
|
||||||
.transactionAmount(amountToBePaid).transactionDate(date).dateFormat("dd MMMM yyyy").locale("en"), command));
|
.transactionAmount(amount).transactionDate(date).dateFormat("dd MMMM yyyy").locale("en"), command));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Rewrite to use fineract-client instead!
|
// TODO: Rewrite to use fineract-client instead!
|
||||||
@@ -1210,6 +1212,13 @@ public class LoanTransactionHelper extends IntegrationTest {
|
|||||||
return ok(fineract().loanTransactions.adjustLoanTransaction(loanId, transactionId, request, "undo"));
|
return ok(fineract().loanTransactions.adjustLoanTransaction(loanId, transactionId, request, "undo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PostLoansLoanIdTransactionsResponse reverseLoanTransaction(final Long loanId, final Long transactionId, String date) {
|
||||||
|
return ok(fineract().loanTransactions.adjustLoanTransaction(loanId, transactionId,
|
||||||
|
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATE_FORMAT).transactionDate(date).transactionAmount(0.0)
|
||||||
|
.locale("en"),
|
||||||
|
"undo"));
|
||||||
|
}
|
||||||
|
|
||||||
public HashMap makeRepaymentWithPDC(final String date, final Float amountToBePaid, final Integer loanID, final Long paymentType) {
|
public HashMap makeRepaymentWithPDC(final String date, final Float amountToBePaid, final Integer loanID, final Long paymentType) {
|
||||||
return (HashMap) performLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID),
|
return (HashMap) performLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID),
|
||||||
getRepaymentWithPDCBodyAsJSON(date, amountToBePaid, paymentType), "");
|
getRepaymentWithPDCBodyAsJSON(date, amountToBePaid, paymentType), "");
|
||||||
|
|||||||
Reference in New Issue
Block a user