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