View Javadoc
1   /**
2    * Copyright 2004-2014 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.calendar.validation;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.log4j.Logger;
21  import org.joda.time.*;
22  import org.kuali.kpme.core.api.accrualcategory.AccrualCategoryContract;
23  import org.kuali.kpme.core.api.accrualcategory.AccrualEarnInterval;
24  import org.kuali.kpme.core.api.assignment.Assignment;
25  import org.kuali.kpme.core.api.assignment.AssignmentDescriptionKey;
26  import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
27  import org.kuali.kpme.core.api.earncode.EarnCode;
28  import org.kuali.kpme.core.api.earncode.EarnCodeContract;
29  import org.kuali.kpme.core.api.earncode.group.EarnCodeGroup;
30  import org.kuali.kpme.core.api.principal.PrincipalHRAttributesContract;
31  import org.kuali.kpme.core.calendar.entry.CalendarEntryBo;
32  import org.kuali.kpme.core.service.HrServiceLocator;
33  import org.kuali.kpme.core.util.HrConstants;
34  import org.kuali.kpme.core.util.HrContext;
35  import org.kuali.kpme.core.util.TKUtils;
36  import org.kuali.kpme.tklm.api.leave.accrual.RateRangeAggregateContract;
37  import org.kuali.kpme.tklm.api.leave.block.LeaveBlock;
38  import org.kuali.kpme.tklm.api.leave.block.LeaveBlockContract;
39  import org.kuali.kpme.tklm.api.leave.override.EmployeeOverrideContract;
40  import org.kuali.kpme.tklm.api.leave.summary.LeaveSummaryContract;
41  import org.kuali.kpme.tklm.api.leave.summary.LeaveSummaryRowContract;
42  import org.kuali.kpme.tklm.common.CalendarValidationUtil;
43  import org.kuali.kpme.tklm.common.LMConstants;
44  import org.kuali.kpme.tklm.leave.calendar.web.LeaveCalendarForm;
45  import org.kuali.kpme.tklm.leave.calendar.web.LeaveCalendarWSForm;
46  import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
47  import org.kuali.rice.kew.api.KewApiServiceLocator;
48  import org.kuali.rice.kew.api.document.DocumentStatus;
49  
50  import java.math.BigDecimal;
51  import java.util.*;
52  
53  public class LeaveCalendarValidationUtil extends CalendarValidationUtil {
54      
55  	private static Logger LOG = Logger.getLogger(LeaveCalendarValidationUtil.class);
56  	
57  	public static List<String> validateLeaveEntry(LeaveCalendarForm lcf) {
58  
59      	List<String> errorMsgList = new ArrayList<String>();
60          CalendarEntry leaveCalendarEntry = lcf.getCalendarEntry();
61      	
62      	if(leaveCalendarEntry != null) {
63  	    	// validates the selected earn code exists on every day within the date range
64  	    	errorMsgList.addAll(CalendarValidationUtil.validateEarnCode(lcf.getSelectedEarnCode(), lcf.getStartDate(), lcf.getEndDate()));
65  	    	if(errorMsgList.isEmpty()) {
66  		    	errorMsgList.addAll(LeaveCalendarValidationUtil.validateLeaveParametersByEarnCodeRecordMethod(lcf));
67  		    	LeaveBlock updatedLeaveBlock = null;
68  		    	if(lcf.getLeaveBlockId() != null) {
69  					updatedLeaveBlock = LmServiceLocator.getLeaveBlockService().getLeaveBlock(lcf.getLeaveBlockId());
70  		    	}
71  		    	errorMsgList.addAll(LeaveCalendarValidationUtil.validateAvailableLeaveBalanceForUsage(lcf.getSelectedEarnCode(), lcf.getStartDate(), lcf.getEndDate(), lcf.getLeaveAmount(), updatedLeaveBlock));
72  		    	//KPME-1263
73  		        errorMsgList.addAll(LeaveCalendarValidationUtil.validateLeaveAccrualRuleMaxUsage(lcf.getLeaveSummary(), lcf.getSelectedEarnCode(), lcf.getStartDate(),
74  		    			lcf.getEndDate(), lcf.getLeaveAmount(), updatedLeaveBlock));
75  		        errorMsgList.addAll(LeaveCalendarValidationUtil.validateHoursUnderTwentyFour(lcf.getSelectedEarnCode(), lcf.getStartDate(), lcf.getEndDate(), lcf.getLeaveAmount()));
76  	    	}
77      	}
78      	//should we really allow validation to pass without a calendar entry, or Log an error and throw some kind of exception?
79  
80      	return errorMsgList;
81  	}
82      
83      public static List<String> validateLeaveParametersByEarnCodeRecordMethod(LeaveCalendarForm lcf) {
84      	List<String> errors = new ArrayList<String>();
85      	if (StringUtils.isNotBlank(lcf.getSelectedEarnCode()) &&  lcf.getCalendarEntry() != null) {
86      		//earn code is validate through the span of the leave entry, could the earn code's record method change between then and the leave period end date?
87      		//Why not use endDateS to retrieve the earn code?
88              CalendarEntry calendarEntry = lcf.getCalendarEntry();
89      		EarnCode earnCode = HrServiceLocator.getEarnCodeService().getEarnCode(lcf.getSelectedEarnCode(), calendarEntry.getEndPeriodFullDateTime().toLocalDate());
90      		if(earnCode != null) {
91      			if(earnCode.getRecordMethod().equalsIgnoreCase(HrConstants.EARN_CODE_TIME)) {
92      		    	return validateTimeParametersForLeaveEntry(earnCode, lcf.getCalendarEntry(), lcf.getStartDate(), lcf.getEndDate(), lcf.getStartTime(), lcf.getEndTime(), lcf.getSelectedAssignment(), lcf.getLeaveBlockId(), lcf.getSpanningWeeks());
93      			}
94      			// we should not have any leave earn codes with amount recording method
95  //    			else if (earnCode.getRecordMethod().equalsIgnoreCase(HrConstants.EARN_CODE_AMOUNT)) {
96  //    		    	return validateAmountParametersForLeaveEntry(earnCode, lcf.getCalendarEntry(), lcf.getStartDate(), lcf.getEndDate(), lcf.getSelectedAssignment(), lcf.getLeaveBlockId());
97  //    			}
98      			else if (earnCode.getRecordMethod().equalsIgnoreCase(HrConstants.EARN_CODE_HOUR)) {
99      		    	return validateHourParametersForLeaveEntry(earnCode, lcf.getCalendarEntry(), lcf.getStartDate(), lcf.getEndDate(), lcf.getLeaveAmount());
100     			}
101     			else if (earnCode.getRecordMethod().equalsIgnoreCase(HrConstants.EARN_CODE_DAY)) {
102     		    	return validateDayParametersForLeaveEntry(earnCode, lcf.getCalendarEntry(), lcf.getStartDate(), lcf.getEndDate(), lcf.getLeaveAmount());
103     			}
104     		}
105     	}
106     	return errors;
107     }
108 	
109     public static List<String> validateTimeParametersForLeaveEntry(EarnCode selectedEarnCode, CalendarEntry leaveCalEntry, String startDateS, String endDateS, String startTimeS, String endTimeS, String selectedAssignment, String leaveBlockId, String spanningWeeks) {
110     	/**
111     	 * Cannot pull this method up to super until validateOverlap is refactored.
112     	 */
113     	List<String> errors = new ArrayList<String>();
114 		//earn code is validate through the span of the leave entry, could the earn code's record method change between then and the leave period end date?
115 		//Why not use endDateS to retrieve the earn code?
116     	
117     	errors.addAll(CalendarValidationUtil.validateDates(startDateS, endDateS));
118         errors.addAll(CalendarValidationUtil.validateTimes(startTimeS, endTimeS));
119         if (errors.size() > 0) return errors;
120 
121         Long startTime;
122         Long endTime;
123        
124         startTime = TKUtils.convertDateStringToDateTimeWithoutZone(startDateS, startTimeS).getMillis();
125         endTime = TKUtils.convertDateStringToDateTimeWithoutZone(endDateS, endTimeS).getMillis();
126 
127         errors.addAll(CalendarValidationUtil.validateInterval(leaveCalEntry, startTime, endTime));
128         if (errors.size() > 0) return errors;
129         
130         if (startTimeS == null) errors.add("The start time is blank.");
131         if (endTimeS == null) errors.add("The end time is blank.");
132         if (startTime - endTime == 0) errors.add("Start time and end time cannot be equivalent");
133         
134         if (errors.size() > 0) return errors;
135 
136         DateTime startTemp = new DateTime(startTime);
137         DateTime endTemp = new DateTime(endTime);
138 
139         if (errors.size() == 0) {
140             Hours hrs = Hours.hoursBetween(startTemp, endTemp);
141             if (hrs.getHours() >= 24) errors.add("One leaveblock cannot exceed 24 hours");
142         }
143         if (errors.size() > 0) return errors;
144         
145         //KPME-2010
146         if(spanningWeeks != null && !StringUtils.equalsIgnoreCase(spanningWeeks,"y")) {
147         	errors.addAll(validateSpanningWeeks(startTemp,endTemp));
148         }
149         
150         //Check that assignment is valid for both days
151         AssignmentDescriptionKey assignKey = HrServiceLocator.getAssignmentService().getAssignmentDescriptionKey(selectedAssignment);
152         Assignment assign = HrServiceLocator.getAssignmentService().getAssignmentForTargetPrincipal(assignKey, startTemp.toLocalDate());
153         
154         if ((startTime.compareTo(endTime) > 0 || endTime.compareTo(startTime) < 0)) {
155             errors.add("The time or date is not valid.");
156         }
157         if (errors.size() > 0) return errors;
158         
159 //		        boolean isRegularEarnCode = StringUtils.equals(assign.getJob().getPayTypeObj().getRegEarnCode(),selectedEarnCode);
160         boolean isRegularEarnCode = true;
161     	errors.addAll(validateOverlap(startTime, endTime, startDateS, endTimeS,startTemp, endTemp, leaveCalEntry, leaveBlockId, isRegularEarnCode, selectedEarnCode.getRecordMethod()));
162         if (errors.size() > 0) return errors;
163         return errors;
164     }
165     
166     //begin KPME-1263
167     public static List<String> validateLeaveAccrualRuleMaxUsage(LeaveCalendarWSForm lcf) {
168     	LeaveBlock updatedLeaveBlock = null;
169     	if(lcf.getLeaveBlockId() != null) {
170     		updatedLeaveBlock = LmServiceLocator.getLeaveBlockService().getLeaveBlock(lcf.getLeaveBlockId());
171     	}
172     	LeaveSummaryContract leaveSummary = LmServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDate(HrContext.getTargetPrincipalId(), TKUtils.formatDateString(lcf.getEndDate()));
173     	return validateLeaveAccrualRuleMaxUsage(leaveSummary, lcf.getSelectedEarnCode(), lcf.getStartDate(),
174     			lcf.getEndDate(), lcf.getLeaveAmount(), updatedLeaveBlock);
175     }
176 
177 	public static List<String> validateLeaveAccrualRuleMaxUsage(LeaveSummaryContract ls, String selectedEarnCode, String leaveStartDateString,
178 			String leaveEndDateString, BigDecimal leaveAmount, LeaveBlock updatedLeaveBlock) {
179     	List<String> errors = new ArrayList<String>();
180         String principalId = HrContext.getTargetPrincipalId();
181     	long daysSpan = TKUtils.getDaysBetween(TKUtils.formatDateString(leaveStartDateString), TKUtils.formatDateString(leaveEndDateString));
182     	if(leaveAmount == null) {
183     		leaveAmount  = TKUtils.getHoursBetween(TKUtils.formatDateString(leaveStartDateString).toDate().getTime(), TKUtils.formatDateString(leaveEndDateString).toDate().getTime());
184     	}
185     	if(ls != null && CollectionUtils.isNotEmpty(ls.getLeaveSummaryRows())) {
186 	    	BigDecimal oldLeaveAmount = null;
187 	    	boolean earnCodeChanged = false;
188     		if(updatedLeaveBlock != null) {
189     			if(!updatedLeaveBlock.getEarnCode().equals(selectedEarnCode)) {
190     				earnCodeChanged = true;
191     			}
192     			if(!updatedLeaveBlock.getLeaveAmount().equals(leaveAmount)) {
193     				oldLeaveAmount = updatedLeaveBlock.getLeaveAmount();
194     			}
195     		}
196     		LocalDate aDate = TKUtils.formatDateString(leaveEndDateString);
197 	    	EarnCodeContract earnCodeObj = HrServiceLocator.getEarnCodeService().getEarnCode(selectedEarnCode, aDate);
198 	    	if(earnCodeObj != null && StringUtils.equals(earnCodeObj.getAccrualBalanceAction(),HrConstants.ACCRUAL_BALANCE_ACTION.USAGE)
199                     || StringUtils.equals(earnCodeObj.getUsageLimit(), "I")) {
200 	    		AccrualCategoryContract accrualCategory = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCodeObj.getAccrualCategory(), aDate);
201 	    		if(accrualCategory != null) {
202 	    			List<? extends LeaveSummaryRowContract> rows = ls.getLeaveSummaryRows();
203 	    			for(LeaveSummaryRowContract aRow : rows) {
204 	    				if(aRow.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
205 	    					//Does employee have overrides in place?
206 	    					List<? extends EmployeeOverrideContract> employeeOverrides = LmServiceLocator.getEmployeeOverrideService().getEmployeeOverrides(principalId,TKUtils.formatDateString(leaveEndDateString));
207 	    					String leavePlan = accrualCategory.getLeavePlan();
208 	    					BigDecimal maxUsage = aRow.getUsageLimit();
209 	    					for(EmployeeOverrideContract eo : employeeOverrides) {
210 	    						if(eo.getLeavePlan().equals(leavePlan) && eo.getAccrualCategory().equals(aRow.getAccrualCategory())) {
211 	    							if(eo.getOverrideType().equals("MU") && eo.isActive()) {
212 	    								if(eo.getOverrideValue()!=null) {
213 	    									maxUsage = new BigDecimal(eo.getOverrideValue());
214                                         } else { // no limit flag
215 	    									maxUsage = null;
216                                         }
217 	    							}
218 	    						}
219 	    					}
220 	    					BigDecimal ytdUsage = aRow.getYtdApprovedUsage();
221 	    					BigDecimal pendingLeaveBalance = aRow.getPendingLeaveRequests();
222 	    					BigDecimal desiredUsage = new BigDecimal(0);
223 	    					if(pendingLeaveBalance!=null) {
224 	    						if(oldLeaveAmount!=null) {
225 	    							
226 	    							if(!earnCodeChanged || 
227 	    									StringUtils.equals(updatedLeaveBlock.getAccrualCategory(), accrualCategory.getAccrualCategory())) {
228    			    						pendingLeaveBalance = pendingLeaveBalance.subtract(oldLeaveAmount.abs());
229 	    							}
230 	    						}
231  
232     							desiredUsage = desiredUsage.add(pendingLeaveBalance);
233 	    					}
234    							
235 	    					desiredUsage = desiredUsage.add(leaveAmount.multiply(new BigDecimal(daysSpan+1)));
236 
237    							if(ytdUsage!=null) {
238     							desiredUsage = desiredUsage.add(ytdUsage);
239     						}
240 	    					if(maxUsage!=null) {
241 		    					if(desiredUsage.compareTo(maxUsage) > 0 ) {
242 		    						errors.add("This leave request would exceed the usage limit for " + aRow.getAccrualCategory());                        //errorMessages
243 		    					}
244 	    					}
245 	    				}
246 	    			}
247 	    		}
248 	    	}
249     	}
250     	return errors;
251     }
252 	//End KPME-1263
253 
254 	//TODO: Move to WarningService
255 	public static Map<String, Set<String>> validatePendingTransactions(String principalId, LocalDate fromDate, LocalDate toDate) {
256 		Map<String, Set<String>> allMessages = new HashMap<String, Set<String>>();
257 		
258         Set<String> actionMessages = new HashSet<String>();
259         Set<String> infoMessages = new HashSet<String>();
260         Set<String> warningMessages = new HashSet<String>();
261         
262         List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(principalId, fromDate, toDate, LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
263         Set<String> workflowDocIds = new HashSet<String>();
264         boolean transferForfeit = false;
265         for(LeaveBlock lb : leaveBlocks) {
266         	if(lb.getTransactionalDocId() != null) {
267         		workflowDocIds.add(lb.getTransactionalDocId());
268             }
269     		if(StringUtils.contains(lb.getDescription(), LMConstants.TRANSFER_FORFEIT_LB_DESCRIPTION)) {
270     			transferForfeit = true;
271             }
272         }
273         for(String workflowDocId : workflowDocIds) {
274             DocumentStatus status = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(workflowDocId);
275             
276             if(StringUtils.equals(status.getCode(), HrConstants.ROUTE_STATUS.FINAL)) {
277             	//show only one of these two messages.
278             	if(transferForfeit
279                 		&& !infoMessages.contains("One or more balance transfer(s) that forfeited accrued leave occurred on this calendar")) 
280                 	infoMessages.add("One or more balance transfer(s) that forfeited accrued leave occurred on this calendar");
281             	else if(!transferForfeit
282             			&& !infoMessages.contains("A balance transfer action occurred on this calendar")) {
283             		infoMessages.add("A balance transfer action occurred on this calendar");
284             	}
285             }
286             else if(StringUtils.equals(status.getCode(), HrConstants.ROUTE_STATUS.ENROUTE)
287             		&& !infoMessages.contains("A pending balance transfer exists on this calendar. It must be finalized before this calendar can be approved")) {
288             	actionMessages.add("A pending balance transfer exists on this calendar. It must be finalized before this calendar can be approved");
289             }
290         }
291         
292         leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(principalId, fromDate, toDate, LMConstants.LEAVE_BLOCK_TYPE.LEAVE_PAYOUT);
293         workflowDocIds = new HashSet<String>();
294         boolean payoutForfeit = false;
295         for(LeaveBlock lb : leaveBlocks) {
296         	if(lb.getTransactionalDocId() != null) {
297         		workflowDocIds.add(lb.getTransactionalDocId());
298             }
299     		if(StringUtils.contains(lb.getDescription(), LMConstants.PAYOUT_FORFEIT_LB_DESCRIPTION)) {
300     			payoutForfeit = true;
301             }
302         }
303         for(String workflowDocId : workflowDocIds) {
304             DocumentStatus status = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(workflowDocId);
305 
306             if(StringUtils.equals(status.getCode(), HrConstants.ROUTE_STATUS.FINAL)) {
307             	//only show one of these two messages.
308             	if(payoutForfeit
309                 		&& !infoMessages.contains("One or more leave payout(s) that forfeited accrued leave occurred on this calendar")) 
310                 	infoMessages.add("One or more leave payout(s) that forfeited accrued leave occurred on this calendar");
311             	else if(!payoutForfeit
312             			&& !infoMessages.contains("A payout action occurred on this calendar")) {
313             		infoMessages.add("A leave payout action occurred on this calendar");
314             	}
315             }
316             else if(StringUtils.equals(status.getCode(), HrConstants.ROUTE_STATUS.ENROUTE)
317             		&& !infoMessages.contains("A pending payout exists on this calendar. It must be finalized before this calendar can be approved")) {
318             	actionMessages.add("A pending payout exists on this calendar. It must be finalized before this calendar can be approved");
319             }
320         }
321         allMessages.put("actionMessages", actionMessages);
322         allMessages.put("infoMessages", infoMessages);
323         allMessages.put("warningMessages", warningMessages);
324         
325         return allMessages;
326 	}
327 	
328     // get warning messages associated with earn codes of leave blocks
329     public static Map<String, Set<String>> getWarningMessagesForLeaveBlocks(List<LeaveBlock> leaveBlocks, DateTime beginDate, DateTime endDate) {
330 //        List<String> warningMessages = new ArrayList<String>();
331         Map<String, Set<String>> allMessages = new HashMap<String, Set<String>>();
332         
333         Set<String> actionMessages = new HashSet<String>();
334         Set<String> infoMessages = new HashSet<String>();
335         Set<String> warningMessages = new HashSet<String>();
336 
337         if (CollectionUtils.isNotEmpty(leaveBlocks)) {
338             for(LeaveBlockContract lb : leaveBlocks) {
339             	if(lb.getLeaveDateTime().compareTo(beginDate) >= 0 && lb.getLeaveDateTime().compareTo(endDate) < 0) {
340 	                EarnCodeContract ec = HrServiceLocator.getEarnCodeService().getEarnCode(lb.getEarnCode(), lb.getLeaveLocalDate());
341 	                if(ec != null) {
342 	                	// KPME-2529
343 	                    //EarnCodeGroup eg = HrServiceLocator.getEarnCodeGroupService().getEarnCodeGroupForEarnCode(lb.getEarnCode(), lb.getLeaveLocalDate());
344 	                	List<EarnCodeGroup> egs = HrServiceLocator.getEarnCodeGroupService().getEarnCodeGroupsForEarnCode(lb.getEarnCode(), lb.getLeaveLocalDate());
345 	                	if (egs != null && egs.size() > 0) {                	    
346 	                		for (EarnCodeGroup eg : egs) {
347 			                    if(!StringUtils.isEmpty(eg.getWarningText())) {
348 			                        warningMessages.add(eg.getWarningText());
349 			                    }
350 	                		}
351 	                	}
352 	                	// check if Earncode is Absent earncode
353 						if("Y".equalsIgnoreCase(ec.getAffectPay()) && "N".equalsIgnoreCase(ec.getEligibleForAccrual())) {
354 							String message = "Absent time cannot be used until other accrual balances are zero or below a specified accrual balance.";
355 							warningMessages.add(message);
356 		                    break;
357 						}
358 	                }
359             	}
360             }
361         }
362         allMessages.put("actionMessages", actionMessages);
363         allMessages.put("infoMessages", infoMessages);
364         allMessages.put("warningMessages", warningMessages);
365 
366 //        warningMessages.addAll(aSet);
367         return allMessages;
368     }
369 
370     public static List<String> validateAvailableLeaveBalance(LeaveCalendarWSForm lcf) {
371     	LeaveBlock updatedLeaveBlock = null;
372     	if(lcf.getLeaveBlockId() != null) {
373 			updatedLeaveBlock = LmServiceLocator.getLeaveBlockService().getLeaveBlock(lcf.getLeaveBlockId());
374     	}
375     	return validateAvailableLeaveBalanceForUsage(lcf.getSelectedEarnCode(), lcf.getStartDate(), lcf.getEndDate(), lcf.getLeaveAmount(), updatedLeaveBlock);
376     }
377 
378     public static List<String> validateAvailableLeaveBalanceForUsage(String earnCode, String leaveStartDateString, String leaveEndDateString,
379     		BigDecimal leaveAmount, LeaveBlock updatedLeaveBlock) {
380     	List<String> errors = new ArrayList<String>();
381     	boolean earnCodeChanged = false;
382     	BigDecimal oldAmount = null;
383     	
384     	if(leaveAmount == null) {
385     		leaveAmount  = TKUtils.getHoursBetween(TKUtils.formatDateString(leaveStartDateString).toDate().getTime(), TKUtils.formatDateString(leaveEndDateString).toDate().getTime());
386     	}
387 		if(updatedLeaveBlock != null) {
388 			if(!updatedLeaveBlock.getEarnCode().equals(earnCode)) {
389 				earnCodeChanged = true;
390 			}
391 			if(!updatedLeaveBlock.getLeaveAmount().equals(leaveAmount)) {
392 				oldAmount = updatedLeaveBlock.getLeaveAmount();
393 			}
394 		}
395 		LocalDate startDate = TKUtils.formatDateString(leaveStartDateString);
396 		LocalDate endDate = TKUtils.formatDateString(leaveEndDateString);
397 		long daysSpan = TKUtils.getDaysBetween(startDate,endDate);
398     	EarnCodeContract earnCodeObj = HrServiceLocator.getEarnCodeService().getEarnCode(earnCode, endDate);
399     	if(earnCodeObj != null && earnCodeObj.getAllowNegativeAccrualBalance().equals("N")) {
400     		AccrualCategoryContract accrualCategory = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCodeObj.getAccrualCategory(), endDate);
401     		if(accrualCategory != null) {
402                 AccrualEarnInterval accrualEarnInterval = AccrualEarnInterval.fromCode(accrualCategory.getAccrualEarnInterval());
403                 DateTime nextIntervalDate;
404                 if (accrualEarnInterval != null
405                         && AccrualEarnInterval.PAY_CAL.equals(accrualEarnInterval)) {
406                     RateRangeAggregateContract rrAggregate = LmServiceLocator.getAccrualService().buildRateRangeAggregate(HrContext.getTargetPrincipalId(), startDate.toDateTimeAtStartOfDay(), endDate.toDateTimeAtStartOfDay());
407                     PrincipalHRAttributesContract phra = rrAggregate.getRateOnDate(endDate.toDateTimeAtStartOfDay()).getPrincipalHRAttributes();
408                     nextIntervalDate = LmServiceLocator.getAccrualService().getNextIntervalDate(endDate.toDateTimeAtStartOfDay(), accrualEarnInterval.getCode(), phra.getPayCalendar(), rrAggregate.getCalEntryMap());
409                 } else {
410     			    nextIntervalDate = LmServiceLocator.getAccrualService().getNextAccrualIntervalDate(accrualCategory.getAccrualEarnInterval(), endDate.toDateTimeAtStartOfDay());
411                 }
412 				// get the usage checking cut off Date, normally it's the day before the next interval date
413     			DateTime usageEndDate = nextIntervalDate;
414 				if (nextIntervalDate.compareTo(endDate.toDateTimeAtCurrentTime()) > 0) {
415 					usageEndDate = nextIntervalDate.minusDays(1);
416 				}
417 				// use the end of the year as the interval date for usage checking of no-accrual hours,
418 				// normally no-accrual hours are from banked/transferred system scheduled time offs
419 				if(accrualCategory.getAccrualEarnInterval().equals(AccrualEarnInterval.NO_ACCRUAL.getCode())) {
420 					usageEndDate = endDate.toDateTimeAtStartOfDay().withMonthOfYear(DateTimeConstants.DECEMBER).withDayOfMonth(31);
421 				}
422 				BigDecimal availableBalance = LmServiceLocator.getLeaveSummaryService()
423 							.getLeaveBalanceForAccrCatUpToDate(HrContext.getTargetPrincipalId(), startDate, endDate, accrualCategory.getAccrualCategory(), usageEndDate.toLocalDate());
424 
425 				if(oldAmount!=null) {
426 					if(!earnCodeChanged ||
427 							(updatedLeaveBlock.getAccrualCategory() != null && updatedLeaveBlock.getAccrualCategory().equals(accrualCategory.getAccrualCategory()))) {
428 						availableBalance = availableBalance.add(oldAmount.abs());
429 					}
430 				}
431 				//multiply by days in span in case the user has also edited the start/end dates.
432 				// daySpan for the same start/end dates is 0 so we need to add 1 to it
433                 BigDecimal desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan+1));
434 //				BigDecimal desiredUsage =null;
435 //				if(!HrConstants.EARN_CODE_TIME.equals(earnCodeObj.getRecordMethod())) {
436 //					desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan+1));
437 //				} else {
438 //					desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan));
439 //				}
440 				
441 				if(desiredUsage.compareTo(availableBalance) >  0 ) {
442 					errors.add("Requested leave amount " + desiredUsage.toString() + " is greater than available leave balance " + availableBalance.toString());      //errorMessages
443 				}
444     		}
445     	}
446     
447     	return errors;
448     }
449     
450     /*
451      * Moving to CalendarValidationUtil
452      */
453     @Deprecated
454     public static List<String> validateDates(String startDateS, String endDateS) {
455         List<String> errors = new ArrayList<String>();
456         if (errors.size() == 0 && StringUtils.isEmpty(startDateS)) errors.add("The start date is blank.");
457         if (errors.size() == 0 && StringUtils.isEmpty(endDateS)) errors.add("The end date is blank.");
458         return errors;
459     }
460 
461     /*
462      * Moving to CalendarValidationUtil
463      */
464     @Deprecated
465     public static List<String> validateTimes(String startTimeS, String endTimeS) {
466         List<String> errors = new ArrayList<String>();
467         if (errors.size() == 0 && startTimeS == null) errors.add("The start time is blank.");
468         if (errors.size() == 0 && endTimeS == null) errors.add("The end time is blank.");
469         return errors;
470     }
471 
472 //    public static List<String> validateAvailableLeaveBalance(LeaveSummary ls, String earnCode, String leaveStartDateString, String leaveEndDateString,
473 //    		BigDecimal leaveAmount, LeaveBlock updatedLeaveBlock) {
474 //    	List<String> errors = new ArrayList<String>();
475 //    	CalendarEntry calendarEntries = new CalendarEntry();
476 //    	boolean earnCodeChanged = false;
477 //    	BigDecimal oldAmount = null;
478 //    	if(ls != null && CollectionUtils.isNotEmpty(ls.getLeaveSummaryRows())) {
479 //    		if(updatedLeaveBlock != null) {
480 //    			if(!updatedLeaveBlock.getEarnCode().equals(earnCode)) {
481 //    				earnCodeChanged = true;
482 //    			}
483 //    			if(!updatedLeaveBlock.getLeaveAmount().equals(leaveAmount)) {
484 //    				oldAmount = updatedLeaveBlock.getLeaveAmount();
485 //    			}
486 //    		}
487 //			Date startDate = TKUtils.formatDateString(leaveStartDateString);
488 //			Date endDate = TKUtils.formatDateString(leaveEndDateString);
489 //			long daysSpan = TKUtils.getDaysBetween(startDate,endDate);
490 //	    	EarnCode earnCodeObj = HrServiceLocator.getEarnCodeService().getEarnCode(earnCode, endDate);
491 //	    	if(earnCodeObj != null && earnCodeObj.getAllowNegativeAccrualBalance().equals("N")) {
492 //	    		AccrualCategory accrualCategory = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCodeObj.getAccrualCategory(), endDate);
493 //	    		if(accrualCategory != null) {
494 //	    			LeaveSummaryRow validationRow = ls.getLeaveSummaryRowForAccrualCategory(accrualCategory.getLmAccrualCategoryId());
495 //    				if(ObjectUtils.isNotNull(validationRow)) {
496 //    					BigDecimal availableBalance = validationRow.getLeaveBalance();
497 //    					LeaveSummary ytdSummary = LmServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDateForAccrualCategory(HrContext.getTargetPrincipalId(), startDate, accrualCategory.getAccrualCategory());
498 //    					if(ytdSummary != null) {
499 //    						LeaveSummaryRow ytdSummaryRow = ytdSummary.getLeaveSummaryRowForAccrualCategory(accrualCategory.getLmAccrualCategoryId());
500 //    						if(ytdSummaryRow != null)
501 //    							availableBalance = ytdSummaryRow.getLeaveBalance();
502 //    					}
503 //
504 //    					if(oldAmount!=null) {
505 //
506 //	    					if(!earnCodeChanged ||
507 //	    							updatedLeaveBlock.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
508 //								availableBalance = availableBalance.add(oldAmount.abs());
509 //	    					}
510 //
511 //						}
512 //						//multiply by days in span in case the user has also edited the start/end dates.
513 //    					BigDecimal desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan+1));
514 //
515 //    					if(desiredUsage.compareTo(availableBalance) >  0 ) {
516 //    						errors.add("Requested leave amount is greater than available leave balance.");      //errorMessages
517 //    					}
518 //    				}
519 //	    		}
520 //	    	}
521 //    	}
522 //    	
523 //    	return errors;
524 //    }
525 
526     /*
527 	 * Moving to CalendarValidationUtil
528 	 */
529 	@Deprecated
530     public static List<String> validateInterval(CalendarEntryBo payCalEntry, Long startTime, Long endTime) {
531         List<String> errors = new ArrayList<String>();
532         LocalDateTime pcb_ldt = payCalEntry.getBeginPeriodLocalDateTime();
533         LocalDateTime pce_ldt = payCalEntry.getEndPeriodLocalDateTime();
534         DateTimeZone utz = HrServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
535         DateTime p_cal_b_dt = pcb_ldt.toDateTime(utz);
536         DateTime p_cal_e_dt = pce_ldt.toDateTime(utz);
537 
538         Interval payInterval = new Interval(p_cal_b_dt, p_cal_e_dt);
539         if (errors.size() == 0 && !payInterval.contains(startTime)) {
540             errors.add("The start date/time is outside the pay period");
541         }
542         if (errors.size() == 0 && !payInterval.contains(endTime) && p_cal_e_dt.getMillis() != endTime) {
543             errors.add("The end date/time is outside the pay period");
544         }
545         return errors;
546     }
547     
548     public static List<String> validateOverlap(Long startTime, Long endTime, String startDateS, String endTimeS, DateTime startTemp, DateTime endTemp, CalendarEntry calendarEntry, String lmLeaveBlockId, boolean isRegularEarnCode, String earnCodeType) {
549         List<String> errors = new ArrayList<String>();
550         Interval addedTimeblockInterval = new Interval(startTime, endTime);
551         List<Interval> dayInt = new ArrayList<Interval>();
552         String viewPrincipal = HrContext.getTargetPrincipalId();
553         
554         dayInt.add(addedTimeblockInterval);
555         List<Assignment> assignments = HrServiceLocator.getAssignmentService().getAllAssignmentsByCalEntryForLeaveCalendar(viewPrincipal, calendarEntry);
556 		List<String> assignmentKeys = new ArrayList<String>();
557         for(Assignment assign : assignments) {
558         	assignmentKeys.add(assign.getAssignmentKey());
559         }
560         
561         List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForLeaveCalendar(viewPrincipal, calendarEntry.getBeginPeriodFullDateTime().toLocalDate(), calendarEntry.getEndPeriodFullDateTime().toLocalDate(), assignmentKeys);
562         for (LeaveBlock leaveBlock : leaveBlocks) {
563         	 if (errors.size() == 0 && StringUtils.equals(earnCodeType, HrConstants.EARN_CODE_TIME) && leaveBlock.getBeginDateTime() != null && leaveBlock.getEndDateTime()!= null) {
564                 Interval leaveBlockInterval = new Interval(leaveBlock.getBeginDateTime(), leaveBlock.getEndDateTime());
565                 for (Interval intv : dayInt) {
566                     if (isRegularEarnCode && leaveBlockInterval.overlaps(intv) && (lmLeaveBlockId == null || lmLeaveBlockId.compareTo(leaveBlock.getLmLeaveBlockId()) != 0)) {
567                         errors.add("The leave block you are trying to add overlaps with an existing time block.");
568                     }
569                 }
570         	 }
571         }
572 
573         return errors;
574     }
575 
576 	public static Collection<? extends String> validateHoursUnderTwentyFour(
577 			String selectedEarnCode, String startDate, String endDate, BigDecimal leaveAmount) {
578     	List<String> errors = new ArrayList<String>();
579 
580     	LocalDate aDate = TKUtils.formatDateString(endDate);
581     	
582     	if (leaveAmount != null
583             && StringUtils.isNotBlank(selectedEarnCode)) {
584     		EarnCodeContract  earnCode = HrServiceLocator.getEarnCodeService().getEarnCode(selectedEarnCode, aDate);
585 	    	
586     		if(earnCode != null && earnCode.getRecordMethod().equalsIgnoreCase(HrConstants.EARN_CODE_HOUR)) {
587     			if(leaveAmount.compareTo(new BigDecimal(24.0)) > 0) {
588     				errors.add("Cannot exceed 24 hours in one day");
589     			}
590     		}
591     		else if (earnCode != null) {
592     			AccrualCategoryContract accrualCategory = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCode.getAccrualCategory(), aDate);
593     			if(accrualCategory != null && StringUtils.equals(accrualCategory.getUnitOfTime(),"H")) {
594     				if(leaveAmount.compareTo(new BigDecimal(24.0)) > 0) {
595     					errors.add("Cannot exceed 24 hours in one day");
596     				}
597     			}
598     		}
599 		}
600 		return errors;
601 
602 	}
603 
604 }