001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.module.endow.document.validation.impl;
017    
018    import java.math.BigDecimal;
019    import java.sql.Date;
020    
021    import org.apache.log4j.Logger;
022    import org.kuali.kfs.module.endow.EndowKeyConstants;
023    import org.kuali.kfs.module.endow.EndowPropertyConstants;
024    import org.kuali.kfs.module.endow.businessobject.PooledFundValue;
025    import org.kuali.kfs.module.endow.document.service.PooledFundValueService;
026    import org.kuali.kfs.module.endow.util.ValidateLastDayOfMonth;
027    import org.kuali.kfs.sys.context.SpringContext;
028    import org.kuali.rice.kns.document.MaintenanceDocument;
029    import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
030    import org.kuali.rice.kns.util.GlobalVariables;
031    import org.kuali.rice.kns.util.MessageMap;
032    import org.kuali.rice.kns.util.ObjectUtils;
033    
034    public class PooledFundValueRule extends MaintenanceDocumentRuleBase {
035    
036        protected static Logger LOG = org.apache.log4j.Logger.getLogger(SecurityRule.class);
037        private PooledFundValue newPooledFundValue;
038    
039        /**
040         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
041         */
042        @Override
043        protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
044    
045            boolean isValid = true;
046            isValid &= super.processCustomRouteDocumentBusinessRules(document);
047            MessageMap errorMap = GlobalVariables.getMessageMap();
048            isValid &= errorMap.hasNoErrors();
049    
050            if (isValid) {
051                PooledFundValue newPooledFundValue = (PooledFundValue) document.getNewMaintainableObject().getBusinessObject();
052                isValid &= checkCustomRequiredFields(newPooledFundValue);
053            }
054    
055            return isValid;
056        }
057    
058        protected boolean checkCustomRequiredFields(PooledFundValue newPooledFundValue) {
059            boolean isValid = true;
060    
061            Date valuationDate = newPooledFundValue.getValuationDate();
062            String pooledSecurityID = newPooledFundValue.getPooledSecurityID();
063            BigDecimal unitValue = newPooledFundValue.getUnitValue();
064    
065            isValid &= isValuationDateLastDayOfMonth(valuationDate);
066            isValid &= isValuationDateTheLatest(pooledSecurityID, valuationDate);
067            isValid &= isUnitValuePositive(unitValue);
068            BigDecimal zero = new BigDecimal(0);
069            BigDecimal incomeDistributionPerUnit = newPooledFundValue.getIncomeDistributionPerUnit();
070            Date distributeIncomeOnDate = newPooledFundValue.getDistributeIncomeOnDate();
071            if (ObjectUtils.isNotNull(incomeDistributionPerUnit) && (incomeDistributionPerUnit.compareTo(zero) == 1)) {
072                isValid &= isIncomeDistributionPerUnitNotNegative(incomeDistributionPerUnit);
073                isValid &= isDateRequiredField(distributeIncomeOnDate, EndowPropertyConstants.DISTRIBUTE_INCOME_ON_DATE, EndowKeyConstants.PooledFundValueConstants.ERROR_DISTRIBUTE_INCOME_ON_DATE_IS_REQUIRED_FIELD);
074            }
075    
076            BigDecimal longTermGainLossDistributionPerUnit = newPooledFundValue.getLongTermGainLossDistributionPerUnit();
077            Date distributeLongTermGainLossOnDate = newPooledFundValue.getDistributeLongTermGainLossOnDate();
078            if (ObjectUtils.isNotNull(longTermGainLossDistributionPerUnit) && (longTermGainLossDistributionPerUnit.compareTo(zero) == 1)) {
079                isValid &= isDateRequiredField(distributeLongTermGainLossOnDate, EndowPropertyConstants.DISTRIBUTE_LONG_TERM_GAIN_LOSS_ON_DATE, EndowKeyConstants.PooledFundValueConstants.ERROR_DISTRIBUTE_LONG_TERM_GAIN_LOSS_ON_DATE_IS_REQUIRED_FIELD);
080            }
081    
082            BigDecimal shortTermGainLossDistributionPerUnit = newPooledFundValue.getShortTermGainLossDistributionPerUnit();
083            Date distributeShortTermGainLossOnDate = newPooledFundValue.getDistributeShortTermGainLossOnDate();
084            if (ObjectUtils.isNotNull(shortTermGainLossDistributionPerUnit) && (shortTermGainLossDistributionPerUnit.compareTo(zero) == 1)) {
085                isValid &= isDateRequiredField(distributeShortTermGainLossOnDate, EndowPropertyConstants.DISTRIBUTE_SHORT_TERM_GAIN_LOSS_ON_DATE, EndowKeyConstants.PooledFundValueConstants.ERROR_DISTRIBUTE_SHORT_TERM_GAIN_LOSS_ON_DATE_IS_REQUIRED_FIELD);
086            }
087    
088    
089            return isValid;
090        }
091    
092        /**
093         * 
094         * 
095         */
096        protected boolean isDateRequiredField(Date theDate, String errorField, String errorKey) {
097            boolean isRequiredField = true;
098            if (ObjectUtils.isNull(theDate)) {
099                putFieldError(errorField, errorKey);
100                isRequiredField = false;
101            }
102            return isRequiredField;
103        }
104    
105        /**
106         * Checks if the value of the valuation date is the last day of the month. If yes, return true; otherwise, return false.
107         * 
108         * @param valuationDate
109         * @return true if valuationDate is the last day of the month, false otherwise
110         */
111        protected boolean isValuationDateLastDayOfMonth(Date valuationDate) {
112            boolean isLastDay = true;
113            if (!ValidateLastDayOfMonth.validateLastDayOfMonth(valuationDate)) {
114                putFieldError(EndowPropertyConstants.VALUATION_DATE, EndowKeyConstants.PooledFundValueConstants.ERROR_VALUATION_DATE_IS_NOT_THE_END_OF_MONTH);
115                isLastDay = false;
116            }
117            return isLastDay;
118        }
119    
120        /**
121         * The rule is "A new record cannot have a VAL_DT that is earlier than the record with the most recent VAL_DT".
122         * 
123         * @param pooledSecurityID
124         * @param theValuationDate
125         * @return true if valuationDate is the latest one for the specified pooledSecurityID, false otherwise.
126         */
127        protected boolean isValuationDateTheLatest(String pooledSecurityID, Date theValuationDate) {
128            PooledFundValueService pooledFundValueService = SpringContext.getBean(PooledFundValueService.class);
129            boolean isLatest = pooledFundValueService.isValuationDateTheLatest(pooledSecurityID, theValuationDate);
130            if (!isLatest) {
131                putFieldError(EndowPropertyConstants.VALUATION_DATE, EndowKeyConstants.PooledFundValueConstants.ERROR_VALUATION_DATE_IS_NOT_LATEST_ONE);
132            }
133            return isLatest;
134        }
135    
136        /**
137         * The rule is unitValue can only be positive because unitValue is a required field.
138         * 
139         * @param unitValue
140         * @return true if unitValue is a positive value, false otherwise
141         */
142        protected boolean isUnitValuePositive(BigDecimal unitValue) {
143            boolean isPositive = true;
144            if (unitValue.compareTo(new BigDecimal(0)) != 1) {
145                putFieldError(EndowPropertyConstants.SECURITY_UNIT_VALUE, EndowKeyConstants.PooledFundValueConstants.ERROR_UNIT_VALUE_IS_NOT_POSITIVE);
146                isPositive = false;
147            }
148            return isPositive;
149        }
150    
151        /**
152         * The rule is incomeDistributionPerUnit can't be less than zero. Either zero or positive value is an accepted/valid input
153         * because incomeDistributionPerUnit is not a required field.
154         * 
155         * @param incomeDistributionPerUnit
156         * @return true if incomeDistributionPerUnit is zero or bigger than zero, false otherwise
157         */
158        protected boolean isIncomeDistributionPerUnitNotNegative(BigDecimal incomeDistributionPerUnit) {
159            boolean isNotNegative = true;
160            if ((incomeDistributionPerUnit.compareTo(new BigDecimal(0)) == 1) || (incomeDistributionPerUnit.compareTo(new BigDecimal(0)) == 0)) {
161                return isNotNegative;
162            }
163            else {
164                putFieldError(EndowPropertyConstants.INCOME_DISTRIBUTION_PER_UNIT, EndowKeyConstants.PooledFundValueConstants.ERROR_INCOME_DISTRIBUTION_PER_UNIT_IS_NOT_POSITIVE);
165                return false;
166            }
167        }
168    
169    }