Skip to content

Commit da1f310

Browse files
committed
FINERACT-2326: Fix duplicate reverse replay of ‘Accrual Activity’ during reprocessing
1 parent 1b3217b commit da1f310

File tree

4 files changed

+67
-2
lines changed

4 files changed

+67
-2
lines changed

fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import static org.apache.fineract.test.factory.LoanProductsRequestFactory.LOCALE_EN;
2828
import static org.assertj.core.api.Assertions.assertThat;
2929
import static org.awaitility.Awaitility.await;
30+
import static org.junit.jupiter.api.Assertions.assertEquals;
3031
import static org.junit.jupiter.api.Assertions.assertNotNull;
3132
import static org.junit.jupiter.api.Assertions.assertNull;
3233
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -6095,4 +6096,26 @@ private List<String> fetchValuesOfAmortizationAllocationMapping(final List<Strin
60956096
}
60966097
return actualValues;
60976098
}
6099+
6100+
@Then("In Loan Transactions the {string}th Transaction of {string} on {string} has {string} relationship with type={string}")
6101+
public void inLoanTransactionsTheThTransactionOfOnHasRelationshipWithTypeREPLAYED(String nthTransactionFromStr, String transactionType,
6102+
String transactionDate, String numberOfRelations, String relationshipType) throws IOException {
6103+
final Response<PostLoansResponse> loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
6104+
final long loanId = loanCreateResponse.body().getLoanId();
6105+
6106+
final Response<GetLoansLoanIdResponse> loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute();
6107+
ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
6108+
6109+
final List<GetLoansLoanIdTransactions> transactions = loanDetailsResponse.body().getTransactions();
6110+
final int nthTransactionFrom = nthTransactionFromStr == null ? transactions.size() - 1
6111+
: Integer.parseInt(nthTransactionFromStr) - 1;
6112+
final GetLoansLoanIdTransactions transactionFrom = transactions.stream()
6113+
.filter(t -> transactionType.equals(t.getType().getValue()) && transactionDate.equals(FORMATTER.format(t.getDate())))
6114+
.toList().get(nthTransactionFrom);
6115+
6116+
final List<GetLoansLoanIdLoanTransactionRelation> relationshipOptional = transactionFrom.getTransactionRelations().stream()
6117+
.filter(r -> r.getRelationType().equals(relationshipType)).toList();
6118+
6119+
assertEquals(Integer.valueOf(numberOfRelations), relationshipOptional.size(), "Missed relationship for transaction");
6120+
}
60986121
}

fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4562,7 +4562,7 @@ Feature: LoanRepayment
45624562
| 27 March 2025 | Repayment | 20.0 | 19.89 | 0.11 | 0.0 | 0.0 | 100.11 | false | true |
45634563
| 27 March 2025 | Merchant Issued Refund | 120.0 | 100.11 | 0.0 | 0.0 | 0.0 | 0.0 | false | true |
45644564
| 27 March 2025 | Interest Refund | 0.11 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true |
4565-
| 27 March 2025 | Accrual Activity | 0.11 | 0.0 | 0.11 | 0.0 | 0.0 | 0.0 | false | true |
4565+
| 27 March 2025 | Accrual Activity | 0.11 | 0.0 | 0.11 | 0.0 | 0.0 | 0.0 | false | false |
45664566
| 28 March 2025 | Accrual | 0.11 | 0.0 | 0.11 | 0.0 | 0.0 | 0.0 | false | false |
45674567
| 28 March 2025 | Credit Balance Refund | 20.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false |
45684568
Then Loan status will be "CLOSED_OBLIGATIONS_MET"

fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,3 +1132,45 @@ Feature: LoanReschedule
11321132
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
11331133
| 24 July 2025 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.0 | false | false |
11341134
Then LoanRescheduledDueAdjustScheduleBusinessEvent is raised on "24 July 2025"
1135+
1136+
@TestRailId:C4225
1137+
Scenario: Verify after reschedule of loan by changing due date, the last Accrual Activity transaction is reversed-replayed only once
1138+
When Admin sets the business date to "05 September 2025"
1139+
And Admin creates a client with random data
1140+
And Admin creates a fully customized loan with the following data:
1141+
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
1142+
| LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY | 31 December 2024 | 1111 | 24.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 24 | MONTHS | 1 | MONTHS | 24 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
1143+
And Admin successfully approves the loan on "31 December 2024" with "1111" amount and expected disbursement date on "31 December 2024"
1144+
And Admin successfully disburse the loan on "31 December 2024" with "1111" EUR transaction amount
1145+
And Customer makes "AUTOPAY" repayment on "31 January 2025" with 59.26 EUR transaction amount
1146+
And Customer makes "AUTOPAY" repayment on "28 February 2025" with 59.26 EUR transaction amount
1147+
And Customer makes "AUTOPAY" repayment on "31 March 2025" with 59.26 EUR transaction amount
1148+
And Customer makes "AUTOPAY" repayment on "30 April 2025" with 59.26 EUR transaction amount
1149+
And Customer makes "AUTOPAY" repayment on "30 May 2025" with 59.26 EUR transaction amount
1150+
And Customer makes "AUTOPAY" repayment on "29 June 2025" with 59.26 EUR transaction amount
1151+
And Customer makes "AUTOPAY" repayment on "31 July 2025" with 59.26 EUR transaction amount
1152+
And Customer makes "AUTOPAY" repayment on "31 August 2025" with 59.26 EUR transaction amount
1153+
When Admin sets the business date to "06 September 2025"
1154+
When Admin runs inline COB job for Loan
1155+
When Admin sets the business date to "11 September 2025"
1156+
When Customer undo "1"th "Repayment" transaction made on "31 August 2025"
1157+
When Admin sets the business date to "30 September 2025"
1158+
And Customer makes "AUTOPAY" repayment on "30 September 2025" with 59.26 EUR transaction amount
1159+
And Customer makes "AUTOPAY" repayment on "30 September 2025" with 59.26 EUR transaction amount
1160+
When Admin runs inline COB job for Loan
1161+
When Admin sets the business date to "10 October 2025"
1162+
When Customer undo "1"th "Repayment" transaction made on "30 September 2025"
1163+
When Customer undo "2"th "Repayment" transaction made on "30 September 2025"
1164+
When Admin sets the business date to "16 October 2025"
1165+
And Customer makes "AUTOPAY" repayment on "16 October 2025" with 60 EUR transaction amount
1166+
When Admin sets the business date to "31 October 2025"
1167+
And Customer makes "AUTOPAY" repayment on "31 October 2025" with 59.26 EUR transaction amount
1168+
And Customer makes "AUTOPAY" repayment on "31 October 2025" with 58.52 EUR transaction amount
1169+
When Admin runs inline COB job for Loan
1170+
When Admin sets the business date to "10 November 2025"
1171+
When Admin runs inline COB job for Loan
1172+
When Admin creates and approves Loan reschedule with the following data:
1173+
| rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate |
1174+
| 30 November 2025 | 10 November 2025 | 31 January 2026 | | | | |
1175+
Then In Loan Transactions the "1"th Transaction of "Accrual Activity" on "31 October 2025" has "1" relationship with type="REPLAYED"
1176+

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1191,7 +1191,7 @@ private static LoanTransaction useOldTransactionIfApplicable(LoanTransaction old
11911191
boolean alreadyProcessed = changedTransactionDetail.getTransactionChanges().stream().map(TransactionChangeData::getNewTransaction)
11921192
.anyMatch(lt -> !lt.equals(newTransaction) && lt.getTransactionDate().equals(oldTransaction.getTransactionDate()));
11931193
boolean amountMatch = LoanTransaction.transactionAmountsMatch(currency, oldTransaction, newTransaction);
1194-
if (!alreadyProcessed && amountMatch) {
1194+
if ((!alreadyProcessed && amountMatch) || newTransaction.isAccrualActivity()) {
11951195
if (!oldTransaction.getTypeOf().isWaiveCharges()) { // WAIVE_CHARGES is not reprocessed
11961196
oldTransaction
11971197
.updateLoanTransactionToRepaymentScheduleMappings(newTransaction.getLoanTransactionToRepaymentScheduleMappings());

0 commit comments

Comments
 (0)