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.leavepayout.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.leavepayout.LeavePayout; 027 import org.kuali.hr.lm.employeeoverride.EmployeeOverride; 028 import org.kuali.hr.time.principal.PrincipalHRAttributes; 029 import org.kuali.hr.time.service.base.TkServiceLocator; 030 import org.kuali.hr.time.util.TKUtils; 031 import org.kuali.hr.time.util.TkConstants; 032 import org.kuali.rice.krad.util.GlobalVariables; 033 import org.kuali.rice.krad.util.ObjectUtils; 034 035 public class LeavePayoutValidationUtils { 036 037 public static boolean validatePayout(LeavePayout leavePayout) { 038 boolean isValid = true; 039 String principalId = leavePayout.getPrincipalId(); 040 Date effectiveDate = leavePayout.getEffectiveDate(); 041 String fromAccrualCategory = leavePayout.getFromAccrualCategory(); 042 String payoutEarnCode = leavePayout.getEarnCode(); 043 AccrualCategory fromCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate); 044 AccrualCategory toCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(payoutEarnCode, effectiveDate); 045 PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate); 046 047 if(ObjectUtils.isNotNull(pha)) { 048 if(ObjectUtils.isNotNull(pha.getLeavePlan())) { 049 AccrualCategoryRule acr = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat, effectiveDate, pha.getServiceDate()); 050 if(ObjectUtils.isNotNull(acr)) { 051 if(ObjectUtils.isNotNull(acr.getMaxBalFlag()) 052 && StringUtils.isNotBlank(acr.getMaxBalFlag()) 053 && StringUtils.isNotEmpty(acr.getMaxBalFlag()) 054 && StringUtils.equals(acr.getMaxBalFlag(), "Y")) { 055 if(ObjectUtils.isNotNull(acr.getMaxPayoutEarnCode()) || StringUtils.equals(LMConstants.ACTION_AT_MAX_BAL.LOSE, acr.getActionAtMaxBalance())) { 056 /* isValid &= validatePrincipal(pha,principalId); 057 isValid &= validateEffectiveDate(effectiveDate); 058 isValid &= validateAgainstLeavePlan(pha,fromCat,toCat,effectiveDate); 059 isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr); 060 isValid &= validateTransferToAccrualCategory(toCat,principalId,effectiveDate,acr); 061 */ 062 isValid &= validatePayoutAmount(leavePayout.getPayoutAmount(),fromCat,toCat, principalId, effectiveDate, acr); 063 } 064 else { 065 //should never be the case if accrual category rules are validated correctly. 066 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", 067 "leavePayout.fromAccrualCategory.rules.payoutToEarnCode", 068 fromAccrualCategory); 069 isValid &= false; 070 } 071 } 072 else { 073 //max bal flag null, blank, empty, or "N" 074 GlobalVariables.getMessageMap().putError("document.newMaintinableObject.fromAccrualCategory", 075 "leavePayout.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory); 076 isValid &= false; 077 } 078 } 079 else { 080 //department admins must validate amount to transfer does not exceed current balance. 081 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", 082 "leavePayout.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory()); 083 isValid &= false; 084 } 085 } 086 else { 087 //if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited. 088 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","leavePayout.principal.noLeavePlan"); 089 isValid &=false; 090 } 091 } 092 else { 093 //if the principal has no principal hr attributes, they're not a principal. 094 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","leavePayout.principal.noAttributes"); 095 isValid &= false; 096 } 097 /* }*/ 098 return isValid; 099 100 } 101 102 private static boolean validatePayoutAmount(BigDecimal payoutAmount, 103 AccrualCategory fromCat, AccrualCategory toCat, String principalId, 104 Date effectiveDate, AccrualCategoryRule accrualRule) { 105 106 BigDecimal balance = TkServiceLocator.getAccrualCategoryService().getAccruedBalanceForPrincipal(principalId, fromCat, effectiveDate); 107 //transfer amount must be less than the max transfer amount defined in the accrual category rule. 108 //it cannot be negative. 109 boolean isValid = true; 110 111 BigDecimal maxPayoutAmount = null; 112 BigDecimal adjustedMaxPayoutAmount = null; 113 if(ObjectUtils.isNotNull(accrualRule.getMaxPayoutAmount())) { 114 maxPayoutAmount = new BigDecimal(accrualRule.getMaxPayoutAmount()); 115 BigDecimal fullTimeEngagement = TkServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate); 116 adjustedMaxPayoutAmount = maxPayoutAmount.multiply(fullTimeEngagement); 117 } 118 119 //use override if one exists. 120 EmployeeOverride maxPayoutAmountOverride = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, fromCat.getLeavePlan(), fromCat.getAccrualCategory(), "MPA", effectiveDate); 121 if(ObjectUtils.isNotNull(maxPayoutAmountOverride)) 122 adjustedMaxPayoutAmount = new BigDecimal(maxPayoutAmountOverride.getOverrideValue()); 123 124 125 if(ObjectUtils.isNotNull(adjustedMaxPayoutAmount)) { 126 if(payoutAmount.compareTo(adjustedMaxPayoutAmount) > 0) { 127 isValid &= false; 128 String fromUnitOfTime = TkConstants.UNIT_OF_TIME.get(fromCat.getUnitOfTime()); 129 GlobalVariables.getMessageMap().putError("leavePayout.payoutAmount","leavePayout.payoutAmount.maxPayoutAmount",adjustedMaxPayoutAmount.toString(),fromUnitOfTime); 130 } 131 } 132 // check for a positive amount. 133 if(payoutAmount.compareTo(BigDecimal.ZERO) < 0 ) { 134 isValid &= false; 135 GlobalVariables.getMessageMap().putError("leavePayout.payoutAmount","leavePayout.payoutAmount.negative"); 136 } 137 138 if(balance.subtract(payoutAmount).compareTo(BigDecimal.ZERO) < 0 ) { 139 if(StringUtils.equals(fromCat.getEarnCodeObj().getAllowNegativeAccrualBalance(),"Y")) 140 isValid &= true; 141 else { 142 isValid &= false; 143 GlobalVariables.getMessageMap().putError("leavePayout.payoutAmount", "maxBalance.amount.exceedsBalance"); 144 } 145 } 146 return isValid; 147 } 148 149 private boolean validateMaxBalance() { 150 //This validation could assert that the payout amount, together with forfeiture 151 //brings the balance for the given accrual category back to, or under, the balance limit 152 //without exceeding the total accrued balance. 153 return true; 154 } 155 156 private boolean validateMaxCarryOver() { 157 //This validation could assert that the payout amount, together with forfeiture 158 //brings the balance for the given accrual category back to, or under, the max carry over limit 159 //without exceeding the total accrued balance. 160 return true; 161 } 162 163 }