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.Calendar; 021 import java.util.List; 022 023 import org.apache.commons.lang.StringUtils; 024 import org.apache.commons.lang.time.DateUtils; 025 import org.kuali.hr.lm.accrual.AccrualCategory; 026 import org.kuali.hr.lm.accrual.AccrualCategoryRule; 027 import org.kuali.hr.lm.balancetransfer.BalanceTransfer; 028 import org.kuali.hr.lm.employeeoverride.EmployeeOverride; 029 import org.kuali.hr.time.principal.PrincipalHRAttributes; 030 import org.kuali.hr.time.service.base.TkServiceLocator; 031 import org.kuali.hr.time.util.TKContext; 032 import org.kuali.hr.time.util.TKUtils; 033 import org.kuali.hr.time.util.TkConstants; 034 import org.kuali.rice.kns.document.MaintenanceDocument; 035 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; 036 import org.kuali.rice.krad.bo.PersistableBusinessObject; 037 import org.kuali.rice.krad.util.GlobalVariables; 038 import org.kuali.rice.krad.util.ObjectUtils; 039 040 public class BalanceTransferValidation extends MaintenanceDocumentRuleBase { 041 042 //the "to" and "from" accrual categories should be in the supplied principal's leave plan as of the effective date. 043 private boolean validateLeavePlan(PrincipalHRAttributes pha, 044 AccrualCategory fromAccrualCategory, AccrualCategory toAccrualCategory, Date effectiveDate) { 045 boolean isValid = true; 046 047 List<AccrualCategory> accrualCategories = TkServiceLocator.getAccrualCategoryService().getActiveAccrualCategoriesForLeavePlan(pha.getLeavePlan(), effectiveDate); 048 if(accrualCategories.size() > 0) { 049 boolean isFromInLeavePlan = false; 050 boolean isToInLeavePlan = false; 051 for(AccrualCategory activeAccrualCategory : accrualCategories) { 052 if(StringUtils.equals(activeAccrualCategory.getLmAccrualCategoryId(),fromAccrualCategory.getLmAccrualCategoryId())) { 053 isFromInLeavePlan = true; 054 } 055 if(StringUtils.equals(activeAccrualCategory.getLmAccrualCategoryId(), toAccrualCategory.getLmAccrualCategoryId())) { 056 isToInLeavePlan = true; 057 } 058 } 059 if(!isFromInLeavePlan) { 060 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.accrualCategory.notInLeavePlan", fromAccrualCategory.getAccrualCategory()); 061 isValid &= false; 062 } 063 if(!isToInLeavePlan) { 064 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.toAccrualCategory", "balanceTransfer.accrualCategory.notInLeavePlan", toAccrualCategory.getAccrualCategory()); 065 isValid &= false; 066 } 067 } 068 else { 069 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "balanceTransfer.principal.noACinLeavePlan"); 070 isValid &=false; 071 } 072 return isValid; 073 } 074 075 //See isTransferAmountUnderMaxLimit for futher validation 076 private boolean validateTransferAmount(BigDecimal transferAmount, 077 AccrualCategory debitedAccrualCategory, 078 AccrualCategory creditedAccrualCategory, String principalId, Date effectiveDate) { 079 080 if(transferAmount.compareTo(BigDecimal.ZERO) < 0 ) { 081 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.transferAmount", "balanceTransfer.amount.negative"); 082 return false; 083 } 084 085 return true; 086 } 087 088 //Effective date not more than one year in advance 089 private boolean validateEffectiveDate(Date date) { 090 if(DateUtils.addYears(TKUtils.getCurrentDate(), 1).compareTo(date) > 0) 091 return true; 092 else 093 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.effectiveDate", "balanceTransfer.effectiveDate.error"); 094 return false; 095 } 096 097 private boolean validateTransferFromAccrualCategory(AccrualCategory accrualCategory, String principalId, 098 Date effectiveDate, AccrualCategoryRule acr) { 099 //accrualCategory has rules 100 PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, effectiveDate); 101 102 return true; 103 } 104 105 //Transfer to accrual category should match the value defined in the accrual category rule 106 private boolean validateTransferToAccrualCategory(AccrualCategory accrualCategory, String principalId, Date effectiveDate, AccrualCategoryRule acr) { 107 AccrualCategory maxBalTranToAccCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(acr.getMaxBalanceTransferToAccrualCategory(),effectiveDate); 108 if(!StringUtils.equals(maxBalTranToAccCat.getLmAccrualCategoryId(),accrualCategory.getLmAccrualCategoryId())) { 109 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.toAccrualCategory", "balanceTransfer.toAccrualCategory.noMatch",accrualCategory.getAccrualCategory()); 110 return false; 111 } 112 return true; 113 } 114 115 //no validation 116 private boolean validatePrincipal(PrincipalHRAttributes pha, String principalId) { 117 return true; 118 } 119 120 //transfer amount must be under max limit when submitted via max balance triggered action or by a work area approver. 121 private boolean isTransferAmountUnderMaxLimit(String principalId, Date effectiveDate, String accrualCategory, 122 BigDecimal transferAmount, AccrualCategoryRule accrualRule, String leavePlan) { 123 124 if(ObjectUtils.isNotNull(accrualRule)) { 125 126 BigDecimal maxTransferAmount = null; 127 if(ObjectUtils.isNotNull(accrualRule.getMaxTransferAmount())) { 128 maxTransferAmount = new BigDecimal(accrualRule.getMaxTransferAmount()); 129 } 130 if(ObjectUtils.isNotNull(maxTransferAmount)) { 131 EmployeeOverride eo = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, leavePlan, accrualCategory, TkConstants.EMPLOYEE_OVERRIDE_TYPE.get("MTA"), effectiveDate); 132 if(ObjectUtils.isNotNull(eo)) 133 maxTransferAmount = new BigDecimal(eo.getOverrideValue()); 134 else { 135 BigDecimal fteSum = TkServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate); 136 maxTransferAmount = maxTransferAmount.multiply(fteSum); 137 } 138 if(transferAmount.compareTo(maxTransferAmount) > 0) { 139 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.transferAmount","balanceTransfer.exceeds.transferLimit"); 140 return false; 141 } 142 } 143 } 144 return true; 145 } 146 147 @Override 148 public boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) { 149 boolean isValid = super.processCustomRouteDocumentBusinessRules(document); 150 LOG.debug("entering custom validation for Balance Transfer"); 151 152 PersistableBusinessObject pbo = (PersistableBusinessObject) this.getNewBo(); 153 154 if(pbo instanceof BalanceTransfer) { 155 156 BalanceTransfer balanceTransfer = (BalanceTransfer) pbo; 157 158 // if this balance transfer is on a system scheduled time off, then don't do further validation 159 if(StringUtils.isNotEmpty(balanceTransfer.getSstoId())) { 160 isValid &= BalanceTransferValidationUtils.validateSstoTranser(balanceTransfer); 161 return isValid; 162 } 163 if(isValid) { 164 165 /** 166 * Validation is basically governed by accrual category rules. Get accrual category 167 * rules for both the "To" and "From" accrual categories, pass to validators along with the 168 * values needing to be validated. 169 * 170 * Balance transfers initiated from the leave calendar display should already have all values 171 * populated, thus validated, including the accrual category rule for the "From" accrual category. 172 * 173 * Balance transfers initiated via the Maintenance tab will have no values populated. 174 */ 175 String principalId = balanceTransfer.getPrincipalId(); 176 Date effectiveDate = balanceTransfer.getEffectiveDate(); 177 String fromAccrualCategory = balanceTransfer.getFromAccrualCategory(); 178 String toAccrualCategory = balanceTransfer.getToAccrualCategory(); 179 AccrualCategory fromCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate); 180 AccrualCategory toCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(toAccrualCategory, effectiveDate); 181 PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate); 182 183 boolean isDeptAdmin = TKContext.getUser().isDepartmentAdmin(); 184 boolean isSysAdmin = TKContext.getUser().isSystemAdmin(); 185 if(isDeptAdmin || isSysAdmin) { 186 isValid &= validateTransferAmount(balanceTransfer.getTransferAmount(),fromCat,toCat, principalId, effectiveDate); 187 } 188 else { 189 if(ObjectUtils.isNotNull(pha)) { 190 if(ObjectUtils.isNotNull(pha.getLeavePlan())) { 191 AccrualCategoryRule acr = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat, 192 effectiveDate, pha.getServiceDate()); 193 if(ObjectUtils.isNotNull(acr)) { 194 if(StringUtils.isNotBlank(acr.getMaxBalFlag()) 195 && StringUtils.equals(acr.getMaxBalFlag(), "Y")) { 196 if(ObjectUtils.isNotNull(toCat)) { 197 198 isValid &= validatePrincipal(pha,principalId); 199 isValid &= validateEffectiveDate(effectiveDate); 200 isValid &= validateLeavePlan(pha,fromCat,toCat,effectiveDate); 201 isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr); 202 isValid &= validateTransferToAccrualCategory(toCat,principalId,effectiveDate,acr); 203 isValid &= validateTransferAmount(balanceTransfer.getTransferAmount(),fromCat,toCat, null, null); 204 isValid &= isTransferAmountUnderMaxLimit(principalId,effectiveDate,fromAccrualCategory,balanceTransfer.getTransferAmount(),acr,pha.getLeavePlan()); 205 } 206 else { 207 //should never be the case if accrual category rules are validated correctly. 208 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", 209 "balanceTransfer.fromAccrualCategory.rules.transferToAccrualCategory", 210 fromAccrualCategory); 211 isValid &= false; 212 } 213 } 214 else { 215 //max bal flag null, blank, empty, or "N" 216 GlobalVariables.getMessageMap().putError("document.newMaintinableObject.fromAccrualCategory", 217 "balanceTransfer.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory); 218 isValid &= false; 219 } 220 } 221 else { 222 //department admins must validate amount to transfer does not exceed current balance. 223 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", 224 "balanceTransfer.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory()); 225 isValid &= false; 226 } 227 } 228 else { 229 //if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited. 230 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noLeavePlan"); 231 isValid &=false; 232 } 233 } 234 else { 235 //if the principal has no principal hr attributes, they're not a principal. 236 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noAttributes"); 237 isValid &= false; 238 } 239 } 240 } 241 } 242 return isValid; 243 } 244 245 @Override 246 protected boolean processCustomApproveDocumentBusinessRules( 247 MaintenanceDocument document) { 248 /* System.out.println("");*/ 249 return super.processCustomApproveDocumentBusinessRules(document); 250 } 251 252 }