/** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mifosplatform.portfolio.loanaccount.domain; import java.util.List; 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) { LoanStatus newState = from; switch (loanEvent) { case LOAN_CREATED: if (from == null) { newState = stateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, this.allowedLoanStatuses); } break; case LOAN_REJECTED: if (from.hasStateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL)) { newState = stateOf(LoanStatus.REJECTED, this.allowedLoanStatuses); } break; case LOAN_APPROVED: if (from.hasStateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL)) { newState = stateOf(LoanStatus.APPROVED, this.allowedLoanStatuses); } break; case LOAN_WITHDRAWN: if (anyOfAllowedWhenComingFrom(from, LoanStatus.SUBMITTED_AND_PENDING_APPROVAL)) { newState = stateOf(LoanStatus.WITHDRAWN_BY_CLIENT, this.allowedLoanStatuses); } break; case LOAN_DISBURSED: if (from.hasStateOf(LoanStatus.APPROVED)) { newState = stateOf(LoanStatus.ACTIVE, this.allowedLoanStatuses); } break; case LOAN_APPROVAL_UNDO: if (from.hasStateOf(LoanStatus.APPROVED)) { newState = stateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, this.allowedLoanStatuses); } break; case LOAN_DISBURSAL_UNDO: if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) { newState = stateOf(LoanStatus.APPROVED, this.allowedLoanStatuses); } 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; } break; case REPAID_IN_FULL: if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.OVERPAID)) { newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET, this.allowedLoanStatuses); } break; case WRITE_OFF_OUTSTANDING: if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) { newState = stateOf(LoanStatus.CLOSED_WRITTEN_OFF, this.allowedLoanStatuses); } break; case LOAN_RESCHEDULE: if (anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) { newState = stateOf(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT, this.allowedLoanStatuses); } break; case INTERST_REBATE_OWED: if (anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET)) { newState = stateOf(LoanStatus.CLOSED_OBLIGATIONS_MET, this.allowedLoanStatuses); } break; case LOAN_OVERPAYMENT: if (anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.ACTIVE)) { newState = stateOf(LoanStatus.OVERPAID, this.allowedLoanStatuses); } break; case LOAN_CLOSED: break; case WRITE_OFF_OUTSTANDING_UNDO: break; default: break; } return newState; } private LoanStatus stateOf(final LoanStatus state, final List<LoanStatus> allowedLoanStatuses) { LoanStatus match = null; for (final LoanStatus loanStatus : allowedLoanStatuses) { if (loanStatus.hasStateOf(state)) { match = loanStatus; break; } } return match; } private boolean anyOfAllowedWhenComingFrom(final LoanStatus state, final LoanStatus... allowedStates) { boolean allowed = false; for (final LoanStatus allowedState : allowedStates) { if (state.hasStateOf(allowedState)) { allowed = true; break; } } return allowed; } }