FINERACT-2081: fix loan status on CBR reverse
This commit is contained in:
committed by
Adam Saghy
parent
c70007e30a
commit
22b10d933b
+28
-9
@@ -18,10 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanStatusChangedBusinessEvent;
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanStatusChangedBusinessEvent;
|
||||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
// TODO: introduce tests for the state machine
|
// TODO: introduce tests for the state machine
|
||||||
@@ -29,6 +32,8 @@ import org.springframework.stereotype.Component;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachine {
|
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 static final List<LoanStatus> ALLOWED_LOAN_STATUSES = List.of(LoanStatus.values());
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
@@ -40,6 +45,9 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void transition(final LoanEvent loanEvent, final Loan loan) {
|
public void transition(final LoanEvent loanEvent, final Loan loan) {
|
||||||
|
loan.updateLoanSummaryDerivedFields();
|
||||||
|
|
||||||
|
LoanStatus oldStatus = loan.getStatus();
|
||||||
LoanStatus newStatus = getNextStatus(loanEvent, loan);
|
LoanStatus newStatus = getNextStatus(loanEvent, loan);
|
||||||
if (newStatus != null) {
|
if (newStatus != null) {
|
||||||
Integer newPlainStatus = newStatus.getValue();
|
Integer newPlainStatus = newStatus.getValue();
|
||||||
@@ -51,16 +59,22 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set mandatory field states based on new status after the transition
|
// set mandatory field states based on new status after the transition
|
||||||
|
LOG.debug("Transitioning loan {} status from {} to {}", loan.getId(), oldStatus, newStatus);
|
||||||
switch (newStatus) {
|
switch (newStatus) {
|
||||||
case ACTIVE -> {
|
case SUBMITTED_AND_PENDING_APPROVAL -> {
|
||||||
if (loan.getClosedOnDate() != null) {
|
loan.setApprovedOnDate(null);
|
||||||
loan.setClosedOnDate(null);
|
loan.setApprovedBy(null);
|
||||||
}
|
|
||||||
if (loan.getOverpaidOnDate() != null) {
|
|
||||||
loan.setOverpaidOnDate(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
default -> {
|
case APPROVED -> {
|
||||||
|
loan.setDisbursedBy(null);
|
||||||
|
loan.setActualDisbursementDate(null);
|
||||||
|
}
|
||||||
|
case ACTIVE -> {
|
||||||
|
loan.setClosedBy(null);
|
||||||
|
loan.setClosedOnDate(null);
|
||||||
|
loan.setOverpaidOnDate(null);
|
||||||
|
}
|
||||||
|
default -> { // no fields need to get cleared
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +159,12 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
|||||||
case LOAN_ADJUST_TRANSACTION:
|
case LOAN_ADJUST_TRANSACTION:
|
||||||
if (anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.CLOSED_WRITTEN_OFF,
|
if (anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.CLOSED_WRITTEN_OFF,
|
||||||
LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT)) {
|
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;
|
break;
|
||||||
case LOAN_INITIATE_TRANSFER:
|
case LOAN_INITIATE_TRANSFER:
|
||||||
|
|||||||
+4
-2
@@ -1300,7 +1300,9 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
|
|
||||||
public void updateLoanSummaryDerivedFields() {
|
public void updateLoanSummaryDerivedFields() {
|
||||||
if (isNotDisbursed()) {
|
if (isNotDisbursed()) {
|
||||||
this.summary.zeroFields();
|
if (this.summary != null) {
|
||||||
|
this.summary.zeroFields();
|
||||||
|
}
|
||||||
this.totalOverpaid = null;
|
this.totalOverpaid = null;
|
||||||
} else {
|
} else {
|
||||||
final Money overpaidBy = calculateTotalOverpayment();
|
final Money overpaidBy = calculateTotalOverpayment();
|
||||||
@@ -3017,7 +3019,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LoanStatus getStatus() {
|
public LoanStatus getStatus() {
|
||||||
return LoanStatus.fromInt(this.loanStatus);
|
return this.loanStatus == null ? null : LoanStatus.fromInt(this.loanStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getPlainStatus() {
|
public Integer getPlainStatus() {
|
||||||
|
|||||||
+16
-2
@@ -245,7 +245,8 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest extend
|
|||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("loanProductFactory")
|
@MethodSource("loanProductFactory")
|
||||||
public void fullRefundChangesStatusToClosedObligationMetTest(LoanProductTestBuilder loanProductTestBuilder) {
|
public void fullRefundChangesStatusToClosedObligationMetAndSetBackToOverpayAfterReverseTest(
|
||||||
|
LoanProductTestBuilder loanProductTestBuilder) {
|
||||||
disburseLoanOfAccountingRule(ACCRUAL_PERIODIC, loanProductTestBuilder);
|
disburseLoanOfAccountingRule(ACCRUAL_PERIODIC, loanProductTestBuilder);
|
||||||
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
|
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
|
||||||
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
|
||||||
@@ -255,7 +256,8 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest extend
|
|||||||
|
|
||||||
final String creditBalanceRefundDate = "09 January 2022";
|
final String creditBalanceRefundDate = "09 January 2022";
|
||||||
final String externalId = null;
|
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,
|
loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, disbursedLoanID,
|
||||||
"status");
|
"status");
|
||||||
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
|
||||||
@@ -267,6 +269,18 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest extend
|
|||||||
totalOverpaidAtEnd = floatZero;
|
totalOverpaidAtEnd = floatZero;
|
||||||
}
|
}
|
||||||
assertEquals(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
|
@ParameterizedTest
|
||||||
|
|||||||
Reference in New Issue
Block a user