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