/* * 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.accounts.loan.struts.actionforms; import static org.apache.commons.lang.StringUtils.isBlank; import static org.mifos.accounts.loan.util.helpers.LoanConstants.PERSPECTIVE_VALUE_REDO_LOAN; import static org.mifos.framework.util.CollectionUtils.select; import static org.mifos.platform.util.CollectionUtils.collect; import static org.mifos.platform.util.CollectionUtils.isNotEmpty; import static org.mifos.platform.util.CollectionUtils.itemIndexOutOfAscendingOrder; import java.math.BigDecimal; import java.sql.Date; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.mifos.accounts.exceptions.AccountException; import org.mifos.accounts.fees.business.FeeDto; import org.mifos.accounts.fees.util.helpers.FeeFormula; import org.mifos.accounts.fees.util.helpers.RateAmountFlag; import org.mifos.accounts.loan.business.LoanBO; import org.mifos.accounts.loan.struts.uihelpers.LoanUIHelperFn; import org.mifos.accounts.loan.struts.uihelpers.PaymentDataHtmlBean; import org.mifos.accounts.loan.util.helpers.LoanConstants; import org.mifos.accounts.loan.util.helpers.LoanExceptionConstants; import org.mifos.accounts.loan.util.helpers.RepaymentScheduleInstallment; import org.mifos.accounts.productdefinition.business.AmountRange; import org.mifos.accounts.productdefinition.business.InstallmentRange; import org.mifos.accounts.productdefinition.business.LoanOfferingBO; import org.mifos.accounts.productdefinition.util.helpers.ProductDefinitionConstants; import org.mifos.accounts.util.helpers.AccountState; import org.mifos.application.admin.servicefacade.InvalidDateException; import org.mifos.application.cashflow.struts.CashFlowCaptor; import org.mifos.application.master.business.CustomFieldDefinitionEntity; import org.mifos.application.master.business.CustomFieldType; import org.mifos.application.master.business.MifosCurrency; import org.mifos.application.meeting.exceptions.MeetingException; import org.mifos.application.meeting.util.helpers.RecurrenceType; import org.mifos.application.questionnaire.struts.QuestionResponseCapturer; import org.mifos.application.util.helpers.EntityType; import org.mifos.application.util.helpers.Methods; import org.mifos.application.util.helpers.YesNoFlag; import org.mifos.config.business.service.ConfigurationBusinessService; import org.mifos.config.persistence.ConfigurationPersistence; import org.mifos.config.util.helpers.ConfigurationConstants; import org.mifos.customers.business.CustomerBO; import org.mifos.customers.persistence.CustomerPersistence; import org.mifos.dto.domain.CustomFieldDto; import org.mifos.dto.domain.CustomerDetailDto; import org.mifos.dto.domain.LoanAccountDetailsDto; import org.mifos.dto.screen.CashFlowDataDto; import org.mifos.framework.components.fieldConfiguration.business.FieldConfigurationEntity; import org.mifos.framework.exceptions.ApplicationException; import org.mifos.framework.exceptions.FrameworkRuntimeException; import org.mifos.framework.exceptions.PageExpiredException; import org.mifos.framework.exceptions.PersistenceException; import org.mifos.framework.exceptions.ServiceException; import org.mifos.framework.struts.actionforms.BaseActionForm; import org.mifos.framework.util.DateTimeService; import org.mifos.framework.util.LocalizationConverter; import org.mifos.framework.util.helpers.Constants; import org.mifos.framework.util.helpers.DateUtils; import org.mifos.framework.util.helpers.DoubleConversionResult; import org.mifos.framework.util.helpers.ExceptionConstants; import org.mifos.framework.util.helpers.Money; import org.mifos.framework.util.helpers.SessionUtils; import org.mifos.platform.cashflow.ui.model.CashFlowForm; import org.mifos.platform.questionnaire.service.QuestionGroupDetail; import org.mifos.platform.util.Transformer; public class LoanAccountActionForm extends BaseActionForm implements QuestionResponseCapturer, CashFlowCaptor { public LoanAccountActionForm() { super(); defaultFees = new ArrayList<FeeDto>(); additionalFees = new ArrayList<FeeDto>(); customFields = new ArrayList<CustomFieldDto>(); clients = new ArrayList<String>(); clientDetails = new ArrayList<LoanAccountDetailsDto>(); configService = new ConfigurationBusinessService(); } // For individual monitoring private List<String> clients; private List<LoanAccountDetailsDto> clientDetails; private String perspective; private String accountId; private String globalAccountNum; private String prdOfferingName; private String accountName; private String accountTypeId; private String customerId; private String prdOfferingId; private String loanAmount; private String interestRate; private String noOfInstallments; private String disbursementDate; private String intDedDisbursement; private String loanOfferingFund; private String gracePeriodDuration; private String externalId; private String businessActivityId; private String collateralTypeId; private String collateralNote; private List<FeeDto> defaultFees; private List<FeeDto> additionalFees; private String stateSelected; private String gracePeriod; private List<CustomFieldDto> customFields; private List<PaymentDataHtmlBean> paymentDataBeans = new ArrayList<PaymentDataHtmlBean>(); // For Repayment day private String monthRank; private String weekRank; private String monthWeek; private String monthType; private String monthDay; private String dayRecurMonth; private String weekDay; private String recurMonth; private String recurWeek; private String frequency; private String firstRepaymentDay; private String recurrenceId; private AmountRange amountRange; private Double maxInterestRate; private Double minInterestRate; private InstallmentRange installmentRange; private String dayNumber; private ConfigurationBusinessService configService; private Date originalDisbursementDate; /*private List<QuestionGroupDto> questionGroupDtos;*/ private List<QuestionGroupDetail> questionGroups; private List<RepaymentScheduleInstallment> installments = new ArrayList<RepaymentScheduleInstallment>(); private boolean variableInstallmentsAllowed; private Integer minimumGapInDays; private Integer maximumGapInDays; private Money minInstallmentAmount; private CashFlowForm cashFlowForm; private List<CashFlowDataDto> cashflowDataDtos; private String scheduleViewDate; private Money loanAmountValue; public List<CashFlowDataDto> getCashflowDataDtos(){ return cashflowDataDtos; } public void setCashflowDataDtos(List<CashFlowDataDto> cashflowDataDtos) { this.cashflowDataDtos = cashflowDataDtos; } public Date getOriginalDisbursementDate() { return this.originalDisbursementDate; } public void setOriginalDisbursementDate(Date originalDisbursementDate) { this.originalDisbursementDate = originalDisbursementDate; } public String getDayNumber() { return dayNumber; } public void setDayNumber(String dayNumber) { this.dayNumber = dayNumber; } public String getMonthRank() { return monthRank; } public void setMonthRank(String monthRank) { this.monthRank = monthRank; } public String getMonthWeek() { return monthWeek; } public void setMonthWeek(String monthWeek) { this.monthWeek = monthWeek; } public String getMonthType() { return monthType; } public void setMonthType(String monthType) { this.monthType = monthType; } public String getMonthDay() { return monthDay; } public void setMonthDay(String monthDay) { this.monthDay = monthDay; } public String getDayRecurMonth() { return dayRecurMonth; } public void setDayRecurMonth(String dayRecurMonth) { this.dayRecurMonth = dayRecurMonth; } public String getRecurMonth() { return recurMonth; } public void setRecurMonth(String recurMonth) { this.recurMonth = recurMonth; } public String getRecurWeek() { return recurWeek; } public void setRecurWeek(String recurWeek) { this.recurWeek = recurWeek; } public String getFrequency() { return frequency; } public void setFrequency(String frequency) { this.frequency = frequency; } public String getWeekDay() { return weekDay; } public void setWeekDay(String weekDay) { this.weekDay = weekDay; } public String getWeekRank() { return weekRank; } public void setWeekRank(String weekRank) { this.weekRank = weekRank; } public String getRecurrenceId() { return recurrenceId; } public void setRecurrenceId(String recurrenceId) { this.recurrenceId = recurrenceId; } public List<PaymentDataHtmlBean> getPaymentDataBeans() { return this.paymentDataBeans; } public String getGracePeriod() { return gracePeriod; } public void setGracePeriod(String gracePeriod) { this.gracePeriod = gracePeriod; } public String getExternalId() { return this.externalId; } public void setExternalId(String externalId) { this.externalId = externalId; } public String getAccountId() { return accountId; } public void setAccountId(String accountId) { this.accountId = accountId; } public String getAccountName() { return accountName; } public void setAccountName(String accountName) { this.accountName = accountName; } public String getAccountTypeId() { return accountTypeId; } public void setAccountTypeId(String accountTypeId) { this.accountTypeId = accountTypeId; } public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } public String getGlobalAccountNum() { return globalAccountNum; } public void setGlobalAccountNum(String globalAccountNum) { this.globalAccountNum = globalAccountNum; } public String getPrdOfferingName() { return prdOfferingName; } public void setPrdOfferingName(String prdOfferingName) { this.prdOfferingName = prdOfferingName; } public String getPrdOfferingId() { return prdOfferingId; } public void setPrdOfferingId(String prdOfferingId) { this.prdOfferingId = prdOfferingId; } public String getBusinessActivityId() { return businessActivityId; } public void setBusinessActivityId(String businessActivityId) { this.businessActivityId = businessActivityId; } public String getCollateralNote() { return collateralNote; } public void setCollateralNote(String collateralNote) { this.collateralNote = collateralNote; } public String getCollateralTypeId() { return collateralTypeId; } public void setCollateralTypeId(String collateralTypeId) { this.collateralTypeId = collateralTypeId; } public String getDisbursementDate() { return disbursementDate; } public String getScheduleViewDate() { return scheduleViewDate; } public void setDisbursementDate(String disbursementDate) { this.disbursementDate = disbursementDate; } public void setScheduleViewDate(String scheduleViewDate) { this.scheduleViewDate = scheduleViewDate; } public String getGracePeriodDuration() { return gracePeriodDuration; } public void setGracePeriodDuration(String gracePeriodDuration) { this.gracePeriodDuration = gracePeriodDuration; } public String getIntDedDisbursement() { return intDedDisbursement; } public void setIntDedDisbursement(String intDedDisbursement) { this.intDedDisbursement = intDedDisbursement; } public String getInterestRate() { return interestRate; } public void setInterestRate(String interestRate) { this.interestRate = interestRate; } public String getLoanAmount() { return loanAmount; } public void setLoanAmount(String loanAmount) { this.loanAmount = loanAmount; } public String getLoanOfferingFund() { return loanOfferingFund; } public void setLoanOfferingFund(String loanOfferingFund) { this.loanOfferingFund = loanOfferingFund; } public String getNoOfInstallments() { return noOfInstallments; } public void setNoOfInstallments(String noOfInstallments) { this.noOfInstallments = noOfInstallments; } public List<CustomFieldDto> getCustomFields() { return customFields; } public void setCustomFields(List<CustomFieldDto> customFields) { this.customFields = customFields; } public CustomFieldDto getCustomField(int i) { while (i >= customFields.size()) { customFields.add(new CustomFieldDto()); } return customFields.get(i); } public List<FeeDto> getAdditionalFees() { return additionalFees; } public void setAdditionalFees(List<FeeDto> additionalFees) { this.additionalFees = additionalFees; } public List<FeeDto> getDefaultFees() { return defaultFees; } public void setDefaultFees(List<FeeDto> defaultFees) { this.defaultFees = defaultFees; } public String getStateSelected() { return stateSelected; } public void setStateSelected(String stateSelected) { this.stateSelected = stateSelected; } public AccountState getState() { return AccountState.fromShort(getShortValue(getStateSelected())); } public Integer getCustomerIdValue() { return getIntegerValue(getCustomerId()); } public Short getPrdOfferingIdValue() { return getShortValue(getPrdOfferingId()); } public Short getGracePeriodDurationValue() { return getShortValue(getGracePeriodDuration()); } public Short getNoOfInstallmentsValue() { return getShortValue(getNoOfInstallments()); } public Date getDisbursementDateValue(Locale locale) throws InvalidDateException { return DateUtils.getLocaleDate(locale, getDisbursementDate()); } public Date getScheduleViewDateValue(Locale locale) throws InvalidDateException { if(scheduleViewDate==null){ scheduleViewDate = LoanUIHelperFn.getCurrrentDate(locale); } return DateUtils.getLocaleDate(locale, scheduleViewDate); } public Date getFirstRepaymentDayValue(Locale locale) throws InvalidDateException { return DateUtils.getLocaleDate(locale, getFirstRepaymentDay()); } public boolean isInterestDedAtDisbValue() { return getBooleanValue(getIntDedDisbursement()); } public Double getInterestDoubleValue() { return getDoubleValue(getInterestRate()); } public Short getLoanOfferingFundValue() { return getShortValue(getLoanOfferingFund()); } public Integer getBusinessActivityIdValue() { return getIntegerValue(getBusinessActivityId()); } public Integer getCollateralTypeIdValue() { return getIntegerValue(getCollateralTypeId()); } public FeeDto getDefaultFee(int i) { while (i >= defaultFees.size()) { defaultFees.add(new FeeDto()); } return defaultFees.get(i); } public Boolean isInterestDeductedAtDisbursement() { if (getIntDedDisbursement().equals("1")) { return true; } return false; } public void initializeTransactionFields(List<PaymentDataHtmlBean> paymentDataBeans) { this.paymentDataBeans = paymentDataBeans; } public List<FeeDto> getFeesToApply() { List<FeeDto> feesToApply = new ArrayList<FeeDto>(); for (FeeDto fee : getAdditionalFees()) { if (fee.getFeeIdValue() != null) { feesToApply.add(fee); } } for (FeeDto fee : getDefaultFees()) { if (!fee.isRemoved()) { feesToApply.add(fee); } } return feesToApply; } public boolean isDefaultFeeRemoved() { for (FeeDto fee : getDefaultFees()) { if (fee.isRemoved()) { return true; } } return false; } public FeeDto getSelectedFee(int index) { while (index >= additionalFees.size()) { additionalFees.add(new FeeDto()); } return additionalFees.get(index); } @Override public void reset(ActionMapping mapping, HttpServletRequest request) { super.reset(mapping, request); String method = request.getParameter(Methods.method.toString()); if (method.equals(Methods.schedulePreview.toString())) { intDedDisbursement = null; for (int i = 0; i < defaultFees.size(); i++) { // if an already checked fee is unchecked then the value set to // 0 if (request.getParameter("defaultFee[" + i + "].feeRemoved") == null) { defaultFees.get(i).setFeeRemoved(YesNoFlag.NO.getValue()); } } } else if (method.equals(Methods.load.toString())) { cashflowDataDtos = null; clients = new ArrayList<String>(); } else if (method.equals(Methods.managePreview.toString())) { intDedDisbursement = "0"; } } @Override public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { String method = request.getParameter(Methods.method.toString()); ActionErrors errors = new ActionErrors(); if (null == request.getAttribute(Constants.CURRENTFLOWKEY)) { request.setAttribute(Constants.CURRENTFLOWKEY, request.getParameter(Constants.CURRENTFLOWKEY)); } try { if (method.equals(Methods.getPrdOfferings.toString())) { checkValidationForGetPrdOfferings(errors); } else if (method.equals(Methods.load.toString())) { checkValidationForLoad(errors); } else if (method.equals(Methods.schedulePreview.toString())) { checkValidationForSchedulePreview(errors, getCurrencyFromLoanOffering(request), request); } else if (method.equals(Methods.managePreview.toString())) { checkValidationForManagePreview(errors, getCurrencyFromLoanOffering(request), request); } else if (method.equals(Methods.preview.toString())) { checkValidationForPreview(errors, getCurrencyFromLoanOffering(request), request); } } catch (ApplicationException ae) { // Discard other errors (is that right?) ae.printStackTrace(); errors = new ActionErrors(); errors.add(ae.getKey(), new ActionMessage(ae.getKey(), ae.getValues())); } if (!errors.isEmpty()) { request.setAttribute(LoanConstants.METHODCALLED, method); } return errors; } protected void validateLoanAmount(ActionErrors errors, Locale locale, MifosCurrency currency) { DoubleConversionResult conversionResult = validateAmount(getLoanAmount(), currency, LoanConstants.LOAN_AMOUNT_KEY, errors, ""); Double loanAmountValue = conversionResult.getDoubleValue(); if (conversionResult.getErrors().size() == 0) { if (loanAmountValue <= 0.0) { addError(errors, LoanConstants.LOAN_AMOUNT_KEY, LoanConstants.ERRORS_MUST_BE_GREATER_THAN_ZERO, getLocalizedMessage(LoanConstants.LOAN_AMOUNT_KEY)); } else { this.loanAmountValue = new Money(currency, loanAmountValue); } } } protected void validateInterest(ActionErrors errors, Locale locale) { DoubleConversionResult conversionResult = validateInterest(getInterestRate(), LoanConstants.LOAN_INTEREST_RATE_KEY, errors); if (conversionResult.getErrors().size() == 0 && !(conversionResult.getDoubleValue() >= 0.0)) { addError(errors, LoanConstants.LOAN_INTEREST_RATE_KEY, LoanConstants.ERRORS_MUST_NOT_BE_NEGATIVE, getLocalizedMessage(LoanConstants.LOAN_INTEREST_RATE_KEY)); } } protected void validateDefaultFee(ActionErrors errors, Locale locale, MifosCurrency currency) { for (FeeDto defaultFee : defaultFees) { if (defaultFee.getFeeType().equals(RateAmountFlag.AMOUNT)) { DoubleConversionResult conversionResult = validateAmount(defaultFee.getAmount(), currency, LoanConstants.LOAN_DEFAULT_FEE_KEY, errors, ""); if (conversionResult.getErrors().size() == 0 && !(conversionResult.getDoubleValue() > 0.0)) { addError(errors, LoanConstants.LOAN_DEFAULT_FEE_KEY, LoanConstants.ERRORS_MUST_BE_GREATER_THAN_ZERO, getLocalizedMessage(LoanConstants.LOAN_DEFAULT_FEE_KEY)); } } else { DoubleConversionResult conversionResult = validateInterest(defaultFee.getAmount(), LoanConstants.LOAN_DEFAULT_FEE_KEY, errors); if (conversionResult.getErrors().size() == 0 && !(conversionResult.getDoubleValue() > 0.0)) { addError(errors, LoanConstants.LOAN_DEFAULT_FEE_KEY, LoanConstants.ERRORS_MUST_BE_GREATER_THAN_ZERO, getLocalizedMessage(LoanConstants.LOAN_DEFAULT_FEE_KEY)); } } } } protected void validateAdditionalFee(ActionErrors errors, Locale locale, MifosCurrency currency, HttpServletRequest request) throws PageExpiredException { Map<String, Boolean> addedFees = new HashMap<String, Boolean>(); List<FeeDto> additionalFeeList = (List<FeeDto>) SessionUtils.getAttribute(LoanConstants.ADDITIONAL_FEES_LIST,request); for (FeeDto additionalFee : additionalFees) { if (additionalFee.getAmount() != null && !additionalFee.getAmount().equals("")) { FeeDto additionalFeeDetails = getAdditionalFeeType(additionalFeeList, additionalFee.getFeeId()); if (additionalFeeDetails.getFeeType().equals(RateAmountFlag.AMOUNT)) { DoubleConversionResult conversionResult = validateAmount(additionalFee.getAmount(), currency, LoanConstants.LOAN_ADDITIONAL_FEE_KEY, errors, ""); if(validPositiveValue(errors, locale, conversionResult)) { validateFeeTypeIfVariableInstallmentLoanType(errors, additionalFeeDetails); } } else { DoubleConversionResult conversionResult = validateInterest(additionalFee.getAmount(), LoanConstants.LOAN_ADDITIONAL_FEE_KEY, errors); if(validPositiveValue(errors, locale, conversionResult)) { validateFeeTypeIfVariableInstallmentLoanType(errors, additionalFeeDetails); } } if (!additionalFeeDetails.isPeriodic() && addedFees.get(additionalFeeDetails.getFeeId()) != null) { addError(errors, "AdditionalFee", ProductDefinitionConstants.MULTIPLE_ONE_TIME_FEES_NOT_ALLOWED); } addedFees.put(additionalFeeDetails.getFeeId(), true); } } } private void validateFeeTypeIfVariableInstallmentLoanType(ActionErrors errors, FeeDto additionalFeeDetails) { if (isVariableInstallmentsAllowed()) { if (additionalFeeDetails.isPeriodic()) { addError(errors, "AdditionalFee", ProductDefinitionConstants.PERIODIC_FEE_NOT_APPLICABLE, additionalFeeDetails.getFeeName()); } else if (additionalFeeDetails.getFeeType().equals(RateAmountFlag.RATE)) { FeeFormula feeFormula = additionalFeeDetails.getFeeFormulaValue(); if (feeFormula != null) { if (feeFormula.equals(FeeFormula.AMOUNT_AND_INTEREST)) { addError(errors, "AdditionalFee", ProductDefinitionConstants.FEE_WITH_PERCENT_INTEREST_NOT_APPLICABLE, additionalFeeDetails.getFeeName()); } else if (feeFormula.equals(FeeFormula.INTEREST)) { addError(errors, "AdditionalFee", ProductDefinitionConstants.FEE_WITH_PERCENT_INTEREST_NOT_APPLICABLE, additionalFeeDetails.getFeeName()); } } } } } private boolean validPositiveValue(ActionErrors errors, Locale locale, DoubleConversionResult conversionResult) { boolean result = true; if (conversionResult.getErrors().size() == 0 && !(conversionResult.getDoubleValue() > 0.0)) { addError(errors, LoanConstants.LOAN_ADDITIONAL_FEE_KEY, LoanConstants.ERRORS_MUST_BE_GREATER_THAN_ZERO, getLocalizedMessage( LoanConstants.LOAN_ADDITIONAL_FEE_KEY)); result = false; } return result; } private FeeDto getAdditionalFeeType(List<FeeDto> additionalFeeList, String feeId) { for (FeeDto fee : additionalFeeList) { if (fee.getFeeId().equals(feeId)) { return fee; } } return null; } // TODO: use localized strings for error messages rather than hardcoded private void checkValidationForGetPrdOfferings(ActionErrors errors) { if (StringUtils.isBlank(getCustomerId())) { addError(errors, LoanConstants.CUSTOMER, LoanConstants.CUSTOMERNOTSELECTEDERROR, getLabel( ConfigurationConstants.CLIENT), getLabel(ConfigurationConstants.GROUP)); } } // TODO: use localized strings for error messages rather than hardcoded private void checkValidationForLoad(ActionErrors errors) { checkValidationForGetPrdOfferings(errors); if (StringUtils.isBlank(getPrdOfferingId())) { String instanceName = this.getLocalizedMessage("loan.instancename"); addError(errors, LoanConstants.PRDOFFERINGID, LoanConstants.LOANOFFERINGNOTSELECTEDERROR, getLabel( ConfigurationConstants.LOAN), instanceName); } } private MifosCurrency getCurrencyFromLoanOffering(HttpServletRequest request){ LoanOfferingBO loanOfferingBO = getLoanOffering(request); return loanOfferingBO != null ? loanOfferingBO.getCurrency() : null; } private LoanOfferingBO getLoanOffering(HttpServletRequest request) { try { return ((LoanOfferingBO) SessionUtils.getAttribute(LoanConstants.LOANOFFERING, request)); } catch (PageExpiredException e) { return null; } } private void checkValidationForSchedulePreview(ActionErrors errors, MifosCurrency currency, HttpServletRequest request) throws ApplicationException { Locale locale = getUserContext(request).getPreferredLocale(); checkValidationForPreviewBefore(errors, request); validateFees(request, errors); validateCustomFields(request, errors); performGlimSpecificValidations(errors, currency, request); validateRepaymentDayRequired(errors); if (!configService.isNewGlimEnabled() || !configService.isGlimEnabled() || !getCustomer(request).isGroup()) { validatePurposeOfLoanFields(errors, getMandatoryFields(request)); } validateSourceOfFundFields(errors, getMandatoryFields(request)); validateExternalIDFields(errors, getMandatoryFields(request)); validateLoanAmount(errors, locale, currency); validateInterest(errors, locale); validateCollateralNotes(errors, locale); validateDefaultFee(errors, locale, currency); validateAdditionalFee(errors, locale, currency, request); } private void validateCollateralNotes(ActionErrors errors, Locale userLocale) { String note = getLocalizedMessage("loan.collateral_notes"); String collateralNote = getCollateralNote(); if (collateralNote != null && collateralNote.length() > 500) { addError(errors, LoanConstants.NOTE, LoanConstants.MAX_LENGTH, note, String .valueOf(LoanConstants.COMMENT_LENGTH)); } } private void validateClientDetails(ActionErrors errors, Locale locale) { for (LoanAccountDetailsDto clientDetail : clientDetails) { } } private void performGlimSpecificValidations(ActionErrors errors, MifosCurrency currency, HttpServletRequest request) throws PageExpiredException, PersistenceException { if ((configService.isNewGlimEnabled() || configService.isGlimEnabled()) && getCustomer(request).isGroup()) { Locale locale = getUserContext(request).getPreferredLocale(); removeClientsNotCheckedInForm(request); validateIndividualLoanFieldsForGlim(errors, locale, currency); validateSelectedClients(errors); validatePurposeOfLoanForGlim(errors, getMandatoryFields(request)); } } // Since this Struts form is set up as "session" scope, we need to clear // the form fields in cases where they are used across pages. // Currently we do that in the following case: When old values of clientId // are // retained from the account creation page, form validation // on submission from the Edit Account Information page is messed up. // Calling // this method fixes that problem private void removeClientsNotCheckedInForm(HttpServletRequest request) { List<String> clientIds = getSelectedClientIdsFromRequest(request); setClientsNotPresentInInputToEmptyString(clientIds); } void setClientsNotPresentInInputToEmptyString(List<String> clientIds) { for (int i = 0; i < clients.size(); i++) { if (!clientIds.contains(clients.get(i))) { clients.set(i, ""); } } } List<String> getSelectedClientIdsFromRequest(HttpServletRequest request) { Collection<?> paramsStartingWithClients = CollectionUtils.select(convertEnumerationToList(request .getParameterNames()), new Predicate() { @Override public boolean evaluate(Object object) { return ((String) object).startsWith("clients"); } }); return extractClientIdsFromRequest(request, paramsStartingWithClients); } private List<String> extractClientIdsFromRequest(HttpServletRequest request, Collection<?> paramsStartingWithClients) { List<String> clientIds = new ArrayList<String>(); for (Object name : paramsStartingWithClients) { String element = (String) name; clientIds.add(request.getParameter(element)); } return clientIds; } private List<String> convertEnumerationToList(Enumeration<?> parameterNames) { List<String> params = new ArrayList<String>(); while (parameterNames.hasMoreElements()) { params.add((String) parameterNames.nextElement()); } return params; } void validatePurposeOfLoanForGlim(ActionErrors errors, List<FieldConfigurationEntity> mandatoryFields) { if (!isPurposeOfLoanMandatory(mandatoryFields)) { return; } List<String> ids_clients_selected = getClients(); List<LoanAccountDetailsDto> listdetail = getClientDetails(); for (LoanAccountDetailsDto loanAccount : listdetail) { if (ids_clients_selected.contains(loanAccount.getClientId())) { if (StringUtils.isBlank(loanAccount.getBusinessActivity())) { addErrorInvalidPurpose(errors); return; } } } } private void addErrorInvalidPurpose(ActionErrors errors) { addError(errors, LoanExceptionConstants.CUSTOMER_PURPOSE_OF_LOAN_FIELD); } private void addErrorInvalidSource(ActionErrors errors) { addError(errors, LoanExceptionConstants.CUSTOMER_SOURCE_OF_FUND_FIELD); } private void addErrorInvalidExternalId(ActionErrors errors) { addError(errors, LoanExceptionConstants.CUSTOMER_EXTERNAL_ID_FIELD); } private void validatePurposeOfLoanFields(ActionErrors errors, List<FieldConfigurationEntity> mandatoryFields) { if (isPurposeOfLoanMandatory(mandatoryFields) && StringUtils.isBlank(getBusinessActivityId())) { addErrorInvalidPurpose(errors); } } private void validateSourceOfFundFields(ActionErrors errors, List<FieldConfigurationEntity> mandatoryFields) { if (isSourceOfFundMandatory(mandatoryFields) && StringUtils.isBlank(getLoanOfferingFund())) { addErrorInvalidSource(errors); } } private void validateExternalIDFields(ActionErrors errors, List<FieldConfigurationEntity> mandatoryFields) { if (isExternalIDMandatory(mandatoryFields) && StringUtils.isBlank(getExternalId())) { addErrorInvalidExternalId(errors); } } private void checkValidationForPreview(ActionErrors errors, MifosCurrency currency, HttpServletRequest request) { if (isRedoOperation()) { validateRedoLoanPayments(request, errors, currency); } } private void checkValidationForManagePreview(ActionErrors errors, MifosCurrency currency, HttpServletRequest request) throws ApplicationException { Locale locale = getUserContext(request).getPreferredLocale(); if (getState().equals(AccountState.LOAN_PARTIAL_APPLICATION) || getState().equals(AccountState.LOAN_PENDING_APPROVAL)) { checkValidationForPreviewBefore(errors, request); checkValidationForPreview(errors, currency, request); // Only validate the disbursement date before a loan has been approved. After // approval, it cannot be edited. try { // only validate if the disbursement date has changed if (!getDisbursementDateValue(getUserContext(request).getPreferredLocale()).equals( getOriginalDisbursementDate())) { validateDisbursementDate(errors, getCustomer(request), getDisbursementDateValue(getUserContext( request).getPreferredLocale())); } } catch (InvalidDateException dateException) { addError(errors, LoanExceptionConstants.ERROR_INVALIDDISBURSEMENTDATE); } } performGlimSpecificValidations(errors, currency, request); validateCustomFields(request, errors); validateRepaymentDayRequired(errors); if (!configService.isNewGlimEnabled() || !configService.isGlimEnabled() || !getCustomer(request).isGroup()) { validatePurposeOfLoanFields(errors, getMandatoryFields(request)); } validateSourceOfFundFields(errors, getMandatoryFields(request)); validateExternalIDFields(errors, getMandatoryFields(request)); validateLoanAmount(errors, locale, currency); validateInterest(errors, locale); validateCollateralNotes(errors, locale); } private void validateDisbursementDate(ActionErrors errors, CustomerBO customer, java.sql.Date disbursementDateValue) throws AccountException, ServiceException { if (!configService.isRepaymentIndepOfMeetingEnabled() && !LoanBO.isDisbursementDateValid(customer, disbursementDateValue)) { addError(errors, LoanExceptionConstants.INVALIDDISBURSEMENTDATE); } } private void checkValidationForPreviewBefore(ActionErrors errors, HttpServletRequest request) throws ApplicationException { LoanOfferingBO loanOffering = (LoanOfferingBO) SessionUtils.getAttribute(LoanConstants.LOANOFFERING, request); if (!((configService.isNewGlimEnabled() || configService.isGlimEnabled()) && getCustomer(request).isGroup())) { checkForMinMax(errors, loanAmount, amountRange, this.getLocalizedMessage("loan.amount")); } checkForMinMax(errors, interestRate, maxInterestRate, minInterestRate, this.getLocalizedMessage("loan.interestRate")); checkForMinMax(errors, noOfInstallments, installmentRange, this.getLocalizedMessage("loan.noOfInstallments")); if (StringUtils.isBlank(getDisbursementDate())) { addError(errors, "Proposed/Actual disbursal date", "errors.validandmandatory", this.getLocalizedMessage("loan.disbursalDate")); } // Check for invalid data format try { DateUtils.getLocaleDate(Locale.ENGLISH, getDisbursementDate()); } catch (InvalidDateException ide) { addError(errors, "Proposed/Actual disbursal date", LoanExceptionConstants.ERROR_INVALID_DISBURSEMENT_DATE_FORMAT, this.getLocalizedMessage("loan.disbursalDate")); } if (isInterestDedAtDisbValue()) { setGracePeriodDuration("0"); } if (((!isInterestDedAtDisbValue()) && StringUtils.isBlank(getGracePeriodDuration())) || (getDoubleValue(getGracePeriodDuration()) != null && getDoubleValue(getNoOfInstallments()) != null && getDoubleValue(getGracePeriodDuration()) >= getDoubleValue(getNoOfInstallments()))) { String gracePeriodForRepayments = this.getLocalizedMessage("loan.grace_period"); String noInst = StringUtils.isBlank(getNoOfInstallments()) ? getStringValue(installmentRange .getMaxNoOfInstall()) : getNoOfInstallments(); addError(errors, LoanConstants.GRACEPERIODDURATION, LoanConstants.GRACEPERIODERROR, gracePeriodForRepayments, noInst); } } void checkForMinMax(ActionErrors errors, String currentValue, AmountRange amountRange, String field) { try { if (isBlank(currentValue) || !amountRange.isInRange(getDoubleValue(currentValue))) { addError(errors, field, LoanExceptionConstants.INVALIDMINMAX, field, getStringValue(amountRange .getMinLoanAmount()), getStringValue(amountRange.getMaxLoanAmount())); } } catch (NumberFormatException nfe) { addError(errors, field, LoanExceptionConstants.INVALIDMINMAX, field, getStringValue(amountRange .getMinLoanAmount()), getStringValue(amountRange.getMaxLoanAmount())); } } void checkForMinMax(ActionErrors errors, String currentValue, InstallmentRange installmentRange, String field) { try { if (StringUtils.isBlank(currentValue) || !installmentRange.isInRange(getShortValue(currentValue))) { addError(errors, field, LoanExceptionConstants.INVALIDMINMAX, field, getStringValue(installmentRange .getMinNoOfInstall()), getStringValue(installmentRange.getMaxNoOfInstall())); } } catch (NumberFormatException nfe) { addError(errors, field, LoanExceptionConstants.INVALIDMINMAX, field, getStringValue(installmentRange .getMinNoOfInstall()), getStringValue(installmentRange.getMaxNoOfInstall())); } } private void checkForMinMax(ActionErrors errors, String currentValue, Double maxValue, Double minValue, String field) { try { if (StringUtils.isBlank(currentValue) || getDoubleValue(currentValue) > maxValue || getDoubleValue(currentValue) < minValue) { addError(errors, field, LoanExceptionConstants.INVALIDMINMAX, field, getStringValue(minValue), getStringValue(maxValue)); } } catch (NumberFormatException nfe) { addError(errors, field, LoanExceptionConstants.INVALIDMINMAX, field, getStringValue(minValue), getStringValue(maxValue)); } } protected void validateFees(HttpServletRequest request, ActionErrors errors) throws ApplicationException { validateForFeeAmount(errors); validateForDuplicatePeriodicFee(request, errors); } protected void validateForFeeAmount(ActionErrors errors) { List<FeeDto> feeList = getFeesToApply(); for (FeeDto fee : feeList) { if (StringUtils.isBlank(fee.getAmount())) { errors.add(LoanConstants.FEE, new ActionMessage(LoanConstants.ERRORS_SPECIFY_FEE_AMOUNT)); } } } protected void validateForDuplicatePeriodicFee(HttpServletRequest request, ActionErrors errors) throws ApplicationException { List<FeeDto> additionalFeeList = (List<FeeDto>) SessionUtils.getAttribute(LoanConstants.ADDITIONAL_FEES_LIST, request); for (FeeDto selectedFee : getAdditionalFees()) { int count = 0; for (FeeDto duplicateSelectedfee : getAdditionalFees()) { if (selectedFee.getFeeIdValue() != null && selectedFee.getFeeId().equals(duplicateSelectedfee.getFeeId())) { if (isSelectedFeePeriodic(selectedFee, additionalFeeList)) { count++; } } } if (count > 1) { errors.add(LoanConstants.FEE, new ActionMessage(LoanConstants.ERRORS_DUPLICATE_PERIODIC_FEE)); break; } } } private boolean isSelectedFeePeriodic(FeeDto selectedFee, List<FeeDto> additionalFeeList) { for (FeeDto fee : additionalFeeList) { if (fee.getFeeId().equals(selectedFee.getFeeId())) { return fee.isPeriodic(); } } return false; } private void validateCustomFields(HttpServletRequest request, ActionErrors errors) { try { List<CustomFieldDefinitionEntity> customFieldDefs = (List<CustomFieldDefinitionEntity>) SessionUtils .getAttribute(LoanConstants.CUSTOM_FIELDS, request); for (CustomFieldDto customField : customFields) { for (CustomFieldDefinitionEntity customFieldDef : customFieldDefs) { if (customField.getFieldId().equals(customFieldDef.getFieldId())) { if (customFieldDef.isMandatory() && StringUtils.isBlank(customField.getFieldValue())) { errors.add(LoanConstants.CUSTOM_FIELDS, new ActionMessage( LoanConstants.ERRORS_SPECIFY_CUSTOM_FIELD_VALUE, customFieldDef.getLabel())); } if (CustomFieldType.fromInt(customField.getFieldId()).equals(CustomFieldType.DATE) && (StringUtils.isNotBlank(customField.getFieldValue()))) { try { DateUtils.getDate(customField.getFieldValue()); } catch (Exception e) { errors.add(LoanConstants.CUSTOM_FIELDS, new ActionMessage( LoanConstants.ERRORS_CUSTOM_DATE_FIELD, customFieldDef.getLabel())); } } break; } } } } catch (PageExpiredException pee) { errors.add(ExceptionConstants.PAGEEXPIREDEXCEPTION, new ActionMessage( ExceptionConstants.PAGEEXPIREDEXCEPTION)); } } void validateSelectedClients(ActionErrors errors) { List<String> selectedClients = new ArrayList<String>(); for (String id : getClients()) { if (StringUtils.isNotBlank(id)) { selectedClients.add(id); } } if (selectedClients.size() < LoanConstants.MINIMUM_NUMBER_OF_CLIENTS_IN_GROUP_LOAN) { addError(errors, "", LoanExceptionConstants.NUMBER_OF_SELECTED_MEMBERS_IS_LESS_THAN_TWO, ""); } } public boolean isAmountZeroOrNull(String loanAmount) { return StringUtils.isBlank(loanAmount) || (Double.compare(new LocalizationConverter().getDoubleValueForCurrentLocale(loanAmount), NumberUtils.DOUBLE_ZERO) == 0); } void validateSumOfTheAmountsSpecified(ActionErrors errors) { List<String> ids_clients_selected = getClients(); double totalAmount = new Double(0); boolean foundInvalidAmount = false; for (LoanAccountDetailsDto loanDetail : getClientDetails()) { if (!foundInvalidAmount) { if (ids_clients_selected.contains(loanDetail.getClientId())) { if (isAmountZeroOrNull(loanDetail.getLoanAmount())) { addError(errors, LoanExceptionConstants.CUSTOMER_LOAN_AMOUNT_FIELD); foundInvalidAmount = true; } else { totalAmount = totalAmount + new LocalizationConverter() .getDoubleValueForCurrentLocale(loanDetail.getLoanAmount()); } } } } if (!foundInvalidAmount && (StringUtils.isBlank(Double.valueOf(totalAmount).toString()) || !amountRange.isInRange(totalAmount))) { addError(errors, LoanConstants.LOANAMOUNT, LoanExceptionConstants.SUM_OF_INDIVIDUAL_AMOUNTS_IS_NOT_IN_THE_RANGE_OF_ALLOWED_AMOUNTS, getStringValue(amountRange.getMinLoanAmount()), getStringValue(amountRange.getMaxLoanAmount())); } } private void addError(ActionErrors errors, String errorCode) { errors.add(errorCode, new ActionMessage(errorCode)); } private void validateRepaymentDayRequired(ActionErrors errors) { Short recurrenceId = RecurrenceType.WEEKLY.getValue(); if (null != this.getRecurrenceId()) { recurrenceId = new Short(this.getRecurrenceId()); } if (new ConfigurationPersistence().isRepaymentIndepOfMeetingEnabled()) { if (StringUtils.isBlank(this.getFrequency())) { addError(errors, "", LoanExceptionConstants.REPAYMENTDAYISREQUIRED, ""); } else if (RecurrenceType.WEEKLY.getValue().equals(recurrenceId)) { if (StringUtils.isBlank(this.getRecurWeek()) || StringUtils.isBlank(this.getWeekDay())) { addError(errors, "", LoanExceptionConstants.REPAYMENTDAYISREQUIRED, ""); } else { try{ Short.parseShort(this.getRecurWeek()); } catch (NumberFormatException e) { addError(errors, "", LoanExceptionConstants.REPAYMENTDAY_WRONGFORMAT, ""); } } } else { if (getMonthType().equals("1")) { // "10th day of the month" if (StringUtils.isBlank(this.getMonthDay()) || StringUtils.isBlank(this.getDayRecurMonth())) { addError(errors, "", LoanExceptionConstants.REPAYMENTDAYISREQUIRED, ""); } short dayNumber = dayMonthParse(); if ((dayNumber < 1 || dayNumber > 31)) { addError(errors, "", LoanExceptionConstants.REPAYMENTDAY_WRONGFORMAT, ""); } } else { // "1st Monday of every month" if (StringUtils.isBlank(this.getMonthRank()) || StringUtils.isBlank(this.getMonthWeek()) || StringUtils.isBlank(this.getRecurMonth())) { addError(errors, "", LoanExceptionConstants.REPAYMENTDAYISREQUIRED, ""); } } } } } private short dayMonthParse() { short dayNumber; try{ dayNumber = Short.parseShort(this.getMonthDay()); } catch (NumberFormatException err){ dayNumber=0; } return dayNumber; } private void validateIndividualLoanFieldsForGlim(ActionErrors errors, Locale locale, MifosCurrency currency) { int errorsBeforeLoanAmountsValidation = errors.size(); for (LoanAccountDetailsDto listDetail : clientDetails) { if (getClients().contains(listDetail.getClientId())) { DoubleConversionResult conversionResult = validateAmount(listDetail.getLoanAmount(), currency, LoanConstants.LOAN_AMOUNT_KEY, errors, ""); if (conversionResult.getErrors().size() == 0 && !(conversionResult.getDoubleValue() > 0.0)) { addError(errors, LoanConstants.LOAN_AMOUNT_KEY, LoanConstants.ERRORS_MUST_BE_GREATER_THAN_ZERO, getLocalizedMessage(LoanConstants.LOAN_AMOUNT_KEY)); } } else { if (!listDetail.isEmpty()) { addError(errors, "", LoanExceptionConstants.LOAN_DETAILS_ENTERED_WITHOUT_SELECTING_INDIVIDUAL, ""); break; } } } int amountValidationErrors = errors.size() - errorsBeforeLoanAmountsValidation; if (amountValidationErrors == 0) { validateSumOfTheAmountsSpecified(errors); } } private List<FieldConfigurationEntity> getMandatoryFields(HttpServletRequest request) { Map<Short, List<FieldConfigurationEntity>> entityMandatoryFieldMap = (Map<Short, List<FieldConfigurationEntity>>) request .getSession().getServletContext().getAttribute(Constants.FIELD_CONFIGURATION); List<FieldConfigurationEntity> mandatoryfieldList = entityMandatoryFieldMap.get(EntityType.LOAN.getValue()); return mandatoryfieldList; } private boolean isPurposeOfLoanMandatory(List<FieldConfigurationEntity> mandatoryfieldList) { boolean isMandatory = false; for (FieldConfigurationEntity entity : mandatoryfieldList) { if (entity.getFieldName().equalsIgnoreCase(LoanConstants.PURPOSE_OF_LOAN)) { isMandatory = true; break; } } return isMandatory; } private boolean isSourceOfFundMandatory(List<FieldConfigurationEntity> mandatoryfieldList) { boolean isMandatory = false; for (FieldConfigurationEntity entity : mandatoryfieldList) { if (entity.getFieldName().equalsIgnoreCase(LoanConstants.SOURCE_OF_FUND)) { isMandatory = true; break; } } return isMandatory; } private boolean isExternalIDMandatory(List<FieldConfigurationEntity> mandatoryfieldList) { boolean isMandatory = false; for (FieldConfigurationEntity entity : mandatoryfieldList) { if (entity.getFieldName().equalsIgnoreCase(LoanConstants.EXTERNAL_ID)) { isMandatory = true; break; } } return isMandatory; } private void validateRedoLoanPayments(HttpServletRequest request, ActionErrors errors, MifosCurrency currency) { Locale locale = getUserContext(request).getPreferredLocale(); try { CustomerBO customer = getCustomer(request); List<PaymentDataHtmlBean> validPaymentBeans = getValidatablePaymentBeans(); for (PaymentDataHtmlBean bean : validPaymentBeans) { validatePaymentDataHtmlBean(errors, currency, locale, customer, bean); } validatePaymentDatesOrdering(validPaymentBeans, errors); validateMaxPayableAmount(request, errors); } catch (InvalidDateException invalidDate) { errors.add(LoanExceptionConstants.INVALIDTRANSACTIONDATE, new ActionMessage( LoanExceptionConstants.INVALIDTRANSACTIONDATE)); } catch (FrameworkRuntimeException invalidDate) { errors.add(LoanExceptionConstants.INVALIDTRANSACTIONDATE, new ActionMessage( LoanExceptionConstants.INVALIDTRANSACTIONDATE)); } catch (MeetingException e) { errors.add(ExceptionConstants.FRAMEWORKRUNTIMEEXCEPTION, new ActionMessage( ExceptionConstants.FRAMEWORKRUNTIMEEXCEPTION)); } catch (PageExpiredException e) { errors.add(ExceptionConstants.PAGEEXPIREDEXCEPTION, new ActionMessage( ExceptionConstants.PAGEEXPIREDEXCEPTION)); } catch (PersistenceException e) { errors.add(ExceptionConstants.FRAMEWORKRUNTIMEEXCEPTION, new ActionMessage( ExceptionConstants.FRAMEWORKRUNTIMEEXCEPTION)); } } private void validateMaxPayableAmount(HttpServletRequest request, ActionErrors errors) throws InvalidDateException { Money totalAmount = Money.zero(getCurrencyFromLoanOffering(request)); Money paymentAmount = Money.zero(getCurrencyFromLoanOffering(request)); for (PaymentDataHtmlBean paymentDataHtmlBean : getPaymentDataBeans()) { totalAmount = totalAmount.add(paymentDataHtmlBean.totalAsMoney()); paymentAmount = paymentAmount.add(paymentDataHtmlBean.paymentAmountAsMoney()); } if (paymentAmount.isGreaterThan(totalAmount)) { errors.add(LoanExceptionConstants.EXCESS_PAYMENT, new ActionMessage( LoanExceptionConstants.EXCESS_PAYMENT)); } } private List<PaymentDataHtmlBean> getValidatablePaymentBeans() { return select(paymentDataBeans, new org.mifos.framework.util.helpers.Predicate<PaymentDataHtmlBean>() { @Override public boolean evaluate(PaymentDataHtmlBean bean) { return bean.hasValidAmount(); } }); } void validatePaymentDatesOrdering(List<PaymentDataHtmlBean> validPaymentBeans, ActionErrors errors) { List<java.util.Date> transactionDates = collect(validPaymentBeans, new Transformer<PaymentDataHtmlBean, java.util.Date>() { @Override public java.util.Date transform(PaymentDataHtmlBean input) { return input.getTransactionDate(); } }); int indexOutOfOrder = itemIndexOutOfAscendingOrder(transactionDates); if (indexOutOfOrder >= 0) { String installmentNumber = validPaymentBeans.get(indexOutOfOrder).getInstallmentNumber(); String errorCode = LoanExceptionConstants.INVALIDTRANSACTIONDATEORDER; errors.add(errorCode, new ActionMessage(errorCode, installmentNumber)); } } private void validatePaymentDataHtmlBean(ActionErrors errors, MifosCurrency currency, Locale locale, CustomerBO customer, PaymentDataHtmlBean bean) throws MeetingException, InvalidDateException { validateTransactionDateOnPayment(errors, bean); if (bean.hasValidAmount() && bean.hasTransactionDate()) { if (customer.isValidMeetingDate(bean.getTransactionDate())) { validateTotalAmount(errors, locale, currency, bean); validateTransactionDate(errors, bean, getDisbursementDateValue(locale)); } else { errors.add(LoanExceptionConstants.INVALIDTRANSACTIONDATE, new ActionMessage( LoanExceptionConstants.INVALIDTRANSACTIONDATE)); } } } void validateTransactionDateOnPayment(ActionErrors errors, PaymentDataHtmlBean bean) { if (bean.hasValidAmount() && bean.hasNoTransactionDate()) { errors.add(LoanExceptionConstants.INVALIDTRANSACTIONDATE, new ActionMessage( LoanExceptionConstants.INVALIDTRANSACTIONDATE)); } } protected void validateTotalAmount(ActionErrors errors, Locale locale, MifosCurrency currency, PaymentDataHtmlBean bean) { String installmentNo = bean.getInstallment().getInstallmentNumberAsString(); DoubleConversionResult conversionResult = validateAmount(bean.getAmount(), currency, LoanConstants.LOAN_AMOUNT_KEY, errors, " "+ installmentNo); if (conversionResult.getErrors().size() == 0 && !(conversionResult.getDoubleValue() > 0.0)) { addError(errors, LoanConstants.LOAN_AMOUNT_KEY, LoanConstants.ERRORS_MUST_BE_GREATER_THAN_ZERO, getLocalizedMessage(LoanConstants.LOAN_AMOUNT_KEY), installmentNo); } } void validateTransactionDate(ActionErrors errors, PaymentDataHtmlBean template, java.util.Date disbursementDate) { if (template.hasTotalAmount()) { try { if (!DateUtils.dateFallsOnOrBeforeDate(template.getTransactionDate(), DateUtils.currentDate())) { errors.add(LoanExceptionConstants.INVALIDTRANSACTIONDATEFORPAYMENT, new ActionMessage( LoanExceptionConstants.INVALIDTRANSACTIONDATEFORPAYMENT)); } else if (!DateUtils.dateFallsBeforeDate(disbursementDate, template.getTransactionDate())) { errors.add(LoanExceptionConstants.INVALIDTRANSACTIONDATE, new ActionMessage( LoanExceptionConstants.INVALIDTRANSACTIONDATE)); } } catch (FrameworkRuntimeException ide) { errors.add(LoanExceptionConstants.INVALIDTRANSACTIONDATEFORPAYMENT, new ActionMessage( LoanExceptionConstants.INVALIDTRANSACTIONDATEFORPAYMENT)); } } } private CustomerBO getCustomer(Integer customerId) throws PersistenceException { return new CustomerPersistence().getCustomer(customerId); } /** * FIXME - keithw - loan refactoring - try to remove this usage from validation stages */ @Deprecated private CustomerBO getCustomer(HttpServletRequest request) throws PageExpiredException, PersistenceException { CustomerDetailDto oldCustomer = (CustomerDetailDto) SessionUtils.getAttribute(LoanConstants.LOANACCOUNTOWNER, request); Integer oldCustomerId; if (oldCustomer == null) { oldCustomerId = Integer.parseInt(getCustomerId()); } else { oldCustomerId = oldCustomer.getCustomerId(); } return getCustomer(oldCustomerId); } public String getPerspective() { return perspective; } public void setPerspective(String perspective) { this.perspective = perspective; } public List<String> getClients() { return clients; } public void setClients(List<String> clients) { this.clients = clients; } public String getClients(int i) { while (i >= clients.size()) { clients.add(""); } return clients.get(i).toString(); } public void setClients(int i, String string) { while (this.clients.size() <= i) { this.clients.add(new String()); } this.clients.set(i, string); } public List<LoanAccountDetailsDto> getClientDetails() { return clientDetails; } public void setClientDetails(List<LoanAccountDetailsDto> clientDetails) { this.clientDetails = clientDetails; } public String getFirstRepaymentDay() { return firstRepaymentDay; } public void setFirstRepaymentDay(String firstRepaymentDay) { this.firstRepaymentDay = firstRepaymentDay; } public void setLoanAmountRange(AmountRange amountRange) { this.amountRange = amountRange; } public void setMaxInterestRate(Double maxInterestRate) { this.maxInterestRate = maxInterestRate; } public void setMinInterestRate(Double minInterestRate) { this.minInterestRate = minInterestRate; } public void setInstallmentRange(InstallmentRange installmentRange) { this.installmentRange = installmentRange; } public String getMinInterestRate() { return getDoubleStringForMoney(getMinInterestRateValue()); } public Double getMinInterestRateValue() { return minInterestRate; } public String getMaxInterestRate() { return getDoubleStringForMoney(getMaxInterestRateValue()); } public Double getMaxInterestRateValue() { return maxInterestRate; } public String getMinLoanAmount() { return getDoubleStringForMoney(getMinLoanAmountValue()); } public Double getMinLoanAmountValue() { if (this.amountRange != null) { return amountRange.getMinLoanAmount(); } return Double.valueOf("0"); } public String getMaxLoanAmount() { return getDoubleStringForMoney(getMaxLoanAmountValue()); } public Double getMaxLoanAmountValue() { if (this.amountRange != null) { return amountRange.getMaxLoanAmount(); } return Double.valueOf("0"); } public String getMinNoInstallments() { return getMinNoInstallmentsValue().toString(); } public Short getMinNoInstallmentsValue() { if (this.installmentRange != null) { return installmentRange.getMinNoOfInstall(); } return Short.valueOf("0"); } public String getMaxNoInstallments() { return getMaxNoInstallmentsValue().toString(); } public Short getMaxNoInstallmentsValue() { if (this.installmentRange != null) { return installmentRange.getMaxNoOfInstall(); } return Short.valueOf("0"); } public void removeClientDetailsWithNoMatchingClients() { List<LoanAccountDetailsDto> clientDetailsCopy = new ArrayList<LoanAccountDetailsDto>( clientDetails); CollectionUtils.filter(clientDetailsCopy, new RemoveEmptyClientDetailsForUncheckedClients(getClients())); clientDetails = new ArrayList<LoanAccountDetailsDto>(clientDetailsCopy); } public void initializeInstallments(List<RepaymentScheduleInstallment> installments) { this.installments = installments; } public BigDecimal getLoanAmountAsBigDecimal() { return loanAmountValue.getAmount(); } public void resetScheduleViewDate() { setScheduleViewDate(new SimpleDateFormat("dd/MM/yyyy", Locale.US).format(new DateTimeService().getCurrentJavaSqlDate())); } public List<FeeDto> getApplicableFees() { List<FeeDto> applicableFees = new ArrayList<FeeDto>(); addDefaultFees(applicableFees); addAdditionalFees(applicableFees); return applicableFees; } private void addAdditionalFees(List<FeeDto> applicableFees) { if (isNotEmpty(additionalFees)) { for (FeeDto additionalFee : additionalFees) { if (additionalFee.isNotEmpty()) applicableFees.add(additionalFee); } } } private void addDefaultFees(List<FeeDto> applicableFees) { if (isNotEmpty(defaultFees)) { for (FeeDto defaultFee : defaultFees) { if (defaultFee.isNotEmpty()) applicableFees.add(defaultFee); } } } private static class RemoveEmptyClientDetailsForUncheckedClients implements Predicate { private final List<String> clients2; RemoveEmptyClientDetailsForUncheckedClients(List<String> clients) { clients2 = clients; } @Override public boolean evaluate(Object object) { LoanAccountDetailsDto loanDetail = ((LoanAccountDetailsDto) object); return !(!clients2.contains(loanDetail.getClientId()) && (loanDetail.isEmpty())); } } public void clearDetailsForLoan() { // clear cached additional fees (MIFOS-2547) this.additionalFees = new ArrayList<FeeDto>(); this.externalId = null; this.businessActivityId = null; this.collateralTypeId = null; this.questionGroups = null; this.scheduleViewDate = null; } @Override public void setQuestionGroups(List<QuestionGroupDetail> questionGroups) { this.questionGroups = questionGroups; } @Override public List<QuestionGroupDetail> getQuestionGroups() { return questionGroups; } public List<RepaymentScheduleInstallment> getInstallments() { return installments; } private boolean isRedoOperation() { return PERSPECTIVE_VALUE_REDO_LOAN.equals(this.perspective) && CollectionUtils.isNotEmpty(paymentDataBeans); } public boolean isVariableInstallmentsAllowed() { return variableInstallmentsAllowed; } public void setVariableInstallmentsAllowed(boolean variableInstallmentsAllowed) { this.variableInstallmentsAllowed = variableInstallmentsAllowed; } public void setMinimumGapInDays(Integer minimumGapInDays) { this.minimumGapInDays = minimumGapInDays; } public Integer getMinimumGapInDays() { return minimumGapInDays; } public Integer getMaximumGapInDays() { return maximumGapInDays; } public void setMaximumGapInDays(Integer maximumGapInDays) { this.maximumGapInDays = maximumGapInDays; } public Money getMinInstallmentAmount() { return minInstallmentAmount; } public void setMinInstallmentAmount(Money minInstallmentAmount) { this.minInstallmentAmount = minInstallmentAmount; } @Override public CashFlowForm getCashFlowForm() { return cashFlowForm; } @Override public void setCashFlowForm(CashFlowForm cashFlowForm) { this.cashFlowForm = cashFlowForm; } public Money getLoanAmountValue() { return loanAmountValue; } }