View Javadoc
1   /**
2    * Copyright 2004-2015 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.kpme.tklm.leave.transfer.validation;
17  
18  import java.math.BigDecimal;
19  
20  import org.apache.commons.lang.StringUtils;
21  import org.joda.time.LocalDate;
22  import org.kuali.kpme.core.accrualcategory.AccrualCategory;
23  import org.kuali.kpme.core.accrualcategory.rule.AccrualCategoryRule;
24  import org.kuali.kpme.core.principal.PrincipalHRAttributes;
25  import org.kuali.kpme.core.service.HrServiceLocator;
26  import org.kuali.kpme.core.util.HrConstants;
27  import org.kuali.kpme.core.util.ValidationUtils;
28  import org.kuali.kpme.tklm.leave.override.EmployeeOverride;
29  import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
30  import org.kuali.kpme.tklm.leave.timeoff.SystemScheduledTimeOff;
31  import org.kuali.kpme.tklm.leave.transfer.BalanceTransfer;
32  import org.kuali.rice.krad.util.GlobalVariables;
33  import org.kuali.rice.krad.util.ObjectUtils;
34  
35  public class BalanceTransferValidationUtils {
36  
37  	public static boolean validateTransfer(BalanceTransfer balanceTransfer) {
38  		boolean isValid = true;
39  		if(StringUtils.isNotEmpty(balanceTransfer.getSstoId())) {
40  			return isValid && validateSstoTranser(balanceTransfer) ;
41  		}
42  		String principalId = balanceTransfer.getPrincipalId();
43  		LocalDate effectiveDate = balanceTransfer.getEffectiveLocalDate();
44  		String fromAccrualCategory = balanceTransfer.getFromAccrualCategory();
45  		String toAccrualCategory = balanceTransfer.getToAccrualCategory();
46  		AccrualCategory fromCat = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate);
47  		
48  		if(!ValidationUtils.validateAccrualCategory(fromAccrualCategory, effectiveDate)) {
49  			GlobalVariables.getMessageMap().putError("balanceTransfer.fromAccrualCategory", "balanceTransfer.accrualcategory.exists");
50  			isValid &= false;
51  		}
52  		
53  		if(!ValidationUtils.validateAccrualCategory(toAccrualCategory, effectiveDate)) {
54  			GlobalVariables.getMessageMap().putError("balanceTransfer.toAccrualCategory", "balanceTransfer.accrualcategory.exists");
55  			isValid &= false;
56  		}
57  		
58  		if(!ValidationUtils.validatePrincipalId(principalId)) {
59  			GlobalVariables.getMessageMap().putError("balanceTransfer.principalId", "balanceTransfer.principal.exists");
60  			isValid &= false;
61  		}
62  		
63  		if(effectiveDate.isAfter(LocalDate.now().plusYears(1))) {
64  			GlobalVariables.getMessageMap().putError("balanceTransfer.effectiveDate", "balanceTransfer.effectiveDate.error");
65  			isValid &= false;
66  		}
67  		
68  		AccrualCategory toCat = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(toAccrualCategory, effectiveDate);
69  		PrincipalHRAttributes pha = HrServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate);
70  		
71  		if(ObjectUtils.isNotNull(pha)) {
72  			if(ObjectUtils.isNotNull(pha.getLeavePlan())) {
73  				AccrualCategoryRule acr = HrServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat,
74  						effectiveDate, pha.getServiceLocalDate());
75  				if(ObjectUtils.isNotNull(acr)) {
76  					if(ObjectUtils.isNotNull(acr.getMaxBalFlag())
77  							&& StringUtils.isNotBlank(acr.getMaxBalFlag())
78  							&& StringUtils.isNotEmpty(acr.getMaxBalFlag())
79  							&& StringUtils.equals(acr.getMaxBalFlag(), "Y")) {
80  						if(ObjectUtils.isNotNull(acr.getMaxBalanceTransferToAccrualCategory()) || StringUtils.equals(HrConstants.ACTION_AT_MAX_BALANCE.LOSE, acr.getActionAtMaxBalance())) {
81  /*							isValid &= validatePrincipal(pha,principalId);
82  							isValid &= validateEffectiveDate(effectiveDate);
83  							isValid &= validateAgainstLeavePlan(pha,fromCat,toCat,effectiveDate);
84  							isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr);
85  							isValid &= validateTransferToAccrualCategory(toCat,principalId,effectiveDate,acr);*/
86  							isValid &= validateAmountTransferred(balanceTransfer.getAmountTransferred());
87  							isValid &= validateMaxCarryOver(balanceTransfer.getAmountTransferred(),toCat,principalId,effectiveDate,acr, pha);
88  							isValid &= validateTransferAmount(balanceTransfer.getTransferAmount(),fromCat,toCat, principalId, effectiveDate, acr);
89  							isValid &= validateForfeitedAmount(balanceTransfer.getForfeitedAmount());
90  						}
91  						else {
92  							//should never be the case if accrual category rules are validated correctly.
93  							GlobalVariables.getMessageMap().putError("balanceTransfer.fromAccrualCategory",
94  									"balanceTransfer.fromAccrualCategory.rules.transferToAccrualCategory",
95  									fromAccrualCategory);
96  							isValid &= false;
97  						}
98  					}
99  					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 }