harden up validation around savings application process.

This commit is contained in:
Keith Woodlock
2013-07-16 17:59:22 +01:00
parent 49ac64020a
commit 2c42d926cc
8 changed files with 220 additions and 124 deletions
@@ -89,6 +89,14 @@ public class DataValidatorBuilder {
dataValidationErrors.add(error);
}
public void failWithCodeNoParameterAddedToErrorCode(final String errorCode) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(errorCode);
StringBuilder defaultEnglishMessage = new StringBuilder("Failed data validation due to: ").append(errorCode).append(".");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
this.parameter, this.value);
dataValidationErrors.add(error);
}
public DataValidatorBuilder equalToParameter(final String linkedParameterName, final Object linkedValue) {
if (value == null && linkedValue == null && ignoreNullValue) { return this; }
@@ -4,19 +4,26 @@ import java.util.Date;
public class JobDetailData {
private Long jobId;
@SuppressWarnings("unused")
private final Long jobId;
private String displayName;
@SuppressWarnings("unused")
private final String displayName;
private Date nextRunTime;
@SuppressWarnings("unused")
private final Date nextRunTime;
private String initializingError;
@SuppressWarnings("unused")
private final String initializingError;
private boolean active;
@SuppressWarnings("unused")
private final boolean active;
private boolean currentlyRunning;
@SuppressWarnings("unused")
private final boolean currentlyRunning;
private JobDetailHistoryData lastRunHistory;
@SuppressWarnings("unused")
private final JobDetailHistoryData lastRunHistory;
public JobDetailData(final Long jobId, final String displayName, final Date nextRunTime, final String initializingError,
final boolean active, final boolean currentlyRunning, final JobDetailHistoryData lastRunHistory) {
@@ -28,5 +35,4 @@ public class JobDetailData {
this.lastRunHistory = lastRunHistory;
this.currentlyRunning = currentlyRunning;
}
}
}
@@ -4,13 +4,20 @@ import java.util.Date;
public class JobDetailHistoryData {
private Long version;
private Date jobRunStartTime;
private Date jobRunEndTime;
private String status;
private String jobRunErrorMessage;
private String triggerType;
private String jobRunErrorLog;
@SuppressWarnings("unused")
private final Long version;
@SuppressWarnings("unused")
private final Date jobRunStartTime;
@SuppressWarnings("unused")
private final Date jobRunEndTime;
@SuppressWarnings("unused")
private final String status;
@SuppressWarnings("unused")
private final String jobRunErrorMessage;
@SuppressWarnings("unused")
private final String triggerType;
@SuppressWarnings("unused")
private final String jobRunErrorLog;
public JobDetailHistoryData(final Long version, final Date jobRunStartTime, final Date jobRunEndTime, final String status,
final String jobRunErrorMessage, final String triggerType, final String jobRunErrorLog) {
@@ -19,6 +19,15 @@ public class SavingsApiConstants {
public static final String SAVINGS_ACCOUNT_RESOURCE_NAME = "savingsaccount";
public static final String SAVINGS_ACCOUNT_TRANSACTION_RESOURCE_NAME = "savingsaccount.transaction";
// actions
public static String summitalAction = ".summital";
public static String approvalAction = ".approval";
public static String undoApprovalAction = ".undoApproval";
public static String rejectAction = ".reject";
public static String withdrawnByApplicantAction = ".withdrawnByApplicant";
public static String activateAction = ".activate";
public static String modifyApplicationAction = ".modify";
// general
public static final String localeParamName = "locale";
public static final String dateFormatParamName = "dateFormat";
@@ -33,9 +42,15 @@ public class SavingsApiConstants {
public static final String groupIdParamName = "groupId";
public static final String productIdParamName = "productId";
public static final String fieldOfficerIdParamName = "fieldOfficerId";
public static final String submittedOnDateParamName = "submittedOnDate";
public static final String activeParamName = "active";
public static final String rejectedOnDateParamName = "rejectedOnDate";
public static final String withdrawnOnDateParamName = "withdrawnOnDate";
public static final String approvedOnDateParamName = "approvedOnDate";
public static final String activatedOnDateParamName = "activatedOnDate";
public static final String closedOnDateParamName = "closedOnDate";
public static final String activeParamName = "active";
public static final String nameParamName = "name";
public static final String descriptionParamName = "description";
public static final String currencyCodeParamName = "currencyCode";
@@ -71,7 +71,6 @@ import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
import org.mifosplatform.portfolio.savings.domain.interest.PostingPeriod;
import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
import org.mifosplatform.portfolio.savings.exception.InvalidSavingsAccountStateTransitionException;
import org.mifosplatform.portfolio.savings.service.SavingsEnumerations;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -825,9 +824,30 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return this.summary.getAccountBalance(this.currency).getAmount();
}
public void update(final JsonCommand command, final Map<String, Object> actualChanges) {
public void modifyApplication(final JsonCommand command, final Map<String, Object> actualChanges) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.modifyApplicationAction);
SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
if (!SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.hasStateOf(currentStatus)) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.in.submittedandpendingapproval.state");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
final String localeAsInput = command.locale();
final String dateFormat = command.dateFormat();
if (command.isChangeInLocalDateParameterNamed(SavingsApiConstants.submittedOnDateParamName, getSubmittedOnLocalDate())) {
final LocalDate newValue = command.localDateValueOfParameterNamed(SavingsApiConstants.submittedOnDateParamName);
final String newValueAsString = command.stringValueOfParameterNamed(SavingsApiConstants.submittedOnDateParamName);
actualChanges.put(SavingsApiConstants.submittedOnDateParamName, newValueAsString);
actualChanges.put(SavingsApiConstants.localeParamName, localeAsInput);
actualChanges.put(SavingsApiConstants.dateFormatParamName, dateFormat);
this.submittedOnDate = newValue.toDate();
}
if (command.isChangeInStringParameterNamed(SavingsApiConstants.accountNoParamName, this.accountNumber)) {
final String newValue = command.stringValueOfParameterNamed(SavingsApiConstants.accountNoParamName);
@@ -1137,20 +1157,25 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final LocalDate submittedOn = getSubmittedOnLocalDate();
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.summitalAction);
if (submittedOn.isAfter(todayDateOfTenant)) {
final String errorMessage = "Savings account application submitted on date cannot be in the future.";
throw new InvalidSavingsAccountStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, submittedOn);
baseDataValidator.reset().parameter(SavingsApiConstants.submittedOnDateParamName).value(submittedOn)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.a.future.date");
}
if (client != null && client.isActivatedAfter(submittedOn)) {
final String errorMessage = "Savings account application submitted on date cannot be earlier than client's activation date.";
throw new InvalidSavingsAccountStateTransitionException("submittal", "cannot.be.before.client.activation.date", errorMessage,
submittedOn);
baseDataValidator.reset().parameter(SavingsApiConstants.submittedOnDateParamName).value(client.getActivationLocalDate())
.failWithCodeNoParameterAddedToErrorCode("cannot.be.before.client.activation.date");
} else if (group != null && group.isActivatedAfter(submittedOn)) {
final String errorMessage = "Savings account application submitted on date cannot be earlier than group's activation date.";
throw new InvalidSavingsAccountStateTransitionException("submittal", "cannot.be.before.group.activation.date", errorMessage,
submittedOn);
baseDataValidator.reset().parameter(SavingsApiConstants.submittedOnDateParamName).value(group.getActivationLocalDate())
.failWithCodeNoParameterAddedToErrorCode("cannot.be.before.client.activation.date");
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
private LocalDate getSubmittedOnLocalDate() {
@@ -1177,43 +1202,49 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.approvalAction);
SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
if (!SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.hasStateOf(currentStatus)) {
final String errorMessage = "Savings account application can only be approved when in 'Submitted and pending approval' state. ";
throw new InvalidSavingsAccountStateTransitionException("approval", "not.in.submittedandpendingapproval.state", errorMessage);
baseDataValidator.reset().parameter(SavingsApiConstants.approvedOnDateParamName)
.failWithCodeNoParameterAddedToErrorCode("not.in.submittedandpendingapproval.state");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
this.status = SavingsAccountStatusType.APPROVED.getValue();
actualChanges.put("status", SavingsEnumerations.status(this.status));
actualChanges.put(SavingsApiConstants.statusParamName, SavingsEnumerations.status(this.status));
// only do below if status has changed in the 'approval' case
LocalDate approvedOn = command.localDateValueOfParameterNamed("approvedOnDate");
String approvedOnDateChange = command.stringValueOfParameterNamed("approvedOnDate");
if (approvedOn == null) {
approvedOn = command.localDateValueOfParameterNamed("eventDate");
approvedOnDateChange = command.stringValueOfParameterNamed("eventDate");
}
LocalDate approvedOn = command.localDateValueOfParameterNamed(SavingsApiConstants.approvedOnDateParamName);
String approvedOnDateChange = command.stringValueOfParameterNamed(SavingsApiConstants.approvedOnDateParamName);
this.approvedOnDate = approvedOn.toDate();
this.approvedBy = currentUser;
actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat());
actualChanges.put("approvedOnDate", approvedOnDateChange);
actualChanges.put(SavingsApiConstants.localeParamName, command.locale());
actualChanges.put(SavingsApiConstants.dateFormatParamName, command.dateFormat());
actualChanges.put(SavingsApiConstants.approvedOnDateParamName, approvedOnDateChange);
// FIXME - kw - format dates based on based locale when doing error
// messages related dates.
final LocalDate submittalDate = new LocalDate(this.submittedOnDate);
final LocalDate submittalDate = getSubmittedOnLocalDate();
if (approvedOn.isBefore(submittalDate)) {
final String errorMessage = "Savings account application cannot be approved on date before its submittal date: "
+ submittalDate.toString();
throw new InvalidSavingsAccountStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage,
getApprovedOnLocalDate(), submittalDate);
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
final String submittalDateAsString = formatter.print(submittalDate);
baseDataValidator.reset().parameter(SavingsApiConstants.approvedOnDateParamName).value(submittalDateAsString)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.before.submittal.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
if (approvedOn.isAfter(tenantsTodayDate)) {
final String errorMessage = "Savings account application cannot be approved on date in the future.";
throw new InvalidSavingsAccountStateTransitionException("approval", "cannot.be.a.future.date", errorMessage,
getApprovedOnLocalDate());
baseDataValidator.reset().parameter(SavingsApiConstants.approvedOnDateParamName)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.a.future.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
// FIXME - kw - support field officer history for savings accounts
@@ -1230,14 +1261,21 @@ public class SavingsAccount extends AbstractPersistable<Long> {
public Map<String, Object> undoApplicationApproval() {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.undoApprovalAction);
SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
if (!SavingsAccountStatusType.APPROVED.hasStateOf(currentStatus)) {
final String errorMessage = "Savings account application can only undo approval when in 'Approved' state. ";
throw new InvalidSavingsAccountStateTransitionException("approval", "not.in.approved.state", errorMessage);
baseDataValidator.reset().parameter(SavingsApiConstants.approvedOnDateParamName)
.failWithCodeNoParameterAddedToErrorCode("not.in.approved.state");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
this.status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue();
actualChanges.put("status", SavingsEnumerations.status(this.status));
actualChanges.put(SavingsApiConstants.statusParamName, SavingsEnumerations.status(this.status));
this.approvedOnDate = null;
this.approvedBy = null;
@@ -1247,7 +1285,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.withdrawnBy = null;
this.closedOnDate = null;
this.closedBy = null;
actualChanges.put("approvedOnDate", "");
actualChanges.put(SavingsApiConstants.approvedOnDateParamName, "");
// FIXME - kw - support field officer history for savings accounts
// this.loanOfficerHistory.clear();
@@ -1259,19 +1297,24 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.rejectAction);
SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
if (!SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.hasStateOf(currentStatus)) {
final String errorMessage = "Savings account application can only be rejected when in 'Submitted and pending approval' state. ";
throw new InvalidSavingsAccountStateTransitionException("reject", "not.in.submittedandpendingapproval.state", errorMessage);
baseDataValidator.reset().parameter(SavingsApiConstants.rejectedOnDateParamName)
.failWithCodeNoParameterAddedToErrorCode("not.in.submittedandpendingapproval.state");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
this.status = SavingsAccountStatusType.REJECTED.getValue();
actualChanges.put("status", SavingsEnumerations.status(this.status));
actualChanges.put(SavingsApiConstants.statusParamName, SavingsEnumerations.status(this.status));
LocalDate rejectedOn = command.localDateValueOfParameterNamed("rejectedOnDate");
final Locale locale = new Locale(command.locale());
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
LocalDate rejectedOn = command.localDateValueOfParameterNamed(SavingsApiConstants.rejectedOnDateParamName);
final String rejectedOnAsString = command.stringValueOfParameterNamed(SavingsApiConstants.rejectedOnDateParamName);
this.rejectedOnDate = rejectedOn.toDate();
this.rejectedBy = currentUser;
@@ -1280,23 +1323,29 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.closedOnDate = rejectedOn.toDate();
this.closedBy = currentUser;
actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat());
actualChanges.put("rejectedOnDate", rejectedOn.toString(fmt));
actualChanges.put("closedOnDate", rejectedOn.toString(fmt));
actualChanges.put(SavingsApiConstants.localeParamName, command.locale());
actualChanges.put(SavingsApiConstants.dateFormatParamName, command.dateFormat());
actualChanges.put(SavingsApiConstants.rejectedOnDateParamName, rejectedOnAsString);
actualChanges.put(SavingsApiConstants.closedOnDateParamName, rejectedOnAsString);
final LocalDate submittalDate = getSubmittedOnLocalDate();
if (rejectedOn.isBefore(submittalDate)) {
final String errorMessage = "Savings account application cannot be rejected on date before its submittal date: "
+ submittalDate.toString();
throw new InvalidSavingsAccountStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage,
getApprovedOnLocalDate(), submittalDate);
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
final String submittalDateAsString = formatter.print(submittalDate);
baseDataValidator.reset().parameter(SavingsApiConstants.rejectedOnDateParamName).value(submittalDateAsString)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.before.submittal.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
if (rejectedOn.isAfter(tenantsTodayDate)) {
final String errorMessage = "Savings account application cannot be rejected on date in the future.";
throw new InvalidSavingsAccountStateTransitionException("reject", "cannot.be.a.future.date", errorMessage,
getApprovedOnLocalDate());
baseDataValidator.reset().parameter(SavingsApiConstants.rejectedOnDateParamName).value(rejectedOn)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.a.future.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
return actualChanges;
@@ -1306,20 +1355,24 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final LocalDate tenantsTodayDate) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.withdrawnByApplicantAction);
SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
if (!SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.hasStateOf(currentStatus)) {
final String errorMessage = "Savings account application can only be withdrawn by applicant when in 'Submitted and pending approval' state. ";
throw new InvalidSavingsAccountStateTransitionException("withdrawnByApplicant", "not.in.submittedandpendingapproval.state",
errorMessage);
baseDataValidator.reset().parameter(SavingsApiConstants.withdrawnOnDateParamName)
.failWithCodeNoParameterAddedToErrorCode("not.in.submittedandpendingapproval.state");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
this.status = SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getValue();
actualChanges.put("status", SavingsEnumerations.status(this.status));
actualChanges.put(SavingsApiConstants.statusParamName, SavingsEnumerations.status(this.status));
LocalDate withdrawnOn = command.localDateValueOfParameterNamed("withdrawnOnDate");
final Locale locale = new Locale(command.locale());
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate withdrawnOn = command.localDateValueOfParameterNamed(SavingsApiConstants.withdrawnOnDateParamName);
final String withdrawnOnAsString = command.stringValueOfParameterNamed(SavingsApiConstants.withdrawnOnDateParamName);
this.rejectedOnDate = null;
this.rejectedBy = null;
@@ -1328,23 +1381,29 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.closedOnDate = withdrawnOn.toDate();
this.closedBy = currentUser;
actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat());
actualChanges.put("withdrawnOnDate", withdrawnOn.toString(fmt));
actualChanges.put("closedOnDate", withdrawnOn.toString(fmt));
actualChanges.put(SavingsApiConstants.localeParamName, command.locale());
actualChanges.put(SavingsApiConstants.dateFormatParamName, command.dateFormat());
actualChanges.put(SavingsApiConstants.withdrawnOnDateParamName, withdrawnOnAsString);
actualChanges.put(SavingsApiConstants.closedOnDateParamName, withdrawnOnAsString);
final LocalDate submittalDate = getSubmittedOnLocalDate();
if (withdrawnOn.isBefore(submittalDate)) {
final String errorMessage = "Savings account application cannot be withdrawn by applicant on date before its submittal date: "
+ submittalDate.toString();
throw new InvalidSavingsAccountStateTransitionException("withdrawnByApplicant", "cannot.be.before.submittal.date",
errorMessage, getApprovedOnLocalDate(), submittalDate);
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
final String submittalDateAsString = formatter.print(submittalDate);
baseDataValidator.reset().parameter(SavingsApiConstants.withdrawnOnDateParamName).value(submittalDateAsString)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.before.submittal.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
if (withdrawnOn.isAfter(tenantsTodayDate)) {
final String errorMessage = "Savings account application cannot be withdrawn by applicant on date in the future.";
throw new InvalidSavingsAccountStateTransitionException("withdrawnByApplicant", "cannot.be.a.future.date", errorMessage,
getApprovedOnLocalDate());
baseDataValidator.reset().parameter(SavingsApiConstants.withdrawnOnDateParamName).value(withdrawnOn)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.a.future.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
return actualChanges;
@@ -1355,10 +1414,17 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.activateAction);
SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
if (!SavingsAccountStatusType.APPROVED.hasStateOf(currentStatus)) {
final String errorMessage = "Savings account application can only be activated when in 'approved' state. ";
throw new InvalidSavingsAccountStateTransitionException("activation", "not.in.approved.state", errorMessage);
baseDataValidator.reset().parameter(SavingsApiConstants.activatedOnDateParamName)
.failWithCodeNoParameterAddedToErrorCode("not.in.approved.state");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
final Locale locale = command.extractLocale();
@@ -1382,24 +1448,34 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate());
if (this.client.isActivatedAfter(activationDate)) {
final String errorMessage = "The date on which a savings account is activate cannot be before its client activated date: "
+ this.client.getActivationLocalDate().toString();
throw new InvalidSavingsAccountStateTransitionException("activate", "cannot.be.before.client.activation.date", errorMessage,
activationDate, this.client.getActivationLocalDate());
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
final String dateAsString = formatter.print(client.getActivationLocalDate());
baseDataValidator.reset().parameter(SavingsApiConstants.activatedOnDateParamName).value(dateAsString)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.before.client.activation.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
final LocalDate submittalDate = getSubmittedOnLocalDate();
if (activationDate.isBefore(submittalDate)) {
final String errorMessage = "Savings account application cannot be withdrawn by applicant on date before its submittal date: "
+ submittalDate.toString();
throw new InvalidSavingsAccountStateTransitionException("activate", "cannot.be.before.submittal.date",
errorMessage, getApprovedOnLocalDate(), submittalDate);
final LocalDate approvalDate = getApprovedOnLocalDate();
if (activationDate.isBefore(approvalDate)) {
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
final String dateAsString = formatter.print(approvalDate);
baseDataValidator.reset().parameter(SavingsApiConstants.activatedOnDateParamName).value(dateAsString)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.before.approval.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
if (activationDate.isAfter(tenantsTodayDate)) {
final String errorMessage = "Savings account application cannot be withdrawn by applicant on date in the future.";
throw new InvalidSavingsAccountStateTransitionException("activate", "cannot.be.a.future.date", errorMessage,
getApprovedOnLocalDate());
baseDataValidator.reset().parameter(SavingsApiConstants.activatedOnDateParamName).value(activationDate)
.failWithCodeNoParameterAddedToErrorCode("cannot.be.a.future.date");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
// auto enter deposit for minimum required opening balance when
@@ -85,6 +85,6 @@ public enum SavingsAccountStatusType {
}
public boolean isClosed() {
return this.value.equals(SavingsAccountStatusType.CLOSED.getValue());
return this.value.equals(SavingsAccountStatusType.CLOSED.getValue()) || isRejected() || isApplicationWithdrawnByApplicant();
}
}
@@ -1,17 +0,0 @@
/**
* 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.savings.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class InvalidSavingsAccountStateTransitionException extends AbstractPlatformDomainRuleException {
public InvalidSavingsAccountStateTransitionException(final String action, final String postFix, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
super("error.msg.saving." + action + "." + postFix, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -162,7 +162,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
account.update(command, changes);
account.modifyApplication(command, changes);
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant());
if (!changes.isEmpty()) {