001    /**
002     * Copyright 2004-2013 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.hr.lm.balancetransfer.validation;
017    
018    import java.math.BigDecimal;
019    import java.sql.Date;
020    import java.util.List;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.kuali.hr.lm.LMConstants;
024    import org.kuali.hr.lm.accrual.AccrualCategory;
025    import org.kuali.hr.lm.accrual.AccrualCategoryRule;
026    import org.kuali.hr.lm.balancetransfer.BalanceTransfer;
027    import org.kuali.hr.lm.employeeoverride.EmployeeOverride;
028    import org.kuali.hr.lm.timeoff.SystemScheduledTimeOff;
029    import org.kuali.hr.time.principal.PrincipalHRAttributes;
030    import org.kuali.hr.time.service.base.TkServiceLocator;
031    import org.kuali.hr.time.util.TKUtils;
032    import org.kuali.hr.time.util.TkConstants;
033    import org.kuali.rice.krad.util.GlobalVariables;
034    import org.kuali.rice.krad.util.ObjectUtils;
035    
036    public class BalanceTransferValidationUtils {
037    
038            public static boolean validateTransfer(BalanceTransfer balanceTransfer) {
039                    boolean isValid = true;
040                    if(StringUtils.isNotEmpty(balanceTransfer.getSstoId())) {
041                            return isValid && validateSstoTranser(balanceTransfer) ;
042                    }
043                    String principalId = balanceTransfer.getPrincipalId();
044                    Date effectiveDate = balanceTransfer.getEffectiveDate();
045                    String fromAccrualCategory = balanceTransfer.getFromAccrualCategory();
046                    String toAccrualCategory = balanceTransfer.getToAccrualCategory();
047                    AccrualCategory fromCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate);
048                    AccrualCategory toCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(toAccrualCategory, effectiveDate);
049                    PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate);
050                    
051                    if(ObjectUtils.isNotNull(pha)) {
052                            if(ObjectUtils.isNotNull(pha.getLeavePlan())) {
053                                    AccrualCategoryRule acr = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat,
054                                                    effectiveDate, pha.getServiceDate());
055                                    if(ObjectUtils.isNotNull(acr)) {
056                                            if(ObjectUtils.isNotNull(acr.getMaxBalFlag())
057                                                            && StringUtils.isNotBlank(acr.getMaxBalFlag())
058                                                            && StringUtils.isNotEmpty(acr.getMaxBalFlag())
059                                                            && StringUtils.equals(acr.getMaxBalFlag(), "Y")) {
060                                                    if(ObjectUtils.isNotNull(acr.getMaxBalanceTransferToAccrualCategory()) || StringUtils.equals(LMConstants.ACTION_AT_MAX_BAL.LOSE, acr.getActionAtMaxBalance())) {
061    /*                                                      isValid &= validatePrincipal(pha,principalId);
062                                                            isValid &= validateEffectiveDate(effectiveDate);
063                                                            isValid &= validateAgainstLeavePlan(pha,fromCat,toCat,effectiveDate);
064                                                            isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr);
065                                                            isValid &= validateTransferToAccrualCategory(toCat,principalId,effectiveDate,acr);*/
066                                                            isValid &= validateMaxCarryOver(balanceTransfer.getAmountTransferred(),toCat,principalId,effectiveDate,acr, pha);
067                                                            isValid &= validateTransferAmount(balanceTransfer.getTransferAmount(),fromCat,toCat, principalId, effectiveDate, acr);
068                                                    }
069                                                    else {
070                                                            //should never be the case if accrual category rules are validated correctly.
071                                                            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
072                                                                            "balanceTransfer.fromAccrualCategory.rules.transferToAccrualCategory",
073                                                                            fromAccrualCategory);
074                                                            isValid &= false;
075                                                    }
076                                            }
077                                            else {
078                                                    //max bal flag null, blank, empty, or "N"
079                                                    GlobalVariables.getMessageMap().putError("document.newMaintinableObject.fromAccrualCategory",
080                                                                    "balanceTransfer.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory);
081                                                    isValid &= false;
082                                            }
083                                    }
084                                    else {
085                                            //department admins must validate amount to transfer does not exceed current balance.
086                                            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
087                                                            "balanceTransfer.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory());
088                                            isValid &= false;
089                                    }
090                            }
091                            else {
092                                    //if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited.
093                                    GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noLeavePlan");
094                                    isValid &=false;
095                            }
096                    }
097                    else  {
098                            //if the principal has no principal hr attributes, they're not a principal.
099                            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noAttributes");
100                            isValid &= false;
101                    }
102    /*              }*/
103                    return isValid;
104    
105            }
106    
107            private static boolean validateMaxCarryOver(BigDecimal amountTransferred,
108                            AccrualCategory toCat, String principalId, Date effectiveDate,
109                            AccrualCategoryRule acr, PrincipalHRAttributes pha) {
110    /*              List<AccrualCategoryRule> rules = toCat.getAccrualCategoryRules();
111                    Date serviceDate = pha.getServiceDate();
112                    Interval interval = new Interval(serviceDate.getTime(), effectiveDate.getTime());
113                    for(AccrualCategoryRule rule : rules) {
114                            String unitOfTime = rule.getServiceUnitOfTime();
115                            if(StringUtils.equals(unitOfTime, LMConstants.SERVICE_TIME_MONTHS))
116                    }*/
117                    return true;
118            }
119    
120            private static boolean validateTransferAmount(BigDecimal transferAmount,
121                            AccrualCategory fromCat, AccrualCategory toCat, String principalId,
122                            Date effectiveDate, AccrualCategoryRule accrualRule) {
123    
124                    //transfer amount must be less than the max transfer amount defined in the accrual category rule.
125                    //it cannot be negative.
126                    boolean isValid = true;
127                    BigDecimal maxTransferAmount = null;
128                    BigDecimal adjustedMaxTransferAmount = null;
129                    if(ObjectUtils.isNotNull(accrualRule.getMaxTransferAmount())) {
130                            maxTransferAmount = new BigDecimal(accrualRule.getMaxTransferAmount());
131                            BigDecimal fullTimeEngagement = TkServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate);
132                            adjustedMaxTransferAmount = maxTransferAmount.multiply(fullTimeEngagement);
133                    }
134                    
135                    //use override if one exists.
136                    List<EmployeeOverride> overrides = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverrides(principalId, effectiveDate);
137                    for(EmployeeOverride override : overrides) {
138                            if(override.getOverrideType().equals(TkConstants.EMPLOYEE_OVERRIDE_TYPE.get("MTA")))
139                                    adjustedMaxTransferAmount = new BigDecimal(override.getOverrideValue());
140                    }
141                                    
142                    if(ObjectUtils.isNotNull(adjustedMaxTransferAmount)) {
143                            if(transferAmount.compareTo(adjustedMaxTransferAmount) > 0) {
144                                    isValid &= false;
145                                    String fromUnitOfTime = TkConstants.UNIT_OF_TIME.get(fromCat.getUnitOfTime());
146                                    GlobalVariables.getMessageMap().putError("balanceTransfer.transferAmount","balanceTransfer.transferAmount.maxTransferAmount",adjustedMaxTransferAmount.toString(),fromUnitOfTime);
147                            }
148                    }
149                    // check for a positive amount.
150                    if(transferAmount.compareTo(BigDecimal.ZERO) < 0 ) {
151                            isValid &= false;
152                            GlobalVariables.getMessageMap().putError("balanceTransfer.transferAmount","balanceTransfer.transferAmount.negative");
153                    }
154                    return isValid;
155            }
156            
157            public static boolean validateSstoTranser(BalanceTransfer bt) {
158                    // make sure from accrual category is consistent with the ssto's
159                    SystemScheduledTimeOff ssto = TkServiceLocator.getSysSchTimeOffService().getSystemScheduledTimeOff(bt.getSstoId());
160                    if(ssto == null) {
161                            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.sstoDoesNotExis", bt.getSstoId());
162                            return false;
163                    }
164                    if(!ssto.getAccrualCategory().equals(bt.getFromAccrualCategory())) {
165                            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.fromACWrong", bt.getFromAccrualCategory(), ssto.getAccrualCategory());
166                            return false;
167                    }
168                    
169                    if(bt.getFromAccrualCategory().equals(bt.getToAccrualCategory())) {
170                            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.fromAndToACTheSame");
171                            return false;
172                    }
173                    
174                    AccrualCategory fromAC = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(bt.getFromAccrualCategory(), bt.getEffectiveDate());
175                    if(fromAC == null) {
176                            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.acDoesNotExist", bt.getFromAccrualCategory());
177                            return false;
178                    }
179                    AccrualCategory toAC = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(bt.getToAccrualCategory(), bt.getEffectiveDate());
180                    if(toAC == null) {
181                            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.toAccrualCategory", "balanceTransfer.transferSSTO.acDoesNotExist", bt.getToAccrualCategory());
182                            return false;
183                    }
184                    // make sure the leave plan of from/to accrual categories are consistent with the employee's leave plan
185                    PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(bt.getPrincipalId(),bt.getEffectiveDate());
186                    if(StringUtils.isNotEmpty(fromAC.getLeavePlan())){
187                            if(!fromAC.getLeavePlan().equals(pha.getLeavePlan())) {
188                                    GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.wrongACLeavePlan", fromAC.getLeavePlan(), pha.getLeavePlan());
189                                    return false;
190                            }
191                    }
192                    if(StringUtils.isNotEmpty(toAC.getLeavePlan())){
193                            if(!fromAC.getLeavePlan().equals(pha.getLeavePlan())) {
194                                    GlobalVariables.getMessageMap().putError("document.newMaintainableObject.toAccrualCategory", "balanceTransfer.transferSSTO.wrongACLeavePlan", toAC.getLeavePlan(), pha.getLeavePlan());
195                                    return false;
196                            }
197                    }
198                    
199                    return true;
200            }
201            
202    
203    }