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());

Reply via email to