View Javadoc

1   /**
2    * Copyright 2004-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.hr.lm.balancetransfer.validation;
17  
18  import java.math.BigDecimal;
19  import java.sql.Date;
20  import org.apache.commons.lang.StringUtils;
21  import org.kuali.hr.lm.LMConstants;
22  import org.kuali.hr.lm.accrual.AccrualCategory;
23  import org.kuali.hr.lm.accrual.AccrualCategoryRule;
24  import org.kuali.hr.lm.balancetransfer.BalanceTransfer;
25  import org.kuali.hr.lm.employeeoverride.EmployeeOverride;
26  import org.kuali.hr.lm.timeoff.SystemScheduledTimeOff;
27  import org.kuali.hr.time.principal.PrincipalHRAttributes;
28  import org.kuali.hr.time.service.base.TkServiceLocator;
29  import org.kuali.hr.time.util.TkConstants;
30  import org.kuali.rice.krad.util.GlobalVariables;
31  import org.kuali.rice.krad.util.ObjectUtils;
32  
33  public class BalanceTransferValidationUtils {
34  
35  	public static boolean validateTransfer(BalanceTransfer balanceTransfer) {
36  		boolean isValid = true;
37  		if(StringUtils.isNotEmpty(balanceTransfer.getSstoId())) {
38  			return isValid && validateSstoTranser(balanceTransfer) ;
39  		}
40  		String principalId = balanceTransfer.getPrincipalId();
41  		Date effectiveDate = balanceTransfer.getEffectiveDate();
42  		String fromAccrualCategory = balanceTransfer.getFromAccrualCategory();
43  		String toAccrualCategory = balanceTransfer.getToAccrualCategory();
44  		AccrualCategory fromCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate);
45  		AccrualCategory toCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(toAccrualCategory, effectiveDate);
46  		PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate);
47  		
48  		if(ObjectUtils.isNotNull(pha)) {
49  			if(ObjectUtils.isNotNull(pha.getLeavePlan())) {
50  				AccrualCategoryRule acr = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat,
51  						effectiveDate, pha.getServiceDate());
52  				if(ObjectUtils.isNotNull(acr)) {
53  					if(ObjectUtils.isNotNull(acr.getMaxBalFlag())
54  							&& StringUtils.isNotBlank(acr.getMaxBalFlag())
55  							&& StringUtils.isNotEmpty(acr.getMaxBalFlag())
56  							&& StringUtils.equals(acr.getMaxBalFlag(), "Y")) {
57  						if(ObjectUtils.isNotNull(acr.getMaxBalanceTransferToAccrualCategory()) || StringUtils.equals(LMConstants.ACTION_AT_MAX_BAL.LOSE, acr.getActionAtMaxBalance())) {
58  /*							isValid &= validatePrincipal(pha,principalId);
59  							isValid &= validateEffectiveDate(effectiveDate);
60  							isValid &= validateAgainstLeavePlan(pha,fromCat,toCat,effectiveDate);
61  							isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr);
62  							isValid &= validateTransferToAccrualCategory(toCat,principalId,effectiveDate,acr);*/
63  							isValid &= validateMaxCarryOver(balanceTransfer.getAmountTransferred(),toCat,principalId,effectiveDate,acr, pha);
64  							isValid &= validateTransferAmount(balanceTransfer.getTransferAmount(),fromCat,toCat, principalId, effectiveDate, acr);
65  							isValid &= validateForfeitedAmount(balanceTransfer.getForfeitedAmount());
66  						}
67  						else {
68  							//should never be the case if accrual category rules are validated correctly.
69  							GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
70  									"balanceTransfer.fromAccrualCategory.rules.transferToAccrualCategory",
71  									fromAccrualCategory);
72  							isValid &= false;
73  						}
74  					}
75  					else {
76  						//max bal flag null, blank, empty, or "N"
77  						GlobalVariables.getMessageMap().putError("document.newMaintinableObject.fromAccrualCategory",
78  								"balanceTransfer.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory);
79  						isValid &= false;
80  					}
81  				}
82  				else {
83  					//department admins must validate amount to transfer does not exceed current balance.
84  					GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
85  							"balanceTransfer.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory());
86  					isValid &= false;
87  				}
88  			}
89  			else {
90  				//if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited.
91  				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noLeavePlan");
92  				isValid &=false;
93  			}
94  		}
95  		else  {
96  			//if the principal has no principal hr attributes, they're not a principal.
97  			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noAttributes");
98  			isValid &= false;
99  		}
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 }