This is an automated email from the ASF dual-hosted git repository.
arnold 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 d003326e4 FINERACT-1734: Refactoring around Loan status changes as a
preparation to emit Loan Status change business events
d003326e4 is described below
commit d003326e48e40a66223753d58c9080541c95579b
Author: Arnold Galovics <[email protected]>
AuthorDate: Fri Sep 9 10:52:47 2022 +0200
FINERACT-1734: Refactoring around Loan status changes as a preparation to
emit Loan Status change business events
---
.../domain/DefaultLoanLifecycleStateMachine.java | 97 +++++++++++++++++-----
.../portfolio/loanaccount/domain/Loan.java | 15 +++-
.../portfolio/loanaccount/domain/LoanEvent.java | 4 +
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 23 +++--
4 files changed, 109 insertions(+), 30 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java
index be0a5cd3c..35afd16e9 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java
@@ -19,15 +19,13 @@
package org.apache.fineract.portfolio.loanaccount.domain;
import java.util.List;
+import lombok.RequiredArgsConstructor;
+@RequiredArgsConstructor
public class DefaultLoanLifecycleStateMachine implements
LoanLifecycleStateMachine {
private final List<LoanStatus> allowedLoanStatuses;
- public DefaultLoanLifecycleStateMachine(final List<LoanStatus>
allowedLoanStatuses) {
- this.allowedLoanStatuses = allowedLoanStatuses;
- }
-
@Override
public LoanStatus transition(final LoanEvent loanEvent, final LoanStatus
from) {
@@ -36,77 +34,94 @@ public class DefaultLoanLifecycleStateMachine implements
LoanLifecycleStateMachi
switch (loanEvent) {
case LOAN_CREATED:
if (from == null) {
- newState =
stateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, this.allowedLoanStatuses);
+ newState = submittedTransition();
}
break;
case LOAN_REJECTED:
if
(from.hasStateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL)) {
- newState = stateOf(LoanStatus.REJECTED,
this.allowedLoanStatuses);
+ newState = rejectedTransition();
}
break;
case LOAN_APPROVED:
if
(from.hasStateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL)) {
- newState = stateOf(LoanStatus.APPROVED,
this.allowedLoanStatuses);
+ newState = approvedTransition();
}
break;
case LOAN_WITHDRAWN:
if (anyOfAllowedWhenComingFrom(from,
LoanStatus.SUBMITTED_AND_PENDING_APPROVAL)) {
- newState = stateOf(LoanStatus.WITHDRAWN_BY_CLIENT,
this.allowedLoanStatuses);
+ newState = withdrawnByClientTransition();
}
break;
case LOAN_DISBURSED:
if (anyOfAllowedWhenComingFrom(from, LoanStatus.APPROVED,
LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.OVERPAID)) {
- newState = stateOf(LoanStatus.ACTIVE,
this.allowedLoanStatuses);
+ newState = activeTransition();
}
break;
case LOAN_APPROVAL_UNDO:
if (from.hasStateOf(LoanStatus.APPROVED)) {
- newState =
stateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, this.allowedLoanStatuses);
+ newState = submittedTransition();
}
break;
case LOAN_DISBURSAL_UNDO:
if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
- newState = stateOf(LoanStatus.APPROVED,
this.allowedLoanStatuses);
+ newState = approvedTransition();
}
break;
case LOAN_CHARGE_PAYMENT:
case LOAN_REPAYMENT_OR_WAIVER:
if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE,
LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.OVERPAID)) {
- newState = stateOf(LoanStatus.ACTIVE,
this.allowedLoanStatuses);
- } else {
- newState = from;
+ newState = activeTransition();
}
break;
case REPAID_IN_FULL:
if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE,
LoanStatus.OVERPAID)) {
- newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET,
this.allowedLoanStatuses);
+ newState = closeObligationsMetTransition();
}
break;
case WRITE_OFF_OUTSTANDING:
if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
- newState = stateOf(LoanStatus.CLOSED_WRITTEN_OFF,
this.allowedLoanStatuses);
+ newState = closedWrittenOffTransition();
}
break;
case LOAN_RESCHEDULE:
if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) {
- newState =
stateOf(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT,
this.allowedLoanStatuses);
+ newState = closedRescheduleOutstandingAmountTransition();
}
break;
case INTERST_REBATE_OWED:
if (anyOfAllowedWhenComingFrom(from,
LoanStatus.CLOSED_OBLIGATIONS_MET)) {
- newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET,
this.allowedLoanStatuses);
+ newState = closeObligationsMetTransition();
}
break;
case LOAN_OVERPAYMENT:
if (anyOfAllowedWhenComingFrom(from,
LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.ACTIVE)) {
- newState = stateOf(LoanStatus.OVERPAID,
this.allowedLoanStatuses);
+ newState = overpaidTransition();
+ }
+ break;
+ case LOAN_ADJUST_TRANSACTION:
+ if (anyOfAllowedWhenComingFrom(from,
LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.CLOSED_WRITTEN_OFF,
+ LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT)) {
+ newState = activeTransition();
}
break;
+ case LOAN_INITIATE_TRANSFER:
+ newState = transferInProgress();
+ break;
+ case LOAN_REJECT_TRANSFER:
+ newState = transferOnHold();
+ break;
+ case LOAN_WITHDRAW_TRANSFER:
+ newState = activeTransition();
+ break;
case LOAN_CLOSED:
break;
case WRITE_OFF_OUTSTANDING_UNDO:
+ if (anyOfAllowedWhenComingFrom(from,
LoanStatus.CLOSED_WRITTEN_OFF)) {
+ newState = activeTransition();
+ }
break;
case LOAN_CREDIT_BALANCE_REFUND:
+ newState = closeObligationsMetTransition();
break;
default:
break;
@@ -115,6 +130,50 @@ public class DefaultLoanLifecycleStateMachine implements
LoanLifecycleStateMachi
return newState;
}
+ private LoanStatus transferOnHold() {
+ return stateOf(LoanStatus.TRANSFER_ON_HOLD, this.allowedLoanStatuses);
+ }
+
+ private LoanStatus transferInProgress() {
+ return stateOf(LoanStatus.TRANSFER_IN_PROGRESS,
this.allowedLoanStatuses);
+ }
+
+ private LoanStatus overpaidTransition() {
+ return stateOf(LoanStatus.OVERPAID, this.allowedLoanStatuses);
+ }
+
+ private LoanStatus closedRescheduleOutstandingAmountTransition() {
+ return stateOf(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT,
this.allowedLoanStatuses);
+ }
+
+ private LoanStatus closedWrittenOffTransition() {
+ return stateOf(LoanStatus.CLOSED_WRITTEN_OFF,
this.allowedLoanStatuses);
+ }
+
+ private LoanStatus closeObligationsMetTransition() {
+ return stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET,
this.allowedLoanStatuses);
+ }
+
+ private LoanStatus activeTransition() {
+ return stateOf(LoanStatus.ACTIVE, this.allowedLoanStatuses);
+ }
+
+ private LoanStatus withdrawnByClientTransition() {
+ return stateOf(LoanStatus.WITHDRAWN_BY_CLIENT,
this.allowedLoanStatuses);
+ }
+
+ private LoanStatus approvedTransition() {
+ return stateOf(LoanStatus.APPROVED, this.allowedLoanStatuses);
+ }
+
+ private LoanStatus rejectedTransition() {
+ return stateOf(LoanStatus.REJECTED, this.allowedLoanStatuses);
+ }
+
+ private LoanStatus submittedTransition() {
+ return stateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL,
this.allowedLoanStatuses);
+ }
+
private LoanStatus stateOf(final LoanStatus state, final List<LoanStatus>
allowedLoanStatuses) {
LoanStatus match = null;
for (final LoanStatus loanStatus : allowedLoanStatuses) {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 95088b15e..cb41f4d1c 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -3635,7 +3635,9 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
}
if (isClosedObligationsMet() || isClosedWrittenOff() ||
isClosedWithOutsandingAmountMarkedForReschedule()) {
- this.loanStatus = LoanStatus.ACTIVE.getValue();
+ LoanStatus loanStatusEnum =
loanLifecycleStateMachine.transition(LoanEvent.LOAN_ADJUST_TRANSACTION,
+ LoanStatus.fromInt(this.loanStatus));
+ this.loanStatus = loanStatusEnum.getValue();
}
if (newTransactionDetail.isRepaymentType() ||
newTransactionDetail.isInterestWaiver()) {
@@ -3646,7 +3648,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
return changedTransactionDetail;
}
- public ChangedTransactionDetail undoWrittenOff(final List<Long>
existingTransactionIds, final List<Long> existingReversedTransactionIds,
+ public ChangedTransactionDetail undoWrittenOff(LoanLifecycleStateMachine
loanLifecycleStateMachine,
+ final List<Long> existingTransactionIds, final List<Long>
existingReversedTransactionIds,
final ScheduleGeneratorDTO scheduleGeneratorDTO) {
validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO);
@@ -3654,7 +3657,9 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final LoanTransaction writeOffTransaction = findWriteOffTransaction();
writeOffTransaction.reverse();
- this.loanStatus = LoanStatus.ACTIVE.getValue();
+ LoanStatus loanStatusEnum =
loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO,
+ LoanStatus.fromInt(this.loanStatus));
+ this.loanStatus = loanStatusEnum.getValue();
final LoanRepaymentScheduleTransactionProcessor
loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement =
retreiveListOfTransactionsPostDisbursement();
@@ -6068,7 +6073,9 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
updateLoanSummaryDerivedFields();
if (this.totalOverpaid == null ||
BigDecimal.ZERO.compareTo(this.totalOverpaid) == 0) {
- this.loanStatus = LoanStatus.CLOSED_OBLIGATIONS_MET.getValue();
+ LoanStatus statusEnum =
defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_CREDIT_BALANCE_REFUND,
+ LoanStatus.fromInt(this.loanStatus));
+ this.loanStatus = statusEnum.getValue();
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanEvent.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanEvent.java
index 7db08e3b1..9d7f1dfba 100755
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanEvent.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanEvent.java
@@ -44,5 +44,9 @@ public enum LoanEvent {
LOAN_EDIT_MULTI_DISBURSE_DATE, //
LOAN_REFUND, //
LOAN_FORECLOSURE, //
+ LOAN_ADJUST_TRANSACTION, //
+ LOAN_INITIATE_TRANSFER, //
+ LOAN_REJECT_TRANSFER, //
+ LOAN_WITHDRAW_TRANSFER, //
LOAN_CREDIT_BALANCE_REFUND;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 2d576c805..248f7e3d4 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -2260,7 +2260,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
final LoanTransaction newTransferTransaction =
LoanTransaction.initiateTransfer(loan.getOffice(), loan, transferDate);
loan.addLoanTransaction(newTransferTransaction);
- loan.setLoanStatus(LoanStatus.TRANSFER_IN_PROGRESS.getValue());
+ LoanLifecycleStateMachine loanLifecycleStateMachine =
defaultLoanLifecycleStateMachine();
+ LoanStatus loanStatusEnum =
loanLifecycleStateMachine.transition(LoanEvent.LOAN_INITIATE_TRANSFER,
loan.status());
+ loan.setLoanStatus(loanStatusEnum.getValue());
this.loanTransactionRepository.saveAndFlush(newTransferTransaction);
saveLoanWithDataIntegrityViolationChecks(loan);
@@ -2281,11 +2283,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
final LoanTransaction newTransferAcceptanceTransaction =
LoanTransaction.approveTransfer(acceptedInOffice, loan, transferDate);
loan.addLoanTransaction(newTransferAcceptanceTransaction);
+ LoanLifecycleStateMachine loanLifecycleStateMachine =
defaultLoanLifecycleStateMachine();
+ LoanStatus loanStatusEnum;
if (loan.getTotalOverpaid() != null) {
- loan.setLoanStatus(LoanStatus.OVERPAID.getValue());
+ loanStatusEnum =
loanLifecycleStateMachine.transition(LoanEvent.LOAN_OVERPAYMENT, loan.status());
} else {
- loan.setLoanStatus(LoanStatus.ACTIVE.getValue());
+ loanStatusEnum =
loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
loan.status());
}
+ loan.setLoanStatus(loanStatusEnum.getValue());
if (loanOfficer != null) {
loan.reassignLoanOfficer(loanOfficer, transferDate);
}
@@ -2310,7 +2315,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
final LoanTransaction newTransferAcceptanceTransaction =
LoanTransaction.withdrawTransfer(loan.getOffice(), loan, transferDate);
loan.addLoanTransaction(newTransferAcceptanceTransaction);
- loan.setLoanStatus(LoanStatus.ACTIVE.getValue());
+ LoanLifecycleStateMachine loanLifecycleStateMachine =
defaultLoanLifecycleStateMachine();
+ LoanStatus loanStatusEnum =
loanLifecycleStateMachine.transition(LoanEvent.LOAN_WITHDRAW_TRANSFER,
loan.status());
+ loan.setLoanStatus(loanStatusEnum.getValue());
this.loanTransactionRepository.saveAndFlush(newTransferAcceptanceTransaction);
saveLoanWithDataIntegrityViolationChecks(loan);
@@ -2326,7 +2333,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
public void rejectLoanTransfer(final Loan loan) {
this.loanAssembler.setHelpers(loan);
businessEventNotifierService.notifyPreBusinessEvent(new
LoanRejectTransferBusinessEvent(loan));
- loan.setLoanStatus(LoanStatus.TRANSFER_ON_HOLD.getValue());
+ LoanLifecycleStateMachine loanLifecycleStateMachine =
defaultLoanLifecycleStateMachine();
+ LoanStatus loanStatusEnum =
loanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECT_TRANSFER,
loan.status());
+ loan.setLoanStatus(loanStatusEnum.getValue());
saveLoanWithDataIntegrityViolationChecks(loan);
businessEventNotifierService.notifyPostBusinessEvent(new
LoanRejectTransferBusinessEvent(loan));
}
@@ -2857,8 +2866,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
ScheduleGeneratorDTO scheduleGeneratorDTO =
this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
- ChangedTransactionDetail changedTransactionDetail =
loan.undoWrittenOff(existingTransactionIds, existingReversedTransactionIds,
- scheduleGeneratorDTO);
+ ChangedTransactionDetail changedTransactionDetail =
loan.undoWrittenOff(defaultLoanLifecycleStateMachine(), existingTransactionIds,
+ existingReversedTransactionIds, scheduleGeneratorDTO);
if (changedTransactionDetail != null) {
for (final Map.Entry<Long, LoanTransaction> mapEntry :
changedTransactionDetail.getNewTransactionMappings().entrySet()) {
this.loanTransactionRepository.save(mapEntry.getValue());