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