Skip to content

Commit 012f73d

Browse files
authored
Merge pull request #5785
FINERACT-2455: WC - Transaction Type - CBR
2 parents a7d0f0e + 02f5530 commit 012f73d

36 files changed

Lines changed: 1705 additions & 58 deletions

File tree

fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,14 @@ public CommandWrapperBuilder repaymentWorkingCapitalLoanTransaction(final Long l
881881
return this;
882882
}
883883

884+
public CommandWrapperBuilder creditBalanceRefundWorkingCapitalLoanTransaction(final Long loanId) {
885+
this.actionName = ACTION_CREDITBALANCEREFUND;
886+
this.entityName = ENTITY_WORKINGCAPITALLOAN;
887+
this.entityId = loanId;
888+
this.href = "/working-capital-loans/" + loanId + "/transactions?command=creditBalanceRefund";
889+
return this;
890+
}
891+
884892
public CommandWrapperBuilder createClientIdentifier(final Long clientId) {
885893
this.actionName = ACTION_CREATE;
886894
this.entityName = ENTITY_CLIENTIDENTIFIER;

fineract-doc/src/docs/en/chapters/features/index.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ include::re-ageing.adoc[leveloffset=+1]
1717
include::delayed-schedule-captures.adoc[leveloffset=+1]
1818
include::loan-origination-details.adoc[leveloffset=+1]
1919
include::working-capital-amortization-schedule.adoc[leveloffset=+1]
20+
include::working-capital-credit-balance-refund.adoc[leveloffset=+1]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
= Working Capital Loan — Credit Balance Refund (CBR)
2+
3+
== Overview
4+
5+
Credit Balance Refund (CBR) is supported for Working Capital loans when a loan has an overpayment balance.
6+
7+
== Core Behavior
8+
9+
For Working Capital loans:
10+
11+
* Overpayment is tracked in `m_wc_loan_balance.overpayment_amount`
12+
* `principal_outstanding` is not reduced below zero; excess repayment is tracked as overpayment
13+
* CBR reduces `overpayment_amount` by the refund amount
14+
15+
== Validation
16+
17+
CBR is allowed only when:
18+
19+
* Loan status is `OVERPAID`
20+
* `overpayment_amount > 0`
21+
* Refund amount is positive and does not exceed current `overpayment_amount`
22+
23+
== Status Handling
24+
25+
After CBR:
26+
27+
* If `overpayment_amount > 0`, the loan remains `OVERPAID`
28+
* If `overpayment_amount = 0` and `principal_outstanding = 0`, status transitions to `CLOSED_OBLIGATIONS_MET`

fineract-e2e-tests-core/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ dependencies {
7171
testImplementation 'io.github.openfeign:feign-core:13.6'
7272
testImplementation 'org.apache.httpcomponents:httpclient:4.5.14'
7373
testImplementation 'org.apache.commons:commons-lang3:3.18.0'
74+
testImplementation 'com.google.guava:guava'
7475
testImplementation ('com.googlecode.json-simple:json-simple:1.1.1') {
7576
exclude group: 'junit', module: 'junit'
7677
}

fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionMerchantIssuedRefundPostEvent;
8484
import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionPayoutRefundPostEvent;
8585
import org.apache.fineract.test.messaging.event.loan.transaction.LoanUndoContractTerminationBusinessEvent;
86+
import org.apache.fineract.test.messaging.event.workingcapitalloan.transaction.WorkingCapitalLoanCreditBalanceRefundTransactionBusinessEvent;
8687
import org.apache.fineract.test.messaging.event.workingcapitalloan.transaction.WorkingCapitalLoanDisbursalTransactionBusinessEvent;
8788
import org.apache.fineract.test.messaging.event.workingcapitalloan.transaction.WorkingCapitalLoanUndoDisbursalTransactionBusinessEvent;
8889
import org.springframework.beans.factory.annotation.Autowired;
@@ -318,6 +319,27 @@ public void workingCapitalLoanDisbursalTransactionEventCheck(final Long loanId,
318319
.extractingData(WorkingCapitalLoanTransactionDataV1::getReversed).isEqualTo(Boolean.FALSE);
319320
}
320321

322+
public void workingCapitalLoanCreditBalanceRefundTransactionEventCheck(final Long loanId, final BigDecimal expectedAmount) {
323+
waitForTransactionCommit();
324+
final GetWorkingCapitalLoansLoanIdResponse body = ok(
325+
() -> fineractClient.workingCapitalLoans().retrieveWorkingCapitalLoanById(loanId));
326+
if (body.getTransactions() == null || body.getTransactions().isEmpty()) {
327+
throw new IllegalStateException("No Working Capital Loan transactions found");
328+
}
329+
330+
final GetWorkingCapitalLoanTransactionIdResponse cbrTransaction = body.getTransactions().stream()
331+
.filter(t -> t.getType() != null && "loanTransactionType.creditBalanceRefund".equals(t.getType().getCode())
332+
&& !Boolean.TRUE.equals(t.getReversed()))
333+
.reduce((first, second) -> second)
334+
.orElseThrow(() -> new IllegalStateException("Credit balance refund transaction not found"));
335+
336+
eventAssertion.assertEvent(WorkingCapitalLoanCreditBalanceRefundTransactionBusinessEvent.class, cbrTransaction.getId())//
337+
.extractingData(WorkingCapitalLoanTransactionDataV1::getWcLoanId).isEqualTo(loanId)//
338+
.extractingBigDecimal(WorkingCapitalLoanTransactionDataV1::getTransactionAmount)
339+
.isEqualTo(expectedAmount == null ? cbrTransaction.getTransactionAmount() : expectedAmount)//
340+
.extractingData(WorkingCapitalLoanTransactionDataV1::getReversed).isEqualTo(Boolean.FALSE);
341+
}
342+
321343
public void workingCapitalLoanUndoDisbursalTransactionEventCheck(final Long loanId) {
322344
workingCapitalLoanUndoDisbursalTransactionEventCheck(loanId, null);
323345
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.test.messaging.event.workingcapitalloan.transaction;
20+
21+
public class WorkingCapitalLoanCreditBalanceRefundTransactionBusinessEvent extends AbstractWorkingCapitalLoanTransactionEvent {
22+
23+
@Override
24+
public String getEventName() {
25+
return "WorkingCapitalLoanCreditBalanceRefundTransactionBusinessEvent";
26+
}
27+
}

0 commit comments

Comments
 (0)