Skip to content

Commit

Permalink
FINERACT-2081: fix loan status on CBR reverse
Browse files Browse the repository at this point in the history
  • Loading branch information
kjozsa committed Aug 9, 2024
1 parent c70007e commit 54d42f8
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,22 @@
*/
package org.apache.fineract.portfolio.loanaccount.domain;

import java.math.BigDecimal;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanStatusChangedBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

// TODO: introduce tests for the state machine
@Component
@RequiredArgsConstructor
public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachine {

private static Logger LOG = LoggerFactory.getLogger(DefaultLoanLifecycleStateMachine.class);

private static final List<LoanStatus> ALLOWED_LOAN_STATUSES = List.of(LoanStatus.values());
private final BusinessEventNotifierService businessEventNotifierService;

Expand All @@ -40,6 +45,9 @@ public LoanStatus dryTransition(final LoanEvent loanEvent, final Loan loan) {

@Override
public void transition(final LoanEvent loanEvent, final Loan loan) {
loan.updateLoanSummaryDerivedFields();

LoanStatus oldStatus = loan.getStatus();
LoanStatus newStatus = getNextStatus(loanEvent, loan);
if (newStatus != null) {
Integer newPlainStatus = newStatus.getValue();
Expand All @@ -51,16 +59,22 @@ public void transition(final LoanEvent loanEvent, final Loan loan) {
}

// set mandatory field states based on new status after the transition
LOG.debug("Transitioning loan {} status from {} to {}", loan.getId(), oldStatus, newStatus);
switch (newStatus) {
case SUBMITTED_AND_PENDING_APPROVAL -> {
loan.setApprovedOnDate(null);
loan.setApprovedBy(null);
}
case APPROVED -> {
loan.setDisbursedBy(null);
loan.setActualDisbursementDate(null);
}
case ACTIVE -> {
if (loan.getClosedOnDate() != null) {
loan.setClosedOnDate(null);
}
if (loan.getOverpaidOnDate() != null) {
loan.setOverpaidOnDate(null);
}
loan.setClosedBy(null);
loan.setClosedOnDate(null);
loan.setOverpaidOnDate(null);
}
default -> {
default -> { // no fields need to get cleared
}
}
}
Expand Down Expand Up @@ -145,7 +159,12 @@ private LoanStatus getNextStatus(LoanEvent loanEvent, Loan loan) {
case LOAN_ADJUST_TRANSACTION:
if (anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.CLOSED_WRITTEN_OFF,
LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT)) {
newState = activeTransition();
boolean isOverpaid = loan.getTotalOverpaid() != null && loan.getTotalOverpaid().compareTo(BigDecimal.ZERO) > 0;
if (isOverpaid) {
newState = overpaidTransition();
} else {
newState = activeTransition();
}
}
break;
case LOAN_INITIATE_TRANSFER:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1300,7 +1300,9 @@ public void updateLoanScheduleDependentDerivedFields() {

public void updateLoanSummaryDerivedFields() {
if (isNotDisbursed()) {
this.summary.zeroFields();
if (this.summary != null) {
this.summary.zeroFields();
}
this.totalOverpaid = null;
} else {
final Money overpaidBy = calculateTotalOverpayment();
Expand Down Expand Up @@ -3017,7 +3019,7 @@ public boolean isNotSubmittedAndPendingApproval() {
}

public LoanStatus getStatus() {
return LoanStatus.fromInt(this.loanStatus);
return this.loanStatus == null ? null : LoanStatus.fromInt(this.loanStatus);
}

public Integer getPlainStatus() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ public void cantRefundMoreThanOverpaidTest(LoanProductTestBuilder loanProductTes

@ParameterizedTest
@MethodSource("loanProductFactory")
public void fullRefundChangesStatusToClosedObligationMetTest(LoanProductTestBuilder loanProductTestBuilder) {
public void fullRefundChangesStatusToClosedObligationMetAndSetBackToOverpayAfterReverseTest(
LoanProductTestBuilder loanProductTestBuilder) {
disburseLoanOfAccountingRule(ACCRUAL_PERIODIC, loanProductTestBuilder);
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
Expand All @@ -255,7 +256,8 @@ public void fullRefundChangesStatusToClosedObligationMetTest(LoanProductTestBuil

final String creditBalanceRefundDate = "09 January 2022";
final String externalId = null;
loanTransactionHelper.creditBalanceRefund(creditBalanceRefundDate, totalOverpaid, externalId, disbursedLoanID, null);
Integer resourceId = (Integer) loanTransactionHelper.creditBalanceRefund(creditBalanceRefundDate, totalOverpaid, externalId,
disbursedLoanID, "resourceId");
loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, disbursedLoanID,
"status");
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
Expand All @@ -267,6 +269,18 @@ public void fullRefundChangesStatusToClosedObligationMetTest(LoanProductTestBuil
totalOverpaidAtEnd = floatZero;
}
assertEquals(totalOverpaidAtEnd, floatZero);

loanTransactionHelper.reverseLoanTransaction(disbursedLoanID, resourceId.longValue(), creditBalanceRefundDate, responseSpec);

loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, disbursedLoanID,
"status");

LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);

Float totalOverpaidAfterReverse = (Float) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec,
disbursedLoanID, "totalOverpaid");

assertEquals(totalOverpaidAfterReverse, totalOverpaid);
}

@ParameterizedTest
Expand Down

0 comments on commit 54d42f8

Please sign in to comment.