added validation around Loan life cycle events like, repayment, disbursement etc..
This commit is contained in:
committed by
Vishwas Babu A J
parent
49a2f30e2c
commit
a354b3e664
+6
@@ -89,6 +89,12 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
|||||||
newState = stateOf(LoanStatus.OVERPAID, this.allowedLoanStatuses);
|
newState = stateOf(LoanStatus.OVERPAID, this.allowedLoanStatuses);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LOAN_CLOSED:
|
||||||
|
break;
|
||||||
|
case WRITE_OFF_OUTSTANDING_UNDO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return newState;
|
return newState;
|
||||||
|
|||||||
+131
-3
@@ -44,6 +44,8 @@ import org.joda.time.format.DateTimeFormat;
|
|||||||
import org.joda.time.format.DateTimeFormatter;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
|
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||||
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
|
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
|
||||||
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
||||||
@@ -1314,7 +1316,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public Map<String, Object> loanApplicationRejection(final AppUser currentUser, final JsonCommand command,
|
public Map<String, Object> loanApplicationRejection(final AppUser currentUser, final JsonCommand command,
|
||||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_REJECTED);
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECTED, LoanStatus.fromInt(this.loanStatus));
|
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECTED, LoanStatus.fromInt(this.loanStatus));
|
||||||
@@ -1410,6 +1414,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
public Map<String, Object> loanApplicationApproval(final AppUser currentUser, final JsonCommand command,
|
public Map<String, Object> loanApplicationApproval(final AppUser currentUser, final JsonCommand command,
|
||||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_APPROVED);
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED, LoanStatus.fromInt(this.loanStatus));
|
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED, LoanStatus.fromInt(this.loanStatus));
|
||||||
@@ -1458,6 +1464,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public Map<String, Object> undoApproval(final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
public Map<String, Object> undoApproval(final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_APPROVAL_UNDO);
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
final LoanStatus currentStatus = LoanStatus.fromInt(this.loanStatus);
|
final LoanStatus currentStatus = LoanStatus.fromInt(this.loanStatus);
|
||||||
@@ -1506,6 +1513,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled, final List<Holiday> holidays,
|
final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled, final List<Holiday> holidays,
|
||||||
final WorkingDays workingDays, final boolean allowTransactionsOnHoliday, final boolean allowTransactionsOnNonWorkingDay) {
|
final WorkingDays workingDays, final boolean allowTransactionsOnHoliday, final boolean allowTransactionsOnNonWorkingDay) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_DISBURSED);
|
||||||
updateLoanToPreDisbursalState();
|
updateLoanToPreDisbursalState();
|
||||||
|
|
||||||
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
|
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
|
||||||
@@ -1674,8 +1682,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final List<Long> existingReversedTransactionIds, final LocalDate calculatedRepaymentsStartingFromDate,
|
final List<Long> existingReversedTransactionIds, final LocalDate calculatedRepaymentsStartingFromDate,
|
||||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
|
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_DISBURSAL_UNDO);
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
final LoanStatus currentStatus = LoanStatus.fromInt(this.loanStatus);
|
final LoanStatus currentStatus = LoanStatus.fromInt(this.loanStatus);
|
||||||
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, currentStatus);
|
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, currentStatus);
|
||||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_DISBURSAL_UNDO, getDisbursementDate());
|
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_DISBURSAL_UNDO, getDisbursementDate());
|
||||||
@@ -1736,6 +1745,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
public ChangedTransactionDetail waiveInterest(final LoanTransaction waiveInterestTransaction,
|
public ChangedTransactionDetail waiveInterest(final LoanTransaction waiveInterestTransaction,
|
||||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds,
|
final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds,
|
||||||
final List<Long> existingReversedTransactionIds) {
|
final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_REPAYMENT_OR_WAIVER);
|
||||||
|
|
||||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
|
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
|
||||||
waiveInterestTransaction.getTransactionDate());
|
waiveInterestTransaction.getTransactionDate());
|
||||||
@@ -1754,6 +1765,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final List<Long> existingReversedTransactionIds, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays,
|
final List<Long> existingReversedTransactionIds, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays,
|
||||||
final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) {
|
final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_REPAYMENT_OR_WAIVER);
|
||||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, repaymentTransaction.getTransactionDate());
|
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, repaymentTransaction.getTransactionDate());
|
||||||
|
|
||||||
validateRepaymentDateIsOnHoliday(repaymentTransaction.getTransactionDate(), allowTransactionsOnHoliday, holidays);
|
validateRepaymentDateIsOnHoliday(repaymentTransaction.getTransactionDate(), allowTransactionsOnHoliday, holidays);
|
||||||
@@ -1773,6 +1785,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final WorkingDays workingDays,
|
final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||||
final boolean allowTransactionsOnNonWorkingDay, final LoanTransaction paymentTransaction, final Integer installmentNumber) {
|
final boolean allowTransactionsOnNonWorkingDay, final LoanTransaction paymentTransaction, final Integer installmentNumber) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_CHARGE_PAYMENT);
|
||||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_CHARGE_PAYMENT, paymentTransaction.getTransactionDate());
|
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_CHARGE_PAYMENT, paymentTransaction.getTransactionDate());
|
||||||
validateRepaymentDateIsOnHoliday(paymentTransaction.getTransactionDate(), allowTransactionsOnHoliday, holidays);
|
validateRepaymentDateIsOnHoliday(paymentTransaction.getTransactionDate(), allowTransactionsOnHoliday, holidays);
|
||||||
validateRepaymentDateIsOnNonWorkingDay(paymentTransaction.getTransactionDate(), workingDays, allowTransactionsOnNonWorkingDay);
|
validateRepaymentDateIsOnNonWorkingDay(paymentTransaction.getTransactionDate(), workingDays, allowTransactionsOnNonWorkingDay);
|
||||||
@@ -2113,6 +2126,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ChangedTransactionDetail undoWrittenOff(final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds){
|
public ChangedTransactionDetail undoWrittenOff(final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds){
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO);
|
||||||
|
|
||||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
final LoanTransaction writeOffTransaction = findWriteOffTransaction();
|
final LoanTransaction writeOffTransaction = findWriteOffTransaction();
|
||||||
@@ -2179,6 +2195,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||||
final AppUser currentUser) {
|
final AppUser currentUser) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING);
|
||||||
|
|
||||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING,
|
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING,
|
||||||
LoanStatus.fromInt(this.loanStatus));
|
LoanStatus.fromInt(this.loanStatus));
|
||||||
|
|
||||||
@@ -2235,7 +2253,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public LoanTransaction close(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
public LoanTransaction close(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||||
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
|
validateAccountStatus(LoanEvent.LOAN_CLOSED);
|
||||||
|
|
||||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
|
|
||||||
@@ -2363,6 +2383,10 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return status().isSubmittedAndPendingApproval();
|
return status().isSubmittedAndPendingApproval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isApproved() {
|
||||||
|
return status().isApproved();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isNotDisbursed() {
|
private boolean isNotDisbursed() {
|
||||||
return !isDisbursed();
|
return !isDisbursed();
|
||||||
}
|
}
|
||||||
@@ -3043,4 +3067,108 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return loanChargePerInstallments;
|
return loanChargePerInstallments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateAccountStatus(final LoanEvent event) {
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case LOAN_CREATED:
|
||||||
|
break;
|
||||||
|
case LOAN_APPROVED:
|
||||||
|
if (!isSubmittedAndPendingApproval()) {
|
||||||
|
final String defaultUserMessage = "Loan Account Approval is not allowed. Loan Account is not in submitted and pending approval state.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError(
|
||||||
|
"error.msg.loan.approve.account.is.not.submitted.and.pending.state", defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOAN_APPROVAL_UNDO:
|
||||||
|
if (!isApproved()) {
|
||||||
|
final String defaultUserMessage = "Loan Account Undo Approval is not allowed. Loan Account is not in approved state.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.undo.approval.account.is.not.approved",
|
||||||
|
defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOAN_DISBURSED:
|
||||||
|
if (!(isApproved() && isNotDisbursed())) {
|
||||||
|
final String defaultUserMessage = "Loan Disbursal is not allowed. Loan Account is not in approved and not disbursed state.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError(
|
||||||
|
"error.msg.loan.disbursal.account.is.not.approve.not.disbursed.state", defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOAN_DISBURSAL_UNDO:
|
||||||
|
if (!isOpen()) {
|
||||||
|
final String defaultUserMessage = "Loan Undo disbursal is not allowed. Loan Account is not active.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.undo.disbursal.account.is.not.active",
|
||||||
|
defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOAN_REPAYMENT_OR_WAIVER:
|
||||||
|
if (!isOpen()) {
|
||||||
|
final String defaultUserMessage = "Loan Repayment or Waiver is not allowed. Loan Account is not active.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError(
|
||||||
|
"error.msg.loan.repayment.or.waiver.account.is.not.active", defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOAN_REJECTED:
|
||||||
|
if (!isClosedWrittenOff()) {
|
||||||
|
final String defaultUserMessage = "Loan application cannot be rejected. Loan Account is not in Submitted and Pending approval state.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError(
|
||||||
|
"error.msg.loan.reject.account.is.not.submitted.pending.approval.state", defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOAN_WITHDRAWN:
|
||||||
|
if (!isSubmittedAndPendingApproval()) {
|
||||||
|
final String defaultUserMessage = "Loan application cannot be withdrawn. Loan Account is not in Submitted and Pending approval state.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError(
|
||||||
|
"error.msg.loan.withdrawn.account.is.not.submitted.pending.approval.state", defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WRITE_OFF_OUTSTANDING:
|
||||||
|
if (!isOpen()) {
|
||||||
|
final String defaultUserMessage = "Loan Written off is not allowed. Loan Account is not active.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.writtenoff.account.is.not.active",
|
||||||
|
defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WRITE_OFF_OUTSTANDING_UNDO:
|
||||||
|
if (!isClosedWrittenOff()) {
|
||||||
|
final String defaultUserMessage = "Loan Undo Written off is not allowed. Loan Account is not Written off.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError(
|
||||||
|
"error.msg.loan.undo.writtenoff.account.is.not.written.off", defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REPAID_IN_FULL:
|
||||||
|
break;
|
||||||
|
case LOAN_CHARGE_PAYMENT:
|
||||||
|
if (!isClosedWrittenOff()) {
|
||||||
|
final String defaultUserMessage = "Charge payment is not allowed. Loan Account is not Active.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.charge.payment.account.is.not.active",
|
||||||
|
defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOAN_CLOSED:
|
||||||
|
if (!isClosedWrittenOff()) {
|
||||||
|
final String defaultUserMessage = "Closing Loan Account is not allowed. Loan Account is not Active.";
|
||||||
|
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.close.account.is.not.active",
|
||||||
|
defaultUserMessage);
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+3
-1
@@ -20,7 +20,9 @@ public enum LoanEvent {
|
|||||||
LOAN_REPAYMENT_OR_WAIVER, //
|
LOAN_REPAYMENT_OR_WAIVER, //
|
||||||
REPAID_IN_FULL, //
|
REPAID_IN_FULL, //
|
||||||
WRITE_OFF_OUTSTANDING, //
|
WRITE_OFF_OUTSTANDING, //
|
||||||
|
WRITE_OFF_OUTSTANDING_UNDO, //
|
||||||
LOAN_RESCHEDULE, //
|
LOAN_RESCHEDULE, //
|
||||||
INTERST_REBATE_OWED, //
|
INTERST_REBATE_OWED, //
|
||||||
LOAN_OVERPAYMENT, LOAN_CHARGE_PAYMENT;
|
LOAN_OVERPAYMENT, LOAN_CHARGE_PAYMENT,
|
||||||
|
LOAN_CLOSED;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user