FINERACT-2024: Fix Overpayment portion miscalculated in CBR reverse-replay
This commit is contained in:
+3
-1
@@ -3867,7 +3867,9 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
if (loanTransaction.isRefund() || loanTransaction.isRefundForActiveLoan()) {
|
if (loanTransaction.isRefund() || loanTransaction.isRefundForActiveLoan()) {
|
||||||
totalPaidInRepayments = totalPaidInRepayments.minus(loanTransaction.getAmount(currency));
|
totalPaidInRepayments = totalPaidInRepayments.minus(loanTransaction.getAmount(currency));
|
||||||
} else if (loanTransaction.isCreditBalanceRefund() || loanTransaction.isChargeback()) {
|
} else if (loanTransaction.isCreditBalanceRefund() || loanTransaction.isChargeback()) {
|
||||||
totalPaidInRepayments = totalPaidInRepayments.minus(loanTransaction.getOverPaymentPortion(currency));
|
if (loanTransaction.getPrincipalPortion(currency).isZero()) {
|
||||||
|
totalPaidInRepayments = totalPaidInRepayments.minus(loanTransaction.getOverPaymentPortion(currency));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -227,7 +227,8 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
onLoanOverpayment(loanTransaction, transactionAmountUnprocessed);
|
onLoanOverpayment(loanTransaction, transactionAmountUnprocessed);
|
||||||
loanTransaction.setOverPayments(transactionAmountUnprocessed);
|
loanTransaction.setOverPayments(transactionAmountUnprocessed);
|
||||||
}
|
}
|
||||||
ctx.getOverpaymentHolder().setMoneyObject(transactionAmountUnprocessed);
|
ctx.getOverpaymentHolder()
|
||||||
|
.setMoneyObject(ctx.getOverpaymentHolder().getMoneyObject().add(transactionAmountUnprocessed));
|
||||||
} else {
|
} else {
|
||||||
ctx.getOverpaymentHolder().setMoneyObject(Money.zero(ctx.getCurrency()));
|
ctx.getOverpaymentHolder().setMoneyObject(Money.zero(ctx.getCurrency()));
|
||||||
}
|
}
|
||||||
|
|||||||
+181
-54
@@ -34,7 +34,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||||
@@ -3283,13 +3283,186 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateLoanSummaryBalances(GetLoansLoanIdResponse loanDetails, Double totalOutstanding, Double totalRepayment,
|
// UC124: Advanced payment allocation, MIR, CBR and Chargeback on overpaid loan
|
||||||
Double principalOutstanding, Double principalPaid, Double totalOverpaid) {
|
// ADVANCED_PAYMENT_ALLOCATION_STRATEGY
|
||||||
assertEquals(totalOutstanding, loanDetails.getSummary().getTotalOutstanding());
|
// 1. Create a Loan product with Adv. Pment. Alloc.
|
||||||
assertEquals(totalRepayment, loanDetails.getSummary().getTotalRepayment());
|
// 2. Submit Loan and approve
|
||||||
assertEquals(principalOutstanding, loanDetails.getSummary().getPrincipalOutstanding());
|
// 3. Disburse only 100
|
||||||
assertEquals(principalPaid, loanDetails.getSummary().getPrincipalPaid());
|
// 4. Fully pay the loan
|
||||||
assertEquals(totalOverpaid, loanDetails.getTotalOverpaid());
|
// 5. Do MIR 3 times
|
||||||
|
// 6. Do a CBR
|
||||||
|
// 7. Do MIR 2 times
|
||||||
|
// 8. Reverse the 1st MIR
|
||||||
|
// 9. Do Chargeback (lower than overpayment amount)
|
||||||
|
// 10.Do Chargeback again (reactive the loan)
|
||||||
|
@Test
|
||||||
|
public void uc124() {
|
||||||
|
runAt("06 March 2024", () -> {
|
||||||
|
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
|
||||||
|
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
|
||||||
|
.numberOfRepayments(1).repaymentEvery(30).enableDownPayment(false);
|
||||||
|
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||||
|
PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductResponse.getResourceId(), "25 January 2024", 1000.0,
|
||||||
|
4);
|
||||||
|
|
||||||
|
applicationRequest = applicationRequest.numberOfRepayments(1).loanTermFrequency(30)
|
||||||
|
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY).repaymentEvery(30);
|
||||||
|
|
||||||
|
PostLoansResponse loanResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||||
|
|
||||||
|
loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
|
||||||
|
new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
|
||||||
|
.approvedOnDate("25 January 2024").locale("en"));
|
||||||
|
|
||||||
|
loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
|
||||||
|
new PostLoansLoanIdRequest().actualDisbursementDate("25 January 2024").dateFormat(DATETIME_PATTERN)
|
||||||
|
.transactionAmount(BigDecimal.valueOf(100.0)).locale("en"));
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 100.0, 0.0, 100.0, 0.0, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 0.0, 100.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getActive());
|
||||||
|
|
||||||
|
String repaymentExternalId = UUID.randomUUID().toString();
|
||||||
|
loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(),
|
||||||
|
new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN).transactionDate("24 February 2024").locale("en")
|
||||||
|
.transactionAmount(100.0).externalId(repaymentExternalId));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getClosedObligationsMet());
|
||||||
|
|
||||||
|
String mir1ExternalId = UUID.randomUUID().toString();
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(),
|
||||||
|
new PostLoansLoanIdTransactionsRequest().transactionDate("28 February 2024").dateFormat(DATETIME_PATTERN)
|
||||||
|
.transactionAmount(36.99).locale("en").externalId(mir1ExternalId));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 36.99);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("28 February 2024").dateFormat(DATETIME_PATTERN).transactionAmount(18.94).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 55.93);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("28 February 2024").dateFormat(DATETIME_PATTERN).transactionAmount(36.99).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 92.92);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("28 February 2024").dateFormat(DATETIME_PATTERN).transactionAmount(31.99).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 124.91);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeCreditBalanceRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("01 March 2024").dateFormat(DATETIME_PATTERN).transactionAmount(124.91).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getClosedObligationsMet());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("02 March 2024").dateFormat(DATETIME_PATTERN).transactionAmount(19.99).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 19.99);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("02 March 2024").dateFormat(DATETIME_PATTERN).transactionAmount(19.99).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 39.98);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
verifyTransactions(loanResponse.getLoanId(), //
|
||||||
|
transaction(100, "Disbursement", "25 January 2024", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(100, "Repayment", "24 February 2024", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(18.94, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 18.94), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 55.93), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 92.92), //
|
||||||
|
transaction(31.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 124.91), //
|
||||||
|
transaction(124.91, "Credit Balance Refund", "01 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 124.91), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 19.99), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 39.98) //
|
||||||
|
);
|
||||||
|
|
||||||
|
loanTransactionHelper.reverseLoanTransaction(loanResponse.getLoanId(), mir1ExternalId,
|
||||||
|
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN).transactionDate("02 March 2024")
|
||||||
|
.transactionAmount(0.0).locale("en"));
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 224.91, 0.0, 224.91, 2.99);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 1), 124.91, 124.91, 0.0, 0.0, 36.99);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
verifyTransactions(loanResponse.getLoanId(), //
|
||||||
|
transaction(100, "Disbursement", "25 January 2024", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(100, "Repayment", "24 February 2024", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 36.99, true), //
|
||||||
|
transaction(18.94, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 18.94), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 55.93), //
|
||||||
|
transaction(31.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(124.91, "Credit Balance Refund", "01 March 2024", 36.99, 36.99, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 17.0, 19.99, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 17.0, 0.0, 0.0, 0.0, 0.0, 2.99) //
|
||||||
|
);
|
||||||
|
|
||||||
|
loanTransactionHelper.chargebackLoanTransaction(loanResponse.getLoanId(), repaymentExternalId,
|
||||||
|
new PostLoansLoanIdTransactionsTransactionIdRequest().locale("en").transactionAmount(2.0));
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 224.91, 0.0, 224.91, 0.99);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 1), 124.91, 124.91, 0.0, 0.0, 36.99);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
verifyTransactions(loanResponse.getLoanId(), //
|
||||||
|
transaction(100, "Disbursement", "25 January 2024", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(100, "Repayment", "24 February 2024", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 36.99, true), //
|
||||||
|
transaction(18.94, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 18.94), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 55.93), //
|
||||||
|
transaction(31.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(124.91, "Credit Balance Refund", "01 March 2024", 36.99, 36.99, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 17.0, 19.99, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 17.0, 0.0, 0.0, 0.0, 0.0, 2.99), //
|
||||||
|
transaction(2.0, "Chargeback", "06 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0) //
|
||||||
|
);
|
||||||
|
|
||||||
|
loanTransactionHelper.chargebackLoanTransaction(loanResponse.getLoanId(), repaymentExternalId,
|
||||||
|
new PostLoansLoanIdTransactionsTransactionIdRequest().locale("en").transactionAmount(1.0));
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.01, 225.90, 0.01, 225.90, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 6), 125.91, 125.90, 0.01, 0.0, 36.99);
|
||||||
|
assertTrue(loanDetails.getStatus().getActive());
|
||||||
|
|
||||||
|
verifyTransactions(loanResponse.getLoanId(), //
|
||||||
|
transaction(100, "Disbursement", "25 January 2024", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(100, "Repayment", "24 February 2024", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 36.99, true), //
|
||||||
|
transaction(18.94, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 18.94), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 55.93), //
|
||||||
|
transaction(31.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(124.91, "Credit Balance Refund", "01 March 2024", 36.99, 36.99, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 17.0, 19.99, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 17.0, 0.0, 0.0, 0.0, 0.0, 2.99), //
|
||||||
|
transaction(2.0, "Chargeback", "06 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0), //
|
||||||
|
transaction(1.0, "Chargeback", "06 March 2024", 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.99) //
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||||
@@ -3430,52 +3603,6 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
|
|||||||
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
|
||||||
double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) {
|
|
||||||
GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream()
|
|
||||||
.filter(p -> Objects.equals(p.getPeriod(), index)).findFirst().orElseThrow();
|
|
||||||
assertEquals(dueDate, period.getDueDate());
|
|
||||||
assertEquals(principalDue, period.getPrincipalDue());
|
|
||||||
assertEquals(principalPaid, period.getPrincipalPaid());
|
|
||||||
assertEquals(principalOutstanding, period.getPrincipalOutstanding());
|
|
||||||
assertEquals(paidInAdvance, period.getTotalPaidInAdvanceForPeriod());
|
|
||||||
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, double principalDue,
|
|
||||||
double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) {
|
|
||||||
GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream()
|
|
||||||
.filter(p -> Objects.equals(p.getPeriod(), index)).findFirst().orElseThrow();
|
|
||||||
assertEquals(principalDue, period.getPrincipalDue());
|
|
||||||
assertEquals(principalPaid, period.getPrincipalPaid());
|
|
||||||
assertEquals(principalOutstanding, period.getPrincipalOutstanding());
|
|
||||||
assertEquals(paidInAdvance, period.getTotalPaidInAdvanceForPeriod());
|
|
||||||
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
|
||||||
double principalPaid, double principalOutstanding, double feeDue, double feePaid, double feeOutstanding, double penaltyDue,
|
|
||||||
double penaltyPaid, double penaltyOutstanding, double interestDue, double interestPaid, double interestOutstanding,
|
|
||||||
double paidInAdvance, double paidLate) {
|
|
||||||
GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream()
|
|
||||||
.filter(p -> Objects.equals(p.getPeriod(), index)).findFirst().orElseThrow();
|
|
||||||
assertEquals(dueDate, period.getDueDate());
|
|
||||||
assertEquals(principalDue, period.getPrincipalDue());
|
|
||||||
assertEquals(principalPaid, period.getPrincipalPaid());
|
|
||||||
assertEquals(principalOutstanding, period.getPrincipalOutstanding());
|
|
||||||
assertEquals(feeDue, period.getFeeChargesDue());
|
|
||||||
assertEquals(feePaid, period.getFeeChargesPaid());
|
|
||||||
assertEquals(feeOutstanding, period.getFeeChargesOutstanding());
|
|
||||||
assertEquals(penaltyDue, period.getPenaltyChargesDue());
|
|
||||||
assertEquals(penaltyPaid, period.getPenaltyChargesPaid());
|
|
||||||
assertEquals(penaltyOutstanding, period.getPenaltyChargesOutstanding());
|
|
||||||
assertEquals(interestDue, period.getInterestDue());
|
|
||||||
assertEquals(interestPaid, period.getInterestPaid());
|
|
||||||
assertEquals(interestOutstanding, period.getInterestOutstanding());
|
|
||||||
assertEquals(paidInAdvance, period.getTotalPaidInAdvanceForPeriod());
|
|
||||||
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final BigDecimal principal,
|
private static PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final BigDecimal principal,
|
||||||
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
|
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
|
||||||
final String expectedDisbursementDate, final String submittedOnDate, String transactionProcessorCode,
|
final String expectedDisbursementDate, final String submittedOnDate, String transactionProcessorCode,
|
||||||
|
|||||||
+56
@@ -22,6 +22,7 @@ import static java.lang.Boolean.FALSE;
|
|||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
import static org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType.BUSINESS_DATE;
|
import static org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType.BUSINESS_DATE;
|
||||||
import static org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY;
|
import static org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
@@ -717,6 +718,61 @@ public abstract class BaseLoanIntegrationTest {
|
|||||||
return new BatchRequestBuilder(requestSpec, responseSpec);
|
return new BatchRequestBuilder(requestSpec, responseSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void validateLoanSummaryBalances(GetLoansLoanIdResponse loanDetails, Double totalOutstanding, Double totalRepayment,
|
||||||
|
Double principalOutstanding, Double principalPaid, Double totalOverpaid) {
|
||||||
|
assertEquals(totalOutstanding, loanDetails.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(totalRepayment, loanDetails.getSummary().getTotalRepayment());
|
||||||
|
assertEquals(principalOutstanding, loanDetails.getSummary().getPrincipalOutstanding());
|
||||||
|
assertEquals(principalPaid, loanDetails.getSummary().getPrincipalPaid());
|
||||||
|
assertEquals(totalOverpaid, loanDetails.getTotalOverpaid());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
||||||
|
double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) {
|
||||||
|
GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream()
|
||||||
|
.filter(p -> Objects.equals(p.getPeriod(), index)).findFirst().orElseThrow();
|
||||||
|
assertEquals(dueDate, period.getDueDate());
|
||||||
|
assertEquals(principalDue, period.getPrincipalDue());
|
||||||
|
assertEquals(principalPaid, period.getPrincipalPaid());
|
||||||
|
assertEquals(principalOutstanding, period.getPrincipalOutstanding());
|
||||||
|
assertEquals(paidInAdvance, period.getTotalPaidInAdvanceForPeriod());
|
||||||
|
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, double principalDue,
|
||||||
|
double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) {
|
||||||
|
GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream()
|
||||||
|
.filter(p -> Objects.equals(p.getPeriod(), index)).findFirst().orElseThrow();
|
||||||
|
assertEquals(principalDue, period.getPrincipalDue());
|
||||||
|
assertEquals(principalPaid, period.getPrincipalPaid());
|
||||||
|
assertEquals(principalOutstanding, period.getPrincipalOutstanding());
|
||||||
|
assertEquals(paidInAdvance, period.getTotalPaidInAdvanceForPeriod());
|
||||||
|
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
||||||
|
double principalPaid, double principalOutstanding, double feeDue, double feePaid, double feeOutstanding, double penaltyDue,
|
||||||
|
double penaltyPaid, double penaltyOutstanding, double interestDue, double interestPaid, double interestOutstanding,
|
||||||
|
double paidInAdvance, double paidLate) {
|
||||||
|
GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream()
|
||||||
|
.filter(p -> Objects.equals(p.getPeriod(), index)).findFirst().orElseThrow();
|
||||||
|
assertEquals(dueDate, period.getDueDate());
|
||||||
|
assertEquals(principalDue, period.getPrincipalDue());
|
||||||
|
assertEquals(principalPaid, period.getPrincipalPaid());
|
||||||
|
assertEquals(principalOutstanding, period.getPrincipalOutstanding());
|
||||||
|
assertEquals(feeDue, period.getFeeChargesDue());
|
||||||
|
assertEquals(feePaid, period.getFeeChargesPaid());
|
||||||
|
assertEquals(feeOutstanding, period.getFeeChargesOutstanding());
|
||||||
|
assertEquals(penaltyDue, period.getPenaltyChargesDue());
|
||||||
|
assertEquals(penaltyPaid, period.getPenaltyChargesPaid());
|
||||||
|
assertEquals(penaltyOutstanding, period.getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(interestDue, period.getInterestDue());
|
||||||
|
assertEquals(interestPaid, period.getInterestPaid());
|
||||||
|
assertEquals(interestOutstanding, period.getInterestOutstanding());
|
||||||
|
assertEquals(paidInAdvance, period.getTotalPaidInAdvanceForPeriod());
|
||||||
|
assertEquals(paidLate, period.getTotalPaidLateForPeriod());
|
||||||
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public static class BatchRequestBuilder {
|
public static class BatchRequestBuilder {
|
||||||
|
|
||||||
|
|||||||
+184
@@ -21,23 +21,34 @@ package org.apache.fineract.integrationtests;
|
|||||||
import static org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder.DEFAULT_STRATEGY;
|
import static org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder.DEFAULT_STRATEGY;
|
||||||
import static org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY;
|
import static org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import io.restassured.builder.RequestSpecBuilder;
|
import io.restassured.builder.RequestSpecBuilder;
|
||||||
import io.restassured.builder.ResponseSpecBuilder;
|
import io.restassured.builder.ResponseSpecBuilder;
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import io.restassured.specification.RequestSpecification;
|
import io.restassured.specification.RequestSpecification;
|
||||||
import io.restassured.specification.ResponseSpecification;
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||||
|
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||||
|
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||||
|
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||||
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||||
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
||||||
|
import org.apache.fineract.client.models.PostLoansRequest;
|
||||||
|
import org.apache.fineract.client.models.PostLoansResponse;
|
||||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||||
import org.apache.fineract.integrationtests.common.Utils;
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
@@ -55,6 +66,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
|
|||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Named;
|
import org.junit.jupiter.api.Named;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
@@ -695,6 +707,178 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest extend
|
|||||||
responseSpec403);
|
responseSpec403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cbrReverseReplayTest() {
|
||||||
|
runAt("06 March 2024", () -> {
|
||||||
|
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
|
||||||
|
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct().numberOfRepayments(1)
|
||||||
|
.repaymentEvery(30).enableDownPayment(false);
|
||||||
|
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||||
|
PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductResponse.getResourceId(), "25 January 2024", 1000.0,
|
||||||
|
4);
|
||||||
|
|
||||||
|
applicationRequest = applicationRequest.numberOfRepayments(1).loanTermFrequency(30)
|
||||||
|
.transactionProcessingStrategyCode(
|
||||||
|
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY)
|
||||||
|
.repaymentEvery(30);
|
||||||
|
|
||||||
|
PostLoansResponse loanResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||||
|
|
||||||
|
loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
|
||||||
|
new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
|
||||||
|
.approvedOnDate("25 January 2024").locale("en"));
|
||||||
|
|
||||||
|
loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
|
||||||
|
new PostLoansLoanIdRequest().actualDisbursementDate("25 January 2024").dateFormat(DATETIME_PATTERN)
|
||||||
|
.transactionAmount(BigDecimal.valueOf(100.0)).locale("en"));
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 100.0, 0.0, 100.0, 0.0, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 0.0, 100.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getActive());
|
||||||
|
|
||||||
|
String repaymentExternalId = UUID.randomUUID().toString();
|
||||||
|
loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(),
|
||||||
|
new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN).transactionDate("24 February 2024").locale("en")
|
||||||
|
.transactionAmount(100.0).externalId(repaymentExternalId));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getClosedObligationsMet());
|
||||||
|
|
||||||
|
String mir1ExternalId = UUID.randomUUID().toString();
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(),
|
||||||
|
new PostLoansLoanIdTransactionsRequest().transactionDate("28 February 2024").dateFormat(DATETIME_PATTERN)
|
||||||
|
.transactionAmount(36.99).locale("en").externalId(mir1ExternalId));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 36.99);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("28 February 2024").dateFormat(DATETIME_PATTERN).transactionAmount(18.94).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 55.93);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("28 February 2024").dateFormat(DATETIME_PATTERN).transactionAmount(36.99).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 92.92);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("28 February 2024").dateFormat(DATETIME_PATTERN).transactionAmount(31.99).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 124.91);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeCreditBalanceRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("01 March 2024").dateFormat(DATETIME_PATTERN).transactionAmount(124.91).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getClosedObligationsMet());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("02 March 2024").dateFormat(DATETIME_PATTERN).transactionAmount(19.99).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 19.99);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||||
|
.transactionDate("02 March 2024").dateFormat(DATETIME_PATTERN).transactionAmount(19.99).locale("en"));
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 39.98);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
verifyTransactions(loanResponse.getLoanId(), //
|
||||||
|
transaction(100, "Disbursement", "25 January 2024", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(100, "Repayment", "24 February 2024", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(18.94, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 18.94), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 55.93), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 92.92), //
|
||||||
|
transaction(31.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 124.91), //
|
||||||
|
transaction(124.91, "Credit Balance Refund", "01 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 124.91), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 19.99), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 39.98) //
|
||||||
|
);
|
||||||
|
|
||||||
|
loanTransactionHelper.reverseLoanTransaction(loanResponse.getLoanId(), mir1ExternalId,
|
||||||
|
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN).transactionDate("02 March 2024")
|
||||||
|
.transactionAmount(0.0).locale("en"));
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 224.91, 0.0, 224.91, 2.99);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 1), 124.91, 124.91, 0.0, 0.0, 36.99);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
verifyTransactions(loanResponse.getLoanId(), //
|
||||||
|
transaction(100, "Disbursement", "25 January 2024", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(100, "Repayment", "24 February 2024", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 36.99, true), //
|
||||||
|
transaction(18.94, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 18.94), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 55.93), //
|
||||||
|
transaction(31.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(124.91, "Credit Balance Refund", "01 March 2024", 36.99, 36.99, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 17.0, 19.99, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 17.0, 0.0, 0.0, 0.0, 0.0, 2.99) //
|
||||||
|
);
|
||||||
|
|
||||||
|
loanTransactionHelper.chargebackLoanTransaction(loanResponse.getLoanId(), repaymentExternalId,
|
||||||
|
new PostLoansLoanIdTransactionsTransactionIdRequest().locale("en").transactionAmount(2.0));
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 224.91, 0.0, 224.91, 0.99);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 1), 124.91, 124.91, 0.0, 0.0, 36.99);
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
|
||||||
|
verifyTransactions(loanResponse.getLoanId(), //
|
||||||
|
transaction(100, "Disbursement", "25 January 2024", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(100, "Repayment", "24 February 2024", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 36.99, true), //
|
||||||
|
transaction(18.94, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 18.94), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 55.93), //
|
||||||
|
transaction(31.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(124.91, "Credit Balance Refund", "01 March 2024", 36.99, 36.99, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 17.0, 19.99, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 17.0, 0.0, 0.0, 0.0, 0.0, 2.99), //
|
||||||
|
transaction(2.0, "Chargeback", "06 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0) //
|
||||||
|
);
|
||||||
|
|
||||||
|
loanTransactionHelper.chargebackLoanTransaction(loanResponse.getLoanId(), repaymentExternalId,
|
||||||
|
new PostLoansLoanIdTransactionsTransactionIdRequest().locale("en").transactionAmount(1.0));
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.01, 225.90, 0.01, 225.90, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 24), 100.0, 100.0, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 6), 125.91, 125.90, 0.01, 0.0, 36.99);
|
||||||
|
assertTrue(loanDetails.getStatus().getActive());
|
||||||
|
|
||||||
|
verifyTransactions(loanResponse.getLoanId(), //
|
||||||
|
transaction(100, "Disbursement", "25 January 2024", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(100, "Repayment", "24 February 2024", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 36.99, true), //
|
||||||
|
transaction(18.94, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 18.94), //
|
||||||
|
transaction(36.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 55.93), //
|
||||||
|
transaction(31.99, "Merchant Issued Refund", "28 February 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(124.91, "Credit Balance Refund", "01 March 2024", 36.99, 36.99, 0.0, 0.0, 0.0, 0.0, 87.92), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 17.0, 19.99, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||||
|
transaction(19.99, "Merchant Issued Refund", "02 March 2024", 0.0, 17.0, 0.0, 0.0, 0.0, 0.0, 2.99), //
|
||||||
|
transaction(2.0, "Chargeback", "06 March 2024", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0), //
|
||||||
|
transaction(1.0, "Chargeback", "06 March 2024", 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.99) //
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static AdvancedPaymentData createRepaymentPaymentAllocation() {
|
private static AdvancedPaymentData createRepaymentPaymentAllocation() {
|
||||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||||
advancedPaymentData.setTransactionType("REPAYMENT");
|
advancedPaymentData.setTransactionType("REPAYMENT");
|
||||||
|
|||||||
Reference in New Issue
Block a user