FINERACT-2107: Interest Refund - Partial Repayment
This commit is contained in:
+5
@@ -165,6 +165,11 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
interestPeriod = repaymentPeriod.getInterestPeriods().stream()
|
||||
.filter(ip -> targetDate.isAfter(ip.getFromDate()) && !targetDate.isAfter(ip.getDueDate())).findFirst().orElseThrow();
|
||||
}
|
||||
scheduleModelCopy.repaymentPeriods().stream()
|
||||
.filter(rp -> targetDate.isAfter(rp.getFromDate()) && !targetDate.isAfter(rp.getDueDate())).findFirst()
|
||||
.ifPresent(rp -> rp.getInterestPeriods().stream()
|
||||
.filter(ip -> targetDate.isAfter(ip.getFromDate()) && !targetDate.isAfter(ip.getDueDate()))
|
||||
.reduce((one, two) -> two).ifPresent(ip -> ip.setDueDate(targetDate)));
|
||||
interestPeriod.setDueDate(adjustedTargetDate);
|
||||
int index = repaymentPeriod.getInterestPeriods().indexOf(interestPeriod);
|
||||
repaymentPeriod.getInterestPeriods().subList(index + 1, repaymentPeriod.getInterestPeriods().size()).clear();
|
||||
|
||||
+32
-37
@@ -18,15 +18,15 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.REPAYMENT;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.LoanTransaction;
|
||||
@@ -54,53 +54,48 @@ public class ProgressiveLoanInterestRefundServiceImpl implements InterestRefundS
|
||||
return loan != null && loan.isInterestBearing() && processor.accept(loan.getTransactionProcessingStrategyCode());
|
||||
}
|
||||
|
||||
private static boolean omitDisbursements(LoanTransaction lt, final AtomicReference<BigDecimal> refundFinal) {
|
||||
private static void simulateRepaymentForDisbursements(LoanTransaction lt, final AtomicReference<BigDecimal> refundFinal,
|
||||
List<LoanTransaction> collect) {
|
||||
collect.add(lt);
|
||||
if (lt.getTypeOf().isDisbursement() && refundFinal.get().compareTo(BigDecimal.ZERO) > 0) {
|
||||
if (lt.getAmount().compareTo(refundFinal.get()) <= 0) {
|
||||
collect.add(
|
||||
new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT.getValue(), lt.getDateOf(), lt.getAmount(),
|
||||
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
|
||||
refundFinal.set(refundFinal.get().subtract(lt.getAmount()));
|
||||
return false;
|
||||
} else {
|
||||
collect.add(
|
||||
new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT.getValue(), lt.getDateOf(), refundFinal.get(),
|
||||
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
|
||||
refundFinal.set(BigDecimal.ZERO);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static LoanTransaction calculateReducedAmountDisbursements(LoanTransaction lt, final AtomicReference<BigDecimal> refundFinal) {
|
||||
if (lt.getTypeOf().isDisbursement() && refundFinal.get().compareTo(BigDecimal.ZERO) > 0) {
|
||||
LoanTransaction result = new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), lt.getTypeOf().getValue(), lt.getDateOf(),
|
||||
lt.getAmount().subtract(refundFinal.get()), lt.getPrincipalPortion(), lt.getInterestPortion(),
|
||||
lt.getFeeChargesPortion(), lt.getPenaltyChargesPortion(),
|
||||
lt.getOverPaymentPortion(lt.getLoan().getCurrency()).getAmount(), lt.isReversed(), lt.getPaymentDetail(),
|
||||
lt.getExternalId());
|
||||
refundFinal.set(BigDecimal.ZERO);
|
||||
return result;
|
||||
}
|
||||
return lt;
|
||||
}
|
||||
|
||||
private BigDecimal totalInterest(final Loan loan, BigDecimal refundAmount, LocalDate relatedRefundTransactionDate) {
|
||||
final AtomicReference<BigDecimal> refundFinal = new AtomicReference<>(refundAmount);
|
||||
List<LoanTransaction> transactionsToReprocess = loan.getLoanTransactions().stream().filter(lt -> !lt.isReversed()) //
|
||||
.filter(lt -> !lt.isAccrual() && !lt.isAccrualActivity()) //
|
||||
.filter(lt -> omitDisbursements(lt, refundFinal)) //
|
||||
.map(lt -> calculateReducedAmountDisbursements(lt, refundFinal)).toList();
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> installmentsToReprocess = new ArrayList<>(
|
||||
loan.getRepaymentScheduleInstallments().stream().filter(i -> !i.isReAged() && !i.isAdditional()).toList());
|
||||
|
||||
ProgressiveLoanInterestScheduleModel modelAfter = processor.reprocessProgressiveLoanTransactions(loan.getDisbursementDate(),
|
||||
transactionsToReprocess, loan.getCurrency(), installmentsToReprocess, loan.getActiveCharges()).getRight();
|
||||
BigDecimal payableInterest = BigDecimal.ZERO;
|
||||
if (modelAfter != null && loan.getStatus().isActive()) {
|
||||
LoanRepaymentScheduleInstallment actualInstallment = loan.getRelatedRepaymentScheduleInstallment(relatedRefundTransactionDate);
|
||||
if (actualInstallment == null) {
|
||||
actualInstallment = loan.getLastLoanRepaymentScheduleInstallment();
|
||||
}
|
||||
payableInterest = emiCalculator.getPayableDetails(modelAfter, actualInstallment.getDueDate(), relatedRefundTransactionDate)
|
||||
.getPayableInterest().getAmount();
|
||||
if (loan.getLoanTransactions().stream().anyMatch(LoanTransaction::isDisbursement)) {
|
||||
List<LoanTransaction> transactionsToReprocess = new ArrayList<>();
|
||||
loan.getLoanTransactions().stream().filter(lt -> !lt.isReversed()) //
|
||||
.filter(lt -> !lt.isAccrual() && !lt.isAccrualActivity()) //
|
||||
.forEach(lt -> simulateRepaymentForDisbursements(lt, refundFinal, transactionsToReprocess)); //
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> installmentsToReprocess = new ArrayList<>(
|
||||
loan.getRepaymentScheduleInstallments().stream().filter(i -> !i.isReAged() && !i.isAdditional()).toList());
|
||||
|
||||
ProgressiveLoanInterestScheduleModel modelAfter = processor.reprocessProgressiveLoanTransactions(loan.getDisbursementDate(),
|
||||
transactionsToReprocess, loan.getCurrency(), installmentsToReprocess, loan.getActiveCharges()).getRight();
|
||||
|
||||
payableInterest = installmentsToReprocess.stream() //
|
||||
.map(installment -> emiCalculator //
|
||||
.getPayableDetails(modelAfter, installment.getDueDate(), relatedRefundTransactionDate) //
|
||||
.getPayableInterest() //
|
||||
.getAmount()) //
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add); //
|
||||
}
|
||||
BigDecimal paidInterest = installmentsToReprocess.stream().map(i -> i.getInterestPaid(loan.getCurrency())).filter(Objects::nonNull)
|
||||
.map(Money::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
return payableInterest.add(paidInterest);
|
||||
return payableInterest;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+6
-1
@@ -295,7 +295,6 @@ public abstract class BaseLoanIntegrationTest {
|
||||
.allowCompoundingOnEod(false)//
|
||||
.canDefineInstallmentAmount(true)//
|
||||
.repaymentStartDateType(1)//
|
||||
.supportedInterestRefundTypes(List.of())//
|
||||
.charges(List.of())//
|
||||
.principalVariationsForBorrowerCycle(List.of())//
|
||||
.interestRateVariationsForBorrowerCycle(List.of())//
|
||||
@@ -1296,4 +1295,10 @@ public abstract class BaseLoanIntegrationTest {
|
||||
|
||||
public static final String LAST_INSTALLMENT = "LAST_INSTALLMENT";
|
||||
}
|
||||
|
||||
public static class SupportedInterestRefundTypesItem {
|
||||
|
||||
public static final String MERCHANT_ISSUED_REFUND = "MERCHANT_ISSUED_REFUND";
|
||||
public static final String PAYOUT_REFUND = "PAYOUT_REFUND";
|
||||
}
|
||||
}
|
||||
|
||||
+269
-36
@@ -26,7 +26,9 @@ import io.restassured.http.ContentType;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
@@ -70,7 +72,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>()) //
|
||||
//
|
||||
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
|
||||
);
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.9,
|
||||
@@ -86,7 +88,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Payout Refund", "22 January 2021"));
|
||||
});
|
||||
@@ -99,7 +101,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>())//
|
||||
//
|
||||
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
|
||||
);
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.9,
|
||||
@@ -115,7 +117,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Merchant Issued Refund", "22 January 2021"));
|
||||
});
|
||||
@@ -128,7 +130,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
|
||||
.addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
|
||||
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
|
||||
);
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
|
||||
@@ -144,7 +146,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, //
|
||||
transaction(1000.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(1000.0, "Payout Refund", "22 January 2021"), //
|
||||
@@ -185,7 +187,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
|
||||
.addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
|
||||
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
|
||||
);
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
|
||||
@@ -201,7 +203,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Merchant Issued Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
|
||||
transaction(5.75, "Interest Refund", "22 January 2021"));
|
||||
@@ -215,8 +217,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
|
||||
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
|
||||
.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.99,
|
||||
@@ -232,7 +234,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Payout Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
|
||||
transaction(5.75, "Interest Refund", "22 January 2021"));
|
||||
@@ -246,8 +248,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
|
||||
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
|
||||
.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.99,
|
||||
@@ -263,7 +265,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Payout Refund", "01 February 2021"), transaction(8.48, "Accrual", "01 February 2021"),
|
||||
transaction(8.48, "Interest Refund", "01 February 2021"));
|
||||
@@ -277,8 +279,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
|
||||
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
|
||||
.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.99,
|
||||
@@ -294,7 +296,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(87.89, "Repayment", "01 February 2021"));
|
||||
});
|
||||
@@ -306,7 +308,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Payout Refund", "09 February 2021"), transaction(87.89, "Repayment", "01 February 2021"),
|
||||
transaction(10.50, "Interest Refund", "09 February 2021"));
|
||||
@@ -320,11 +322,11 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>())//
|
||||
//
|
||||
.disallowExpectedDisbursements(true)//
|
||||
.multiDisburseLoan(true)//
|
||||
.maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
|
||||
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
|
||||
.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.99,
|
||||
@@ -341,7 +343,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(750.0, "Disbursement", "01 January 2021"),
|
||||
transaction(250.0, "Disbursement", "01 January 2021"), transaction(1000.0, "Payout Refund", "22 January 2021"),
|
||||
transaction(5.75, "Accrual", "22 January 2021"), transaction(5.75, "Interest Refund", "22 January 2021"));
|
||||
@@ -355,9 +357,9 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>()).disallowExpectedDisbursements(true).multiDisburseLoan(true)
|
||||
.maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
|
||||
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
|
||||
.disallowExpectedDisbursements(true).multiDisburseLoan(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.99,
|
||||
@@ -377,7 +379,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(750.0, "Disbursement", "04 January 2021"),
|
||||
transaction(250.0, "Disbursement", "01 January 2021"), transaction(1000.0, "Payout Refund", "22 January 2021"),
|
||||
transaction(5.14, "Accrual", "22 January 2021"), transaction(5.14, "Interest Refund", "22 January 2021"));
|
||||
@@ -391,9 +393,10 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.supportedInterestRefundTypes(new ArrayList<>()).disallowExpectedDisbursements(true).multiDisburseLoan(true)
|
||||
.maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
|
||||
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
|
||||
.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.99,
|
||||
@@ -413,7 +416,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(500.0, "Disbursement", "01 January 2021"),
|
||||
transaction(500.0, "Disbursement", "07 January 2021"), transaction(87.82, "Repayment", "01 February 2021"));
|
||||
});
|
||||
@@ -425,18 +428,248 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logTransactions(loanId);
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(500.0, "Disbursement", "01 January 2021"),
|
||||
transaction(500.0, "Disbursement", "07 January 2021"), transaction(1000.0, "Payout Refund", "09 February 2021"),
|
||||
transaction(87.82, "Repayment", "01 February 2021"), transaction(9.67, "Interest Refund", "09 February 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
private void logTransactions(Long loanId) {
|
||||
@Test
|
||||
public void verifyUC06() {
|
||||
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
runAt("1 December 2020", () -> {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.PAYOUT_REFUND) //
|
||||
.addSupportedInterestRefundTypesItem(SupportedInterestRefundTypesItem.MERCHANT_ISSUED_REFUND) //
|
||||
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
|
||||
);
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 December 2020", 1000.0, 9.99,
|
||||
6, null);
|
||||
Assertions.assertNotNull(loanId);
|
||||
loanIdRef.set(loanId);
|
||||
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 December 2020");
|
||||
|
||||
});
|
||||
runAt("14 December 2020", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
|
||||
.makeLoanRepayment("PayoutRefund", "14 December 2020", 500F, loanId.intValue());
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 December 2020"), //
|
||||
transaction(500.0, "Payout Refund", "14 December 2020"), //
|
||||
transaction(1.78, "Interest Refund", "14 December 2020"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyUC07() {
|
||||
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
runAt("1 January 2021", () -> {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.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.99,
|
||||
12, null);
|
||||
Assertions.assertNotNull(loanId);
|
||||
loanIdRef.set(loanId);
|
||||
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||
logInstallmentsOfLoanDetails(loanDetails);
|
||||
});
|
||||
runAt("1 February 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment("Repayment",
|
||||
"1 February 2021", 87.89F, loanId.intValue());
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(87.89, "Repayment", "01 February 2021"));
|
||||
});
|
||||
runAt("9 February 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
|
||||
.makeLoanRepayment("PayoutRefund", "09 February 2021", 500F, loanId.intValue());
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(87.89, "Repayment", "01 February 2021"), //
|
||||
transaction(500.0, "Payout Refund", "09 February 2021"), //
|
||||
transaction(5.35, "Interest Refund", "09 February 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyUC08() {
|
||||
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
runAt("1 January 2021", () -> {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
//
|
||||
.disallowExpectedDisbursements(true)//
|
||||
.multiDisburseLoan(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.99,
|
||||
6, null);
|
||||
Assertions.assertNotNull(loanId);
|
||||
loanIdRef.set(loanId);
|
||||
disburseLoan(loanId, BigDecimal.valueOf(250), "1 January 2021");
|
||||
disburseLoan(loanId, BigDecimal.valueOf(750), "1 January 2021");
|
||||
});
|
||||
runAt("22 January 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
|
||||
.makeLoanRepayment("PayoutRefund", "22 January 2021", 500F, loanId.intValue());
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(750.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(500.0, "Payout Refund", "22 January 2021"), //
|
||||
transaction(2.88, "Interest Refund", "22 January 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyUC09() {
|
||||
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
runAt("1 January 2021", () -> {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.disallowExpectedDisbursements(true).multiDisburseLoan(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.99,
|
||||
6, null);
|
||||
Assertions.assertNotNull(loanId);
|
||||
loanIdRef.set(loanId);
|
||||
disburseLoan(loanId, BigDecimal.valueOf(250), "1 January 2021");
|
||||
});
|
||||
runAt("7 January 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
disburseLoan(loanId, BigDecimal.valueOf(750), "7 January 2021");
|
||||
});
|
||||
runAt("22 January 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
|
||||
.makeLoanRepayment("PayoutRefund", "22 January 2021", 500F, loanId.intValue());
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(750.0, "Disbursement", "07 January 2021"), //
|
||||
transaction(500.0, "Payout Refund", "22 January 2021"), //
|
||||
transaction(2.47, "Interest Refund", "22 January 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyUC10() {
|
||||
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
runAt("1 January 2021", () -> {
|
||||
PostLoanProductsResponse loanProduct = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
|
||||
.daysInYearType(DaysInYearType.ACTUAL) //
|
||||
.disallowExpectedDisbursements(true).multiDisburseLoan(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.99,
|
||||
6, null);
|
||||
Assertions.assertNotNull(loanId);
|
||||
loanIdRef.set(loanId);
|
||||
disburseLoan(loanId, BigDecimal.valueOf(250), "1 January 2021");
|
||||
|
||||
});
|
||||
runAt("7 January 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
disburseLoan(loanId, BigDecimal.valueOf(750), "7 January 2021");
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||
logInstallmentsOfLoanDetails(loanDetails);
|
||||
});
|
||||
runAt("1 July 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 February 2021", 171.29F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 March 2021", 171.29F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 April 2021", 171.29F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 May 2021", 171.29F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 June 2021", 171.29F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 July 2021", 171.32F, loanId.intValue());
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(750.0, "Disbursement", "07 January 2021"), //
|
||||
transaction(171.29, "Repayment", "01 February 2021"), //
|
||||
transaction(171.29, "Repayment", "01 March 2021"), //
|
||||
transaction(171.29, "Repayment", "01 April 2021"), //
|
||||
transaction(171.29, "Repayment", "01 May 2021"), //
|
||||
transaction(171.29, "Repayment", "01 June 2021"), //
|
||||
transaction(171.32, "Repayment", "01 July 2021") //
|
||||
); //
|
||||
});
|
||||
runAt("11 July 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
|
||||
.makeLoanRepayment("PayoutRefund", "11 July 2021", 500.0F, loanId.intValue());
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(750.0, "Disbursement", "07 January 2021"), //
|
||||
transaction(171.29, "Repayment", "01 February 2021"), //
|
||||
transaction(171.29, "Repayment", "01 March 2021"), //
|
||||
transaction(171.29, "Repayment", "01 April 2021"), //
|
||||
transaction(171.29, "Repayment", "01 May 2021"), //
|
||||
transaction(171.29, "Repayment", "01 June 2021"), //
|
||||
transaction(171.32, "Repayment", "01 July 2021"), //
|
||||
transaction(500.0, "Payout Refund", "11 July 2021"), //
|
||||
transaction(20.41, "Interest Refund", "11 July 2021")); //
|
||||
});
|
||||
}
|
||||
|
||||
private void logInstallmentsOfLoanDetails(GetLoansLoanIdResponse loanDetails) {
|
||||
log.info("index, dueDate, principal, fee, penalty, interest");
|
||||
if (loanDetails != null && loanDetails.getRepaymentSchedule() != null && loanDetails.getRepaymentSchedule().getPeriods() != null) {
|
||||
loanDetails.getRepaymentSchedule().getPeriods()
|
||||
.forEach(period -> log.info("{}, \"{}\", {}, {}, {}, {}", period.getPeriod(),
|
||||
DateTimeFormatter.ofPattern(DATETIME_PATTERN, Locale.ENGLISH)
|
||||
.format(Objects.requireNonNull(period.getDueDate())),
|
||||
period.getPrincipalDue(), period.getFeeChargesDue(), period.getPenaltyChargesDue(), period.getInterestDue()));
|
||||
}
|
||||
}
|
||||
|
||||
private void logLoanTransactions(Long loanId) {
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
|
||||
assert loanDetails.getTransactions() != null;
|
||||
loanDetails.getTransactions()
|
||||
.forEach(tr -> log.info("Transaction {} {} {} ", tr.getType().getValue(), tr.getDate(), tr.getAmount()));
|
||||
if (loanDetails.getTransactions() != null) {
|
||||
loanDetails.getTransactions()
|
||||
.forEach(tr -> log.info("Transaction {} {} {} ", tr.getType().getValue(), tr.getDate(), tr.getAmount()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user