/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.ui.core.controller;
import org.hibernate.validator.constraints.NotEmpty;
import org.mifos.config.servicefacade.ConfigurationServiceFacade;
import org.mifos.config.servicefacade.dto.AccountingConfigurationDto;
import org.mifos.dto.domain.CustomerDto;
import org.mifos.dto.domain.PrdOfferingDto;
import org.mifos.dto.screen.SavingsProductReferenceDto;
import org.mifos.platform.questionnaire.service.QuestionGroupDetail;
import org.mifos.platform.questionnaire.service.QuestionnaireServiceFacade;
import org.mifos.platform.validation.MifosBeanValidator;
import org.mifos.platform.validations.ValidationException;
import org.mifos.ui.core.controller.util.ValidationExceptionMessageExtractor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
import org.springframework.binding.validation.ValidationContext;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* An object to hold information collected in create savings account process.
*/
@SuppressWarnings("PMD")
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value={"SE_NO_SERIALVERSIONID", "SE_BAD_FIELD"}, justification="should disable at filter level and also for pmd - not important for us")
public class CreateSavingsAccountFormBean implements Serializable {
// FIXME - keithw - there is no need to differentiate between madatory and voluntary deposit amount
// - there is only one field on the form - deposit amount and at creation we use the
// - product definition to determine if it is mandatory or voluntary?
static final int MANDATORY_DEPOSIT = 1;
static final int VOLUNTARY_DEPOSIT = 2;
private CustomerDto customer;
@NotEmpty(groups = CustomerSearchStep.class)
private String searchString;
@NotNull(groups = { MandatorySavings.class })
@Pattern(regexp = "^[0-9]+(\\.[0-9]+)?$?", groups = { MandatorySavings.class })
private String mandatoryDepositAmount;
private SavingsProductReferenceDto product;
@NotNull(groups = { SelectProductStep.class })
private Integer productId;
private List<QuestionGroupDetail> questionGroups;
private List<PrdOfferingDto> productOfferings;
private Map<String, String> productOfferingOptions;
private Map<String, String> savingsTypes;
private Map<String, String> recurrenceTypes;
private Map<String, String> recurrenceFrequencies;
@Autowired
private transient MifosBeanValidator validator;
@Autowired
private transient QuestionnaireServiceFacade questionnaireServiceFacade;
private transient ConfigurationServiceFacade configurationServiceFacade;
public void setValidator(MifosBeanValidator validator) {
this.validator = validator;
}
public void setQuestionnaireServiceFascade(QuestionnaireServiceFacade questionnaireServiceFacade) {
this.questionnaireServiceFacade = questionnaireServiceFacade;
}
@Autowired
public void setConfigurationServiceFacade(ConfigurationServiceFacade configurationServiceFacade) {
this.configurationServiceFacade = configurationServiceFacade;
}
public void setCustomer(CustomerDto customer) {
this.customer = customer;
}
public CustomerDto getCustomer() {
return customer;
}
public void setSearchString(String searchString) {
this.searchString = searchString;
}
public String getSearchString() {
return searchString;
}
/**
* Sets the savings product associated with the (new) savings account. The
* product can be referenced in form validation.
*
* @param product
* An instance of {@link SavingsProductReferenceDto}
*/
public void setProduct(SavingsProductReferenceDto product) {
this.product = product;
}
public SavingsProductReferenceDto getProduct() {
return product;
}
public void setProductOfferings(List<PrdOfferingDto> productOfferings) {
this.productOfferings = productOfferings;
}
public List<PrdOfferingDto> getProductOfferings() {
return productOfferings;
}
public void setProductOfferingOptions(
Map<String, String> productOfferingOptions) {
this.productOfferingOptions = productOfferingOptions;
}
public Map<String, String> getProductOfferingOptions() {
return productOfferingOptions;
}
/**
* Validation method that Spring webflow calls on state transition out of
* customerSearchStep.
*/
public void validateCustomerSearchStep(ValidationContext context) {
MessageContext messages = context.getMessageContext();
validator.validate(this, messages, CustomerSearchStep.class);
}
/**
* Validation method that Spring webflow calls on state transition out of
* selectCustomerStep.
*/
public void validateSelectCustomerStep(ValidationContext context) {
MessageContext messages = context.getMessageContext();
validator.validate(this, messages, CustomerSearchStep.class);
}
/**
* Validation method that Spring webflow calls on state transition out of
* selectProductOfferingStep.
*/
public void validateSelectProductOfferingStep(ValidationContext context) {
MessageContext messages = context.getMessageContext();
validator.validate(this, messages, SelectProductStep.class);
}
public void validateEnterAccountDetailsStep(ValidationContext context) {
validateAccountDetails(context);
}
public void validateEditAccountDetailsStep(ValidationContext context) {
validateAccountDetails(context);
}
public void validateAnswerQuestionGroupStep(ValidationContext context) {
validateQuestionGroupAnswers(context);
}
public void validateEditQuestionGroupStep(ValidationContext context) {
validateQuestionGroupAnswers(context);
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public Integer getProductId() {
return productId;
}
public void setSavingsTypes(Map<String, String> savingsTypes) {
this.savingsTypes = savingsTypes;
}
public Map<String, String> getSavingsTypes() {
return savingsTypes;
}
public void setRecurrenceTypes(Map<String, String> recurrenceTypes) {
this.recurrenceTypes = recurrenceTypes;
}
public Map<String, String> getRecurrenceTypes() {
return recurrenceTypes;
}
public void setRecurrenceFrequencies(
Map<String, String> recurrenceFrequencies) {
this.recurrenceFrequencies = recurrenceFrequencies;
}
public Map<String, String> getRecurrenceFrequencies() {
return recurrenceFrequencies;
}
public void setMandatoryDepositAmount(String mandatoryDepositAmount) {
this.mandatoryDepositAmount = mandatoryDepositAmount;
}
public String getMandatoryDepositAmount() {
return mandatoryDepositAmount;
}
public void setQuestionGroups(List<QuestionGroupDetail> questionGroups) {
this.questionGroups = questionGroups;
}
public List<QuestionGroupDetail> getQuestionGroups() {
return questionGroups;
}
private void validateAccountDetails(ValidationContext context) {
MessageContext messages = context.getMessageContext();
validator.validate(this, messages, MandatorySavings.class);
validateMandatoryDepositAmountDigits(context);
}
private void validateQuestionGroupAnswers(ValidationContext context) {
MessageContext messages = context.getMessageContext();
try {
questionnaireServiceFacade.validateResponses(this
.getQuestionGroups());
} catch (ValidationException e) {
ValidationExceptionMessageExtractor extractor = new ValidationExceptionMessageExtractor();
extractor.extract(messages, e);
}
}
private void validateMandatoryDepositAmountDigits(ValidationContext context) {
if (mandatoryDepositAmount == null) {
return;
}
AccountingConfigurationDto accountingConfiguration = configurationServiceFacade.getAccountingConfiguration();
BigDecimal decimalAmount;
try {
decimalAmount = new BigDecimal(mandatoryDepositAmount);
} catch (NumberFormatException e) {
return;
}
if ((decimalAmount.precision() - decimalAmount.scale()) > accountingConfiguration.getDigitsBeforeDecimal()) {
context.getMessageContext().addMessage(new MessageBuilder()
.error()
.source("mandatoryDepositAmount")
.code("DigitsBefore.CreateSavingsAccountFormBean.mandatoryDepositAmount")
.arg(accountingConfiguration.getDigitsBeforeDecimal())
.build()
);
}
if (decimalAmount.scale() > accountingConfiguration.getDigitsAfterDecimal()) {
context.getMessageContext().addMessage(new MessageBuilder()
.error()
.source("mandatoryDepositAmount")
.code("DigitsAfter.CreateSavingsAccountFormBean.mandatoryDepositAmount")
.arg(accountingConfiguration.getDigitsAfterDecimal())
.build()
);
}
}
}
/**
* Marker interfaces for JSR-303 validation groups.
*/
interface CustomerSearchStep {
}
interface SelectProductStep {
}
interface EnterAccountInfoStep {
}
interface MandatorySavings {
}