FINERACT-2024: Fix Overpayment portion miscalculated in CBR reverse-replay

This commit is contained in:
Adam Saghy
2024-03-08 06:04:07 +01:00
committed by taskain7
parent 698e2ce8c3
commit 5ce69c19fe
5 changed files with 426 additions and 56 deletions
@@ -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));
}
} }
} }
@@ -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()));
} }
@@ -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,
@@ -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 {
@@ -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");