This is an automated email from the ASF dual-hosted git repository.
taskain pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 5ce69c19f FINERACT-2024: Fix Overpayment portion miscalculated in CBR
reverse-replay
5ce69c19f is described below
commit 5ce69c19fe829b19d64c19f93c9ee6cc68e7a214
Author: Adam Saghy <[email protected]>
AuthorDate: Thu Mar 7 16:36:15 2024 +0100
FINERACT-2024: Fix Overpayment portion miscalculated in CBR reverse-replay
---
.../portfolio/loanaccount/domain/Loan.java | 4 +-
...tLoanRepaymentScheduleTransactionProcessor.java | 3 +-
...PaymentAllocationLoanRepaymentScheduleTest.java | 235 ++++++++++++++++-----
.../integrationtests/BaseLoanIntegrationTest.java | 56 +++++
...lanceRefundandRepaymentTypeIntegrationTest.java | 184 ++++++++++++++++
5 files changed, 426 insertions(+), 56 deletions(-)
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index deeb280ce..d9d9c931c 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -3867,7 +3867,9 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
if (loanTransaction.isRefund() ||
loanTransaction.isRefundForActiveLoan()) {
totalPaidInRepayments =
totalPaidInRepayments.minus(loanTransaction.getAmount(currency));
} else if (loanTransaction.isCreditBalanceRefund() ||
loanTransaction.isChargeback()) {
- totalPaidInRepayments =
totalPaidInRepayments.minus(loanTransaction.getOverPaymentPortion(currency));
+ if (loanTransaction.getPrincipalPortion(currency).isZero()) {
+ totalPaidInRepayments =
totalPaidInRepayments.minus(loanTransaction.getOverPaymentPortion(currency));
+ }
}
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
index 94592fed8..b05c2ae9e 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
@@ -227,7 +227,8 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
onLoanOverpayment(loanTransaction,
transactionAmountUnprocessed);
loanTransaction.setOverPayments(transactionAmountUnprocessed);
}
-
ctx.getOverpaymentHolder().setMoneyObject(transactionAmountUnprocessed);
+ ctx.getOverpaymentHolder()
+
.setMoneyObject(ctx.getOverpaymentHolder().getMoneyObject().add(transactionAmountUnprocessed));
} else {
ctx.getOverpaymentHolder().setMoneyObject(Money.zero(ctx.getCurrency()));
}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
index aa1bd5e42..7e71d4223 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
@@ -34,7 +34,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
-import java.util.Objects;
+import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
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,
- 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());
+ // UC124: Advanced payment allocation, MIR, CBR and Chargeback on overpaid
loan
+ // ADVANCED_PAYMENT_ALLOCATION_STRATEGY
+ // 1. Create a Loan product with Adv. Pment. Alloc.
+ // 2. Submit Loan and approve
+ // 3. Disburse only 100
+ // 4. Fully pay the loan
+ // 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) {
@@ -3430,52 +3603,6 @@ public class
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
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,
final int loanTermFrequency, final int repaymentAfterEvery, final
int numberOfRepayments, final BigDecimal interestRate,
final String expectedDisbursementDate, final String
submittedOnDate, String transactionProcessorCode,
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
index bcd50f555..7903ca41e 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
@@ -22,6 +22,7 @@ import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
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.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -717,6 +718,61 @@ public abstract class BaseLoanIntegrationTest {
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
public static class BatchRequestBuilder {
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
index 3f884f2da..cffaa660c 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
@@ -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.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.assertTrue;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
+import java.math.BigDecimal;
+import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.client.models.AdvancedPaymentData;
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
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.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.CommonConstants;
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.BeforeEach;
import org.junit.jupiter.api.Named;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -695,6 +707,178 @@ public class
ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest extend
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() {
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
advancedPaymentData.setTransactionType("REPAYMENT");