FINERACT-1981: Reverse Interest Refund transaction not allowed directly
This commit is contained in:
committed by
Adam Saghy
parent
4956bdd574
commit
1ef9c0f4bb
+8
-3
@@ -1412,19 +1412,24 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
new LoanAdjustTransactionBusinessEvent(new LoanAdjustTransactionBusinessEvent.Data(transactionToAdjust)));
|
||||
if (this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.LOAN)) {
|
||||
throw new PlatformServiceUnavailableException("error.msg.loan.transfer.transaction.update.not.allowed",
|
||||
"Loan transaction:" + transactionId + " update not allowed as it involves in account transfer", transactionId);
|
||||
"Loan transaction: " + transactionId + " update not allowed as it involves in account transfer", transactionId);
|
||||
}
|
||||
if (loan.isClosedWrittenOff()) {
|
||||
throw new PlatformServiceUnavailableException("error.msg.loan.written.off.update.not.allowed",
|
||||
"Loan transaction:" + transactionId + " update not allowed as loan status is written off", transactionId);
|
||||
"Loan transaction: " + transactionId + " update not allowed as loan status is written off", transactionId);
|
||||
}
|
||||
|
||||
if (transactionToAdjust.hasChargebackLoanTransactionRelations()) {
|
||||
throw new PlatformServiceUnavailableException("error.msg.loan.transaction.update.not.allowed",
|
||||
"Loan transaction:" + transactionId + " update not allowed as loan transaction is linked to other transactions",
|
||||
"Loan transaction: " + transactionId + " update not allowed as loan transaction is linked to other transactions",
|
||||
transactionId);
|
||||
}
|
||||
|
||||
if (transactionToAdjust.isInterestRefund()) {
|
||||
throw new PlatformServiceUnavailableException("error.msg.loan.transaction.update.not.allowed",
|
||||
"Interest refund transaction: " + transactionId + " cannot be reversed or adjusted directly", transactionId);
|
||||
}
|
||||
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||
final ExternalId txnExternalId = externalIdFactory.createFromCommand(command, LoanApiConstants.externalIdParameterName);
|
||||
|
||||
+65
@@ -19,6 +19,9 @@
|
||||
package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum.REPLAYED;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
@@ -29,13 +32,17 @@ import java.math.BigDecimal;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
||||
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
||||
import org.apache.fineract.integrationtests.common.BusinessStepHelper;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
@@ -1193,6 +1200,64 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
});
|
||||
}
|
||||
|
||||
// UC19: Interest Refund reverse transaction only when the related transactions, Merchant Issued Refund or Payout
|
||||
// Refund are reversed
|
||||
// 1. Create a Loan Product that supports Interest Refund Types
|
||||
// 2. Submit, Approve and Disburse the loan
|
||||
// 3. Apply a Merchant Issued Refund Transaction
|
||||
// 4. Try to reverse the Interest Refund Transaction expecting to have an Exception
|
||||
// 5. Reverse the Merchant Issued Refund transaction and review the Interest Refund Transction is reversed too
|
||||
@Test
|
||||
public void verifyUC19() {
|
||||
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
runAt("1 January 2021", () -> {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.multiDisburseLoan(true)//
|
||||
.disallowExpectedDisbursements(true)//
|
||||
.maxTrancheCount(2)//
|
||||
.addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
|
||||
.addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
|
||||
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
|
||||
);
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.9,
|
||||
12, null);
|
||||
Assertions.assertNotNull(loanId);
|
||||
loanIdRef.set(loanId);
|
||||
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
|
||||
});
|
||||
runAt("22 January 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
loanTransactionHelper.makeLoanRepayment("MerchantIssuedRefund", "22 January 2021", 1000F, loanId.intValue());
|
||||
logLoanTransactions(loanId);
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
|
||||
Optional<GetLoansLoanIdTransactions> optInterestRefundTransaction = loanDetails.getTransactions().stream()
|
||||
.filter(item -> Objects.equals(item.getType().getValue(), "Interest Refund")).findFirst();
|
||||
final Long interestRefundTransactionId = optInterestRefundTransaction.get().getId();
|
||||
|
||||
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> loanTransactionHelper.reverseLoanTransaction(loanId, interestRefundTransactionId,
|
||||
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN)
|
||||
.transactionDate("22 January 2021").transactionAmount(0.0).locale("en")));
|
||||
assertEquals(503, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.transaction.update.not.allowed"));
|
||||
|
||||
Optional<GetLoansLoanIdTransactions> optMerchantIssuedTransaction = loanDetails.getTransactions().stream()
|
||||
.filter(item -> Objects.equals(item.getType().getValue(), "Merchant Issued Refund")).findFirst();
|
||||
final Long merchantIssuedTransactionId = optMerchantIssuedTransaction.get().getId();
|
||||
|
||||
loanTransactionHelper.reverseLoanTransaction(loanId, merchantIssuedTransactionId,
|
||||
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN).transactionDate("22 January 2021")
|
||||
.transactionAmount(0.0).locale("en"));
|
||||
|
||||
loanDetails = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
|
||||
optInterestRefundTransaction = loanDetails.getTransactions().stream()
|
||||
.filter(item -> Objects.equals(item.getType().getValue(), "Interest Refund")).findFirst();
|
||||
assertEquals(Boolean.TRUE, optInterestRefundTransaction.get().getManuallyReversed());
|
||||
});
|
||||
}
|
||||
|
||||
private void logInstallmentsOfLoanDetails(GetLoansLoanIdResponse loanDetails) {
|
||||
log.info("index, dueDate, principal, fee, penalty, interest");
|
||||
if (loanDetails != null && loanDetails.getRepaymentSchedule() != null && loanDetails.getRepaymentSchedule().getPeriods() != null) {
|
||||
|
||||
Reference in New Issue
Block a user