drop loan status table in favour of enum for now.

This commit is contained in:
Keith Woodlock
2012-08-16 19:40:03 +01:00
parent 9fe9a091c9
commit abb4ec17dc
11 changed files with 212 additions and 180 deletions
@@ -0,0 +1,6 @@
ALTER TABLE `portfolio_loan` DROP FOREIGN KEY `FK7C885878B1147D1`;
ALTER TABLE `portfolio_loan` DROP INDEX `FK7C885878B1147D1`;
drop table `ref_loan_status`;
@@ -242,10 +242,9 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
"l.id as id, l.external_id as externalId,"); "l.id as id, l.external_id as externalId,");
loanAccountSummary loanAccountSummary
.append("l.product_id as productId, lp.name as productName,") .append("l.product_id as productId, lp.name as productName,")
.append("l.loan_status_id as statusId, ls.display_name as statusName ") .append("l.loan_status_id as statusId ")
.append("from portfolio_loan l ") .append("from portfolio_loan l ")
.append("LEFT JOIN portfolio_product_loan AS lp ON lp.id = l.product_id ") .append("LEFT JOIN portfolio_product_loan AS lp ON lp.id = l.product_id ");
.append("LEFT JOIN ref_loan_status AS ls ON ls.id = l.loan_status_id ");
return loanAccountSummary.toString(); return loanAccountSummary.toString();
} }
@@ -2,87 +2,86 @@ package org.mifosng.platform.loan.domain;
import java.util.List; import java.util.List;
public class DefaultLoanLifecycleStateMachine implements public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachine {
LoanLifecycleStateMachine {
private final List<LoanStatus> allowedLoanStatuses; private final List<LoanStatusEnum> allowedLoanStatuses;
public DefaultLoanLifecycleStateMachine(List<LoanStatus> allowedLoanStatuses) { public DefaultLoanLifecycleStateMachine(List<LoanStatusEnum> allowedLoanStatuses) {
this.allowedLoanStatuses = allowedLoanStatuses; this.allowedLoanStatuses = allowedLoanStatuses;
} }
@Override @Override
public LoanStatus transition(LoanEvent loanEvent, LoanStatus from) { public LoanStatusEnum transition(LoanEvent loanEvent, LoanStatusEnum from) {
LoanStatus newState = null; LoanStatusEnum newState = null;
switch (loanEvent) { switch (loanEvent) {
case LOAN_CREATED: case LOAN_CREATED:
if (from == null) { if (from == null) {
newState = stateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL, newState = stateOf(LoanStatusEnum.SUBMITED_AND_PENDING_APPROVAL,
allowedLoanStatuses); allowedLoanStatuses);
} }
break; break;
case LOAN_REJECTED: case LOAN_REJECTED:
if (from.hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL)) { if (from.hasStateOf(LoanStatusEnum.SUBMITED_AND_PENDING_APPROVAL)) {
newState = stateOf(LoanStatus.REJECTED, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.REJECTED, allowedLoanStatuses);
} }
break; break;
case LOAN_APPROVED: case LOAN_APPROVED:
if (from.hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL)) { if (from.hasStateOf(LoanStatusEnum.SUBMITED_AND_PENDING_APPROVAL)) {
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.APPROVED, allowedLoanStatuses);
} }
break; break;
case LOAN_WITHDRAWN: case LOAN_WITHDRAWN:
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.SUBMITED_AND_PENDING_APPROVAL, LoanStatus.APPROVED)) { if (this.anyOfAllowedWhenComingFrom(from, LoanStatusEnum.SUBMITED_AND_PENDING_APPROVAL, LoanStatusEnum.APPROVED)) {
newState = stateOf(LoanStatus.WITHDRAWN_BY_CLIENT, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.WITHDRAWN_BY_CLIENT, allowedLoanStatuses);
} }
break; break;
case LOAN_DISBURSED: case LOAN_DISBURSED:
if (from.hasStateOf(LoanStatus.APPROVED)) { if (from.hasStateOf(LoanStatusEnum.APPROVED)) {
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.ACTIVE, allowedLoanStatuses);
} }
break; break;
case LOAN_APPROVAL_UNDO: case LOAN_APPROVAL_UNDO:
if (from.hasStateOf(LoanStatus.APPROVED)) { if (from.hasStateOf(LoanStatusEnum.APPROVED)) {
newState = stateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.SUBMITED_AND_PENDING_APPROVAL, allowedLoanStatuses);
} }
break; break;
case LOAN_DISBURSAL_UNDO: case LOAN_DISBURSAL_UNDO:
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) { if (this.anyOfAllowedWhenComingFrom(from, LoanStatusEnum.ACTIVE)) {
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.APPROVED, allowedLoanStatuses);
} }
break; break;
case LOAN_REPAYMENT: case LOAN_REPAYMENT:
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.CLOSED, LoanStatus.OVERPAID)) { if (this.anyOfAllowedWhenComingFrom(from, LoanStatusEnum.ACTIVE, LoanStatusEnum.CLOSED, LoanStatusEnum.OVERPAID)) {
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.ACTIVE, allowedLoanStatuses);
} else { } else {
newState = from; newState = from;
} }
break; break;
case REPAID_IN_FULL: case REPAID_IN_FULL:
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) { if (this.anyOfAllowedWhenComingFrom(from, LoanStatusEnum.ACTIVE)) {
newState = stateOf(LoanStatus.CLOSED, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.CLOSED, allowedLoanStatuses);
} }
break; break;
case LOAN_WRITE_OFF: case LOAN_WRITE_OFF:
if (this.anyOfAllowedWhenComingFrom(from,LoanStatus.ACTIVE)) { if (this.anyOfAllowedWhenComingFrom(from,LoanStatusEnum.ACTIVE)) {
newState = stateOf(LoanStatus.CLOSED, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.CLOSED, allowedLoanStatuses);
} }
break; break;
case LOAN_RESCHEDULE: case LOAN_RESCHEDULE:
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE)) { if (this.anyOfAllowedWhenComingFrom(from, LoanStatusEnum.ACTIVE)) {
newState = stateOf(LoanStatus.CLOSED, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.CLOSED, allowedLoanStatuses);
} }
break; break;
case INTERST_REBATE_OWED: case INTERST_REBATE_OWED:
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED)) { if (this.anyOfAllowedWhenComingFrom(from, LoanStatusEnum.CLOSED)) {
newState = stateOf(LoanStatus.CLOSED, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.CLOSED, allowedLoanStatuses);
} }
break; break;
case LOAN_OVERPAYMENT: case LOAN_OVERPAYMENT:
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED, LoanStatus.ACTIVE)) { if (this.anyOfAllowedWhenComingFrom(from, LoanStatusEnum.CLOSED, LoanStatusEnum.ACTIVE)) {
newState = stateOf(LoanStatus.OVERPAID, allowedLoanStatuses); newState = stateOf(LoanStatusEnum.OVERPAID, allowedLoanStatuses);
} }
break; break;
} }
@@ -90,9 +89,9 @@ public class DefaultLoanLifecycleStateMachine implements
return newState; return newState;
} }
private LoanStatus stateOf(Integer state, List<LoanStatus> allowedLoanStatuses) { private LoanStatusEnum stateOf(LoanStatusEnum state, List<LoanStatusEnum> allowedLoanStatuses) {
LoanStatus match = null; LoanStatusEnum match = null;
for (LoanStatus loanStatus : allowedLoanStatuses) { for (LoanStatusEnum loanStatus : allowedLoanStatuses) {
if (loanStatus.hasStateOf(state)) { if (loanStatus.hasStateOf(state)) {
match = loanStatus; match = loanStatus;
break; break;
@@ -101,11 +100,11 @@ public class DefaultLoanLifecycleStateMachine implements
return match; return match;
} }
private boolean anyOfAllowedWhenComingFrom(final LoanStatus state, private boolean anyOfAllowedWhenComingFrom(final LoanStatusEnum state,
final Integer... allowedStates) { final LoanStatusEnum... allowedStates) {
boolean allowed = false; boolean allowed = false;
for (Integer allowedState : allowedStates) { for (LoanStatusEnum allowedState : allowedStates) {
if (state.hasStateOf(allowedState)) { if (state.hasStateOf(allowedState)) {
allowed = true; allowed = true;
break; break;
@@ -114,5 +113,4 @@ public class DefaultLoanLifecycleStateMachine implements
return allowed; return allowed;
} }
} }
@@ -72,9 +72,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "term_period_frequency_enum", nullable = false) @Column(name = "term_period_frequency_enum", nullable = false)
private PeriodFrequencyType termPeriodFrequencyType; private PeriodFrequencyType termPeriodFrequencyType;
@ManyToOne @Column(name = "loan_status_id", nullable = false)
@JoinColumn(name = "loan_status_id", nullable = false) private Integer loanStatus;
private LoanStatus loanStatus;
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@Column(name = "submittedon_date") @Column(name = "submittedon_date")
@@ -165,13 +164,17 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public Loan(final Client client, Fund fund, LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, public Loan(final Client client, Fund fund, LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct,
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanProductRelatedDetail loanRepaymentScheduleDetail,
final LoanStatus loanStatus) { final LoanStatusEnum loanStatus) {
this.client = client; this.client = client;
this.fund = fund; this.fund = fund;
this.transactionProcessingStrategy = transactionProcessingStrategy; this.transactionProcessingStrategy = transactionProcessingStrategy;
this.loanProduct = loanProduct; this.loanProduct = loanProduct;
this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail; this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
this.loanStatus = loanStatus; if (loanStatus != null) {
this.loanStatus = loanStatus.getValue();
} else {
this.loanStatus = null;
}
this.interestRebateOwed = BigDecimal.ZERO; this.interestRebateOwed = BigDecimal.ZERO;
} }
@@ -200,7 +203,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
final LocalDate interestChargedFromDate, final LocalDate interestChargedFromDate,
final LoanLifecycleStateMachine lifecycleStateMachine) { final LoanLifecycleStateMachine lifecycleStateMachine) {
this.loanStatus = lifecycleStateMachine.transition(LoanEvent.LOAN_CREATED, this.loanStatus); LoanStatusEnum statusEnum = lifecycleStateMachine.transition(LoanEvent.LOAN_CREATED, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.termFrequency = loanTermFrequency; this.termFrequency = loanTermFrequency;
this.termPeriodFrequencyType = loanTermFrequencyType; this.termPeriodFrequencyType = loanTermFrequencyType;
@@ -245,8 +249,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public void reject(final LocalDate rejectedOn, public void reject(final LocalDate rejectedOn,
LoanLifecycleStateMachine loanLifecycleStateMachine) { LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition( LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECTED, LoanStatusEnum.fromInt(this.loanStatus));
LoanEvent.LOAN_REJECTED, this.loanStatus); this.loanStatus = statusEnum.getValue();
this.rejectedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate(); this.rejectedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate();
this.closedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate(); this.closedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate();
@@ -268,8 +272,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public void withdraw(final LocalDate withdrawnOn, public void withdraw(final LocalDate withdrawnOn,
LoanLifecycleStateMachine loanLifecycleStateMachine) { LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition( LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_WITHDRAWN, LoanStatusEnum.fromInt(this.loanStatus));
LoanEvent.LOAN_WITHDRAWN, this.loanStatus); this.loanStatus = statusEnum.getValue();
this.withdrawnOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate(); this.withdrawnOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate();
this.closedOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate(); this.closedOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate();
@@ -290,8 +294,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public void approve(final LocalDate approvedOn, public void approve(final LocalDate approvedOn,
LoanLifecycleStateMachine loanLifecycleStateMachine) { LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(
LoanEvent.LOAN_APPROVED, this.loanStatus); LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.approvedOnDate = approvedOn.toDateTimeAtCurrentTime().toDate(); this.approvedOnDate = approvedOn.toDateTimeAtCurrentTime().toDate();
LocalDate submittalDate = new LocalDate(this.submittedOnDate); LocalDate submittalDate = new LocalDate(this.submittedOnDate);
@@ -311,8 +317,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} }
public void undoApproval(LoanLifecycleStateMachine loanLifecycleStateMachine) { public void undoApproval(LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(
LoanEvent.LOAN_APPROVAL_UNDO, this.loanStatus); LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVAL_UNDO, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.approvedOnDate = null; this.approvedOnDate = null;
} }
@@ -330,8 +338,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public void disburse(final LocalDate disbursedOn, public void disburse(final LocalDate disbursedOn,
LoanLifecycleStateMachine loanLifecycleStateMachine) { LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(
LoanEvent.LOAN_DISBURSED, this.loanStatus); LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.disbursedOnDate = disbursedOn.toDateTimeAtCurrentTime().toDate(); this.disbursedOnDate = disbursedOn.toDateTimeAtCurrentTime().toDate();
this.expectedMaturityDate = this.repaymentScheduleInstallments this.expectedMaturityDate = this.repaymentScheduleInstallments
.get(this.repaymentScheduleInstallments.size() - 1) .get(this.repaymentScheduleInstallments.size() - 1)
@@ -369,14 +379,19 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public void undoDisbursal( public void undoDisbursal(
LoanLifecycleStateMachine loanLifecycleStateMachine) { LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(
LoanEvent.LOAN_DISBURSAL_UNDO, this.loanStatus); LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.loanTransactions.clear(); this.loanTransactions.clear();
this.disbursedOnDate = null; this.disbursedOnDate = null;
} }
public void waive(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) { public void waive(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT, this.loanStatus);
LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
loanTransaction.updateLoan(this); loanTransaction.updateLoan(this);
this.loanTransactions.add(loanTransaction); this.loanTransactions.add(loanTransaction);
@@ -424,7 +439,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
private void handleRepaymentTransaction( private void handleRepaymentTransaction(
final LoanTransaction loanTransaction, final LoanTransaction loanTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final boolean adjusted) { final LoanLifecycleStateMachine loanLifecycleStateMachine, final boolean adjusted) {
this.loanStatus = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT, this.loanStatus);
LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
loanTransaction.updateLoan(this); loanTransaction.updateLoan(this);
boolean isTransactionChronologicallyLatest = isChronologicallyLatestRepaymentOrWaiver(loanTransaction, this.loanTransactions); boolean isTransactionChronologicallyLatest = isChronologicallyLatestRepaymentOrWaiver(loanTransaction, this.loanTransactions);
@@ -482,21 +500,29 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} }
private void handleLoanRepaymentInFull(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) { private void handleLoanRepaymentInFull(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, this.loanStatus);
LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.closedOnDate = loanTransaction.getTransactionDate().toDate(); this.closedOnDate = loanTransaction.getTransactionDate().toDate();
this.maturedOnDate = loanTransaction.getTransactionDate().toDate(); this.maturedOnDate = loanTransaction.getTransactionDate().toDate();
if (isInterestRebateAllowed()) { if (isInterestRebateAllowed()) {
Money rebateDue = calculateRebateWhenPaidInFullOn(loanTransaction.getTransactionDate()); Money rebateDue = calculateRebateWhenPaidInFullOn(loanTransaction.getTransactionDate());
if (rebateDue.isGreaterThanZero()) { if (rebateDue.isGreaterThanZero()) {
this.loanStatus = loanLifecycleStateMachine.transition(LoanEvent.INTERST_REBATE_OWED, this.loanStatus); statusEnum = loanLifecycleStateMachine.transition(LoanEvent.INTERST_REBATE_OWED, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.interestRebateOwed = rebateDue.getAmount(); this.interestRebateOwed = rebateDue.getAmount();
} }
} }
} }
private void handleLoanOverpayment(@SuppressWarnings("unused") final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) { private void handleLoanOverpayment(@SuppressWarnings("unused") final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(LoanEvent.LOAN_OVERPAYMENT, this.loanStatus);
LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_OVERPAYMENT, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.closedOnDate = null; this.closedOnDate = null;
this.maturedOnDate = null; this.maturedOnDate = null;
} }
@@ -635,8 +661,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public void writeOff(final DateTime writtenOffOn, public void writeOff(final DateTime writtenOffOn,
final LoanLifecycleStateMachine loanLifecycleStateMachine) { final LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(
LoanEvent.LOAN_WRITE_OFF, this.loanStatus); LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_WRITE_OFF, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.closedOnDate = writtenOffOn.toDate(); this.closedOnDate = writtenOffOn.toDate();
this.writtenOffOnDate = writtenOffOn.toDate(); this.writtenOffOnDate = writtenOffOn.toDate();
@@ -658,8 +686,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public void reschedule(final DateTime rescheduledOn, public void reschedule(final DateTime rescheduledOn,
final LoanLifecycleStateMachine loanLifecycleStateMachine) { final LoanLifecycleStateMachine loanLifecycleStateMachine) {
this.loanStatus = loanLifecycleStateMachine.transition(
LoanEvent.LOAN_RESCHEDULE, this.loanStatus); LoanStatusEnum statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RESCHEDULE, LoanStatusEnum.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.closedOnDate = rescheduledOn.toDate(); this.closedOnDate = rescheduledOn.toDate();
this.rescheduledOnDate = rescheduledOn.toDate(); this.rescheduledOnDate = rescheduledOn.toDate();
@@ -683,12 +713,16 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return !isSubmittedAndPendingApproval(); return !isSubmittedAndPendingApproval();
} }
private LoanStatusEnum status() {
return LoanStatusEnum.fromInt(this.loanStatus);
}
public boolean isSubmittedAndPendingApproval() { public boolean isSubmittedAndPendingApproval() {
return this.loanStatus.isSubmittedAndPendingApproval(); return status().isSubmittedAndPendingApproval();
} }
public boolean isApproved() { public boolean isApproved() {
return this.loanStatus.isApproved(); return status().isApproved();
} }
public boolean isNotApproved() { public boolean isNotApproved() {
@@ -712,7 +746,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} }
public boolean isClosed() { public boolean isClosed() {
return this.loanStatus.isClosed() || this.isCancelled(); return status().isClosed() || this.isCancelled();
} }
public boolean isCancelled() { public boolean isCancelled() {
@@ -720,11 +754,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} }
public boolean isWithdrawn() { public boolean isWithdrawn() {
return this.loanStatus.isWithdrawnByClient(); return status().isWithdrawnByClient();
} }
public boolean isRejected() { public boolean isRejected() {
return this.loanStatus.isRejected(); return status().isRejected();
} }
public boolean isNotClosed() { public boolean isNotClosed() {
@@ -732,7 +766,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} }
public boolean isOpen() { public boolean isOpen() {
return this.loanStatus.isActive(); return status().isActive();
} }
public boolean isOpenWithNoRepaymentMade() { public boolean isOpenWithNoRepaymentMade() {
@@ -1031,10 +1065,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|| identifier.equalsIgnoreCase(this.getId().toString()); || identifier.equalsIgnoreCase(this.getId().toString());
} }
public String getLoanStatusDisplayName() {
return this.loanStatus.getDisplayName();
}
public MonetaryCurrency getCurrency() { public MonetaryCurrency getCurrency() {
return this.loanRepaymentScheduleDetail.getCurrency(); return this.loanRepaymentScheduleDetail.getCurrency();
} }
@@ -2,6 +2,6 @@ package org.mifosng.platform.loan.domain;
public interface LoanLifecycleStateMachine { public interface LoanLifecycleStateMachine {
LoanStatus transition(LoanEvent loanEvent, LoanStatus from); LoanStatusEnum transition(LoanEvent loanEvent, LoanStatusEnum from);
} }
@@ -1,73 +0,0 @@
package org.mifosng.platform.loan.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.data.domain.Persistable;
@Entity
@Table(name = "ref_loan_status")
public class LoanStatus implements Persistable<Integer> {
public static final Integer SUBMITED_AND_PENDING_APPROVAL = 100;
public static final Integer APPROVED = 200;
public static final Integer ACTIVE = 300;
public static final Integer WITHDRAWN_BY_CLIENT = 400;
public static final Integer REJECTED = 500;
public static final Integer CLOSED = 600;
public static final Integer OVERPAID = 700;
@Id
@Column(name = "id")
private Integer id;
@Column(name = "display_name")
private String displayName;
public LoanStatus() {
}
public String getDisplayName() {
return this.displayName;
}
@Override
public Integer getId() {
return null;
}
@Override
public boolean isNew() {
return false;
}
public boolean hasStateOf(Integer state) {
return this.id.equals(state);
}
public boolean isSubmittedAndPendingApproval() {
return hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL);
}
public boolean isApproved() {
return hasStateOf(LoanStatus.APPROVED);
}
public boolean isClosed() {
return hasStateOf(LoanStatus.CLOSED);
}
public boolean isWithdrawnByClient() {
return hasStateOf(LoanStatus.WITHDRAWN_BY_CLIENT);
}
public boolean isRejected() {
return hasStateOf(LoanStatus.REJECTED);
}
public boolean isActive() {
return hasStateOf(LoanStatus.ACTIVE);
}
}
@@ -0,0 +1,86 @@
package org.mifosng.platform.loan.domain;
public enum LoanStatusEnum {
INVALID(0, "loanStatusType.invalid"), //
SUBMITED_AND_PENDING_APPROVAL(100, "loanStatusType.submitted.and.pending.approval"), //
APPROVED(200, "loanStatusType.approved"), //
ACTIVE(300, "loanStatusType.active"), //
WITHDRAWN_BY_CLIENT(400, "loanStatusType.withdrawn.by.client"), //
REJECTED(500, "loanStatusType.rejected"), //
CLOSED(600, "loanStatusType.closed"), //
OVERPAID(700, "loanStatusType.overpaid");
private final Integer value;
private final String code;
public static LoanStatusEnum fromInt(final Integer selectedMethod) {
LoanStatusEnum enumeration = LoanStatusEnum.INVALID;
switch (selectedMethod) {
case 100:
enumeration = LoanStatusEnum.SUBMITED_AND_PENDING_APPROVAL;
break;
case 200:
enumeration = LoanStatusEnum.APPROVED;
break;
case 300:
enumeration = LoanStatusEnum.ACTIVE;
break;
case 400:
enumeration = LoanStatusEnum.WITHDRAWN_BY_CLIENT;
break;
case 500:
enumeration = LoanStatusEnum.REJECTED;
break;
case 600:
enumeration = LoanStatusEnum.CLOSED;
break;
case 700:
enumeration = LoanStatusEnum.OVERPAID;
break;
}
return enumeration;
}
private LoanStatusEnum(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public boolean hasStateOf(final LoanStatusEnum state) {
return this.value.equals(state.getValue());
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return code;
}
public boolean isSubmittedAndPendingApproval() {
return this.value.equals(LoanStatusEnum.SUBMITED_AND_PENDING_APPROVAL.getValue());
}
public boolean isApproved() {
return this.value.equals(LoanStatusEnum.APPROVED.getValue());
}
public boolean isActive() {
return this.value.equals(LoanStatusEnum.ACTIVE.getValue());
}
public boolean isClosed() {
return this.value.equals(LoanStatusEnum.CLOSED.getValue());
}
public boolean isWithdrawnByClient() {
return this.value.equals(LoanStatusEnum.WITHDRAWN_BY_CLIENT.getValue());
}
public boolean isRejected() {
return this.value.equals(LoanStatusEnum.REJECTED.getValue());
}
}
@@ -1,8 +0,0 @@
package org.mifosng.platform.loan.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface LoanStatusRepository extends JpaRepository<LoanStatus, Long>, JpaSpecificationExecutor<LoanStatus> {
// no added behaviour
}
@@ -1,6 +1,7 @@
package org.mifosng.platform.loan.service; package org.mifosng.platform.loan.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.mifosng.platform.api.commands.SubmitLoanApplicationCommand; import org.mifosng.platform.api.commands.SubmitLoanApplicationCommand;
@@ -26,8 +27,7 @@ import org.mifosng.platform.loan.domain.LoanProduct;
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail; import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
import org.mifosng.platform.loan.domain.LoanProductRepository; import org.mifosng.platform.loan.domain.LoanProductRepository;
import org.mifosng.platform.loan.domain.LoanRepaymentScheduleInstallment; import org.mifosng.platform.loan.domain.LoanRepaymentScheduleInstallment;
import org.mifosng.platform.loan.domain.LoanStatus; import org.mifosng.platform.loan.domain.LoanStatusEnum;
import org.mifosng.platform.loan.domain.LoanStatusRepository;
import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategy; import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategy;
import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategyRepository; import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategyRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loan.domain.PeriodFrequencyType;
@@ -38,7 +38,6 @@ import org.springframework.stereotype.Service;
@Service @Service
public class LoanAssembler { public class LoanAssembler {
private final LoanStatusRepository loanStatusRepository;
private final LoanProductRepository loanProductRepository; private final LoanProductRepository loanProductRepository;
private final ClientRepository clientRepository; private final ClientRepository clientRepository;
private final AprCalculator aprCalculator = new AprCalculator(); private final AprCalculator aprCalculator = new AprCalculator();
@@ -46,12 +45,11 @@ public class LoanAssembler {
private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository;
@Autowired @Autowired
public LoanAssembler(final LoanStatusRepository loanStatusRepository, public LoanAssembler(
final LoanProductRepository loanProductRepository, final LoanProductRepository loanProductRepository,
final ClientRepository clientRepository, final ClientRepository clientRepository,
final FundRepository fundRepository, final FundRepository fundRepository,
final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository) { final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository) {
this.loanStatusRepository = loanStatusRepository;
this.loanProductRepository = loanProductRepository; this.loanProductRepository = loanProductRepository;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.fundRepository = fundRepository; this.fundRepository = fundRepository;
@@ -123,7 +121,7 @@ public class LoanAssembler {
} }
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
List<LoanStatus> allowedLoanStatuses = this.loanStatusRepository.findAll(); List<LoanStatusEnum> allowedLoanStatuses = Arrays.asList(LoanStatusEnum.values());
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses); return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
} }
@@ -31,6 +31,7 @@ import org.mifosng.platform.infrastructure.JdbcSupport;
import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource; import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource;
import org.mifosng.platform.loan.domain.Loan; import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanRepository; import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.loan.domain.LoanStatusEnum;
import org.mifosng.platform.loan.domain.LoanTransaction; import org.mifosng.platform.loan.domain.LoanTransaction;
import org.mifosng.platform.loan.domain.LoanTransactionRepository; import org.mifosng.platform.loan.domain.LoanTransactionRepository;
import org.mifosng.platform.loan.domain.LoanTransactionType; import org.mifosng.platform.loan.domain.LoanTransactionType;
@@ -411,12 +412,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, " + " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, "
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, " + " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, "
+ " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType," + " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
+ " l.loan_status_id as lifeCycleStatusId, st.display_name as lifeCycleStatusText, " + " l.loan_status_id as lifeCycleStatusId, "
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode" + " l.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode"
+ " from portfolio_loan l" + " from portfolio_loan l"
+ " join portfolio_product_loan lp on lp.id = l.product_id" + " join portfolio_product_loan lp on lp.id = l.product_id"
+ " join ref_currency rc on rc.`code` = l.currency_code" + " join ref_currency rc on rc.`code` = l.currency_code"
+ " join ref_loan_status st on st.id = l.loan_status_id"
+ " left join org_fund f on f.id = l.fund_id"; + " left join org_fund f on f.id = l.fund_id";
} }
@@ -494,9 +494,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
EnumOptionData interestCalculationPeriodType = LoanEnumerations EnumOptionData interestCalculationPeriodType = LoanEnumerations
.interestCalculationPeriodType(interestCalculationPeriodTypeInt); .interestCalculationPeriodType(interestCalculationPeriodTypeInt);
Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId");
"lifeCycleStatusId"); String lifeCycleStatusText = LoanStatusEnum.fromInt(lifeCycleStatusId).getCode();
String lifeCycleStatusText = rs.getString("lifeCycleStatusText");
LocalDate lifeCycleStatusDate = submittedOnDate; LocalDate lifeCycleStatusDate = submittedOnDate;
if (approvedOnDate != null) { if (approvedOnDate != null) {
@@ -2,6 +2,7 @@ package org.mifosng.platform.loan.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@@ -28,8 +29,7 @@ import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine; import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine;
import org.mifosng.platform.loan.domain.LoanRepaymentScheduleInstallment; import org.mifosng.platform.loan.domain.LoanRepaymentScheduleInstallment;
import org.mifosng.platform.loan.domain.LoanRepository; import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.loan.domain.LoanStatus; import org.mifosng.platform.loan.domain.LoanStatusEnum;
import org.mifosng.platform.loan.domain.LoanStatusRepository;
import org.mifosng.platform.loan.domain.LoanTransaction; import org.mifosng.platform.loan.domain.LoanTransaction;
import org.mifosng.platform.loan.domain.LoanTransactionRepository; import org.mifosng.platform.loan.domain.LoanTransactionRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loan.domain.PeriodFrequencyType;
@@ -45,7 +45,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final LoanRepository loanRepository; private final LoanRepository loanRepository;
private final LoanStatusRepository loanStatusRepository;
private final NoteRepository noteRepository; private final NoteRepository noteRepository;
private final CalculationPlatformService calculationPlatformService; private final CalculationPlatformService calculationPlatformService;
private final LoanTransactionRepository loanTransactionRepository; private final LoanTransactionRepository loanTransactionRepository;
@@ -54,13 +53,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Autowired @Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanAssembler loanAssembler, public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanAssembler loanAssembler,
final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository, final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository,
final LoanStatusRepository loanStatusRepository,
final NoteRepository noteRepository, final CalculationPlatformService calculationPlatformService) { final NoteRepository noteRepository, final CalculationPlatformService calculationPlatformService) {
this.context = context; this.context = context;
this.loanAssembler = loanAssembler; this.loanAssembler = loanAssembler;
this.loanRepository = loanRepository; this.loanRepository = loanRepository;
this.loanTransactionRepository = loanTransactionRepository; this.loanTransactionRepository = loanTransactionRepository;
this.loanStatusRepository = loanStatusRepository;
this.noteRepository = noteRepository; this.noteRepository = noteRepository;
this.calculationPlatformService = calculationPlatformService; this.calculationPlatformService = calculationPlatformService;
} }
@@ -70,7 +67,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
List<LoanStatus> allowedLoanStatuses = this.loanStatusRepository.findAll(); List<LoanStatusEnum> allowedLoanStatuses = Arrays.asList(LoanStatusEnum.values());
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses); return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
} }