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.leavecalendar.validation;
017    
018    import java.math.BigDecimal;
019    import java.sql.Date;
020    import java.util.ArrayList;
021    import java.util.Calendar;
022    import java.util.HashMap;
023    import java.util.HashSet;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.Set;
027    
028    import org.apache.commons.collections.CollectionUtils;
029    import org.apache.commons.lang.StringUtils;
030    import org.joda.time.DateTime;
031    import org.joda.time.DateTimeConstants;
032    import org.joda.time.DateTimeZone;
033    import org.joda.time.Hours;
034    import org.joda.time.Interval;
035    import org.joda.time.LocalDateTime;
036    import org.kuali.hr.lm.LMConstants;
037    import org.kuali.hr.lm.accrual.AccrualCategory;
038    import org.kuali.hr.lm.employeeoverride.EmployeeOverride;
039    import org.kuali.hr.lm.leave.web.LeaveCalendarWSForm;
040    import org.kuali.hr.lm.leaveSummary.LeaveSummary;
041    import org.kuali.hr.lm.leaveSummary.LeaveSummaryRow;
042    import org.kuali.hr.lm.leaveblock.LeaveBlock;
043    import org.kuali.hr.lm.leavecalendar.LeaveCalendarDocument;
044    import org.kuali.hr.time.assignment.Assignment;
045    import org.kuali.hr.time.assignment.AssignmentDescriptionKey;
046    import org.kuali.hr.time.calendar.CalendarEntries;
047    import org.kuali.hr.time.earncode.EarnCode;
048    import org.kuali.hr.time.earncodegroup.EarnCodeGroup;
049    import org.kuali.hr.time.service.base.TkServiceLocator;
050    import org.kuali.hr.time.util.TKContext;
051    import org.kuali.hr.time.util.TKUser;
052    import org.kuali.hr.time.util.TKUtils;
053    import org.kuali.hr.time.util.TkConstants;
054    import org.kuali.rice.kew.api.KewApiServiceLocator;
055    import org.kuali.rice.kew.api.document.DocumentStatus;
056    
057    public class LeaveCalendarValidationUtil {
058        
059        //begin KPME-1263
060        public static List<String> validateLeaveAccrualRuleMaxUsage(LeaveCalendarWSForm lcf) {
061            LeaveBlock updatedLeaveBlock = null;
062            if(lcf.getLeaveBlockId() != null) {
063                    updatedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lcf.getLeaveBlockId());
064            }
065            return validateLeaveAccrualRuleMaxUsage(lcf.getLeaveSummary(), lcf.getSelectedEarnCode(), lcf.getStartDate(),
066                            lcf.getEndDate(), lcf.getLeaveAmount(), updatedLeaveBlock);
067        }
068    
069            public static List<String> validateLeaveAccrualRuleMaxUsage(LeaveSummary ls, String selectedEarnCode, String leaveStartDateString,
070                            String leaveEndDateString, BigDecimal leaveAmount, LeaveBlock updatedLeaveBlock) {
071            List<String> errors = new ArrayList<String>();
072            String principalId = TKContext.getTargetPrincipalId();
073            long daysSpan = TKUtils.getDaysBetween(TKUtils.formatDateString(leaveStartDateString), TKUtils.formatDateString(leaveEndDateString));
074            if(leaveAmount == null) {
075                    leaveAmount  = TKUtils.getHoursBetween(TKUtils.formatDateString(leaveStartDateString).getTime(), TKUtils.formatDateString(leaveEndDateString).getTime());
076            }
077            if(ls != null && CollectionUtils.isNotEmpty(ls.getLeaveSummaryRows())) {
078                    BigDecimal oldLeaveAmount = null;
079                    boolean earnCodeChanged = false;
080                    if(updatedLeaveBlock != null) {
081                            if(!updatedLeaveBlock.getEarnCode().equals(selectedEarnCode)) {
082                                    earnCodeChanged = true;
083                            }
084                            if(!updatedLeaveBlock.getLeaveAmount().equals(leaveAmount)) {
085                                    oldLeaveAmount = updatedLeaveBlock.getLeaveAmount();
086                            }
087                    }
088                    Date aDate = TKUtils.formatDateString(leaveEndDateString);
089                    EarnCode earnCodeObj = TkServiceLocator.getEarnCodeService().getEarnCode(selectedEarnCode, aDate);
090                    if(earnCodeObj != null && StringUtils.equals(earnCodeObj.getAccrualBalanceAction(),LMConstants.ACCRUAL_BALANCE_ACTION.USAGE)
091                                    || StringUtils.equals(earnCodeObj.getUsageLimit(), "I")) {
092                            AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCodeObj.getAccrualCategory(), aDate);
093                            if(accrualCategory != null) {
094                                    List<LeaveSummaryRow> rows = ls.getLeaveSummaryRows();
095                                    for(LeaveSummaryRow aRow : rows) {
096                                            if(aRow.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
097                                                    //Does employee have overrides in place?
098                                                    List<EmployeeOverride> employeeOverrides = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverrides(principalId,TKUtils.formatDateString(leaveEndDateString));
099                                                    String leavePlan = accrualCategory.getLeavePlan();
100                                                    BigDecimal maxUsage = aRow.getUsageLimit();
101                                                    for(EmployeeOverride eo : employeeOverrides) {
102                                                            if(eo.getLeavePlan().equals(leavePlan) && eo.getAccrualCategory().equals(aRow.getAccrualCategory())) {
103                                                                    if(eo.getOverrideType().equals("MU") && eo.isActive()) {
104                                                                            if(eo.getOverrideValue()!=null) {
105                                                                                    maxUsage = new BigDecimal(eo.getOverrideValue());
106                                            } else { // no limit flag
107                                                                                    maxUsage = null;
108                                            }
109                                                                    }
110                                                            }
111                                                    }
112                                                    BigDecimal ytdUsage = aRow.getYtdApprovedUsage();
113                                                    BigDecimal pendingLeaveBalance = aRow.getPendingLeaveRequests();
114                                                    BigDecimal desiredUsage = new BigDecimal(0);
115                                                    if(pendingLeaveBalance!=null) {
116                                                            if(oldLeaveAmount!=null) {
117                                                                    
118                                                                    if(!earnCodeChanged || 
119                                                                                    updatedLeaveBlock.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
120                                                                            pendingLeaveBalance = pendingLeaveBalance.subtract(oldLeaveAmount.abs());
121                                                                    }
122                                                            }
123     
124                                                            desiredUsage = desiredUsage.add(pendingLeaveBalance);
125                                                    }
126                                                            
127                                                    desiredUsage = desiredUsage.add(leaveAmount.multiply(new BigDecimal(daysSpan+1)));
128    
129                                                            if(ytdUsage!=null) {
130                                                            desiredUsage = desiredUsage.add(ytdUsage);
131                                                    }
132                                                    if(maxUsage!=null) {
133                                                            if(desiredUsage.compareTo(maxUsage) > 0 ) {
134                                                                    errors.add("This leave request would exceed the usage limit for " + aRow.getAccrualCategory());                        //errorMessages
135                                                            }
136                                                    }
137                                            }
138                                    }
139                            }
140                    }
141            }
142            return errors;
143        }
144            //End KPME-1263
145    
146            //TODO: Move to WarningService
147            public static Map<String, Set<String>> validatePendingTransactions(String principalId, Date fromDate, Date toDate) {
148                    Map<String, Set<String>> allMessages = new HashMap<String, Set<String>>();
149                    
150            Set<String> actionMessages = new HashSet<String>();
151            Set<String> infoMessages = new HashSet<String>();
152            Set<String> warningMessages = new HashSet<String>();
153            
154            List<LeaveBlock> leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(principalId, fromDate, toDate, LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
155            Set<String> workflowDocIds = new HashSet<String>();
156            for(LeaveBlock lb : leaveBlocks) {
157                    if(lb.getTransactionalDocId() != null) {
158                            workflowDocIds.add(lb.getTransactionalDocId());
159                } else {
160                            if(StringUtils.contains(lb.getDescription(), "Forfeited balance transfer amount")) {
161                                    infoMessages.add("A max balance action that forfeited accrued leave occurred on this calendar");
162                    }
163                }
164            }
165            for(String workflowDocId : workflowDocIds) {
166                DocumentStatus status = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(workflowDocId);
167                
168                if(StringUtils.equals(status.getCode(), TkConstants.ROUTE_STATUS.FINAL)) {
169                    infoMessages.add("A transfer action occurred on this calendar");
170                }
171                else if(StringUtils.equals(status.getCode(), TkConstants.ROUTE_STATUS.ENROUTE)) {
172                    actionMessages.add("A pending balance transfer exists on this calendar. It must be finalized before this calendar can be approved");
173                }
174                else {
175                    warningMessages.add("A balance transfer document exists for this calendar with status neither final nor enroute");
176                }
177            }
178            
179            leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(principalId, fromDate, toDate, LMConstants.LEAVE_BLOCK_TYPE.LEAVE_PAYOUT);
180            workflowDocIds = new HashSet<String>();
181            for(LeaveBlock lb : leaveBlocks) {
182                    if(lb.getTransactionalDocId() != null) {
183                            workflowDocIds.add(lb.getTransactionalDocId());
184                }
185            }
186            for(String workflowDocId : workflowDocIds) {
187                DocumentStatus status = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(workflowDocId);
188    
189                if(StringUtils.equals(status.getCode(), TkConstants.ROUTE_STATUS.FINAL)) {
190                    infoMessages.add("A payout action occurred on this calendar");
191                }
192                else if(StringUtils.equals(status.getCode(), TkConstants.ROUTE_STATUS.ENROUTE)) {
193                    actionMessages.add("A pending payout exists on this calendar. It must be finalized before this calendar can be approved");
194                }
195                else {
196                    warningMessages.add("A payout document exists for this calendar with status neither final or enroute");
197                }
198            }
199            allMessages.put("actionMessages", actionMessages);
200            allMessages.put("infoMessages", infoMessages);
201            allMessages.put("warningMessages", warningMessages);
202            
203            return allMessages;
204            }
205            
206        // get warning messages associated with earn codes of leave blocks
207        public static Map<String, Set<String>> getWarningMessagesForLeaveBlocks(List<LeaveBlock> leaveBlocks) {
208    //        List<String> warningMessages = new ArrayList<String>();
209            Map<String, Set<String>> allMessages = new HashMap<String, Set<String>>();
210            
211            Set<String> actionMessages = new HashSet<String>();
212            Set<String> infoMessages = new HashSet<String>();
213            Set<String> warningMessages = new HashSet<String>();
214    
215            if (CollectionUtils.isNotEmpty(leaveBlocks)) {
216                for(LeaveBlock lb : leaveBlocks) {
217                    EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(lb.getEarnCode(), lb.getLeaveDate());
218                    if(ec != null) {
219                        EarnCodeGroup eg = TkServiceLocator.getEarnCodeGroupService().getEarnCodeGroupForEarnCode(lb.getEarnCode(), lb.getLeaveDate());
220                        if(eg != null && !StringUtils.isEmpty(eg.getWarningText())) {
221                            warningMessages.add(eg.getWarningText());
222                        }
223                    }
224                }
225            }
226            allMessages.put("actionMessages", actionMessages);
227            allMessages.put("infoMessages", infoMessages);
228            allMessages.put("warningMessages", warningMessages);
229    
230    //        warningMessages.addAll(aSet);
231            return allMessages;
232        }
233    
234        public static List<String> validateAvailableLeaveBalance(LeaveCalendarWSForm lcf) {
235            LeaveBlock updatedLeaveBlock = null;
236            if(lcf.getLeaveBlockId() != null) {
237                            updatedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lcf.getLeaveBlockId());
238            }
239            return validateAvailableLeaveBalanceForUsage(lcf.getSelectedEarnCode(), lcf.getStartDate(), lcf.getEndDate(), lcf.getLeaveAmount(), updatedLeaveBlock);
240        }
241    
242        public static List<String> validateAvailableLeaveBalanceForUsage(String earnCode, String leaveStartDateString, String leaveEndDateString,
243                    BigDecimal leaveAmount, LeaveBlock updatedLeaveBlock) {
244            List<String> errors = new ArrayList<String>();
245            boolean earnCodeChanged = false;
246            BigDecimal oldAmount = null;
247            
248            if(leaveAmount == null) {
249                    leaveAmount  = TKUtils.getHoursBetween(TKUtils.formatDateString(leaveStartDateString).getTime(), TKUtils.formatDateString(leaveEndDateString).getTime());
250            }
251                    if(updatedLeaveBlock != null) {
252                            if(!updatedLeaveBlock.getEarnCode().equals(earnCode)) {
253                                    earnCodeChanged = true;
254                            }
255                            if(!updatedLeaveBlock.getLeaveAmount().equals(leaveAmount)) {
256                                    oldAmount = updatedLeaveBlock.getLeaveAmount();
257                            }
258                    }
259                    Date startDate = TKUtils.formatDateString(leaveStartDateString);
260                    Date endDate = TKUtils.formatDateString(leaveEndDateString);
261                    long daysSpan = TKUtils.getDaysBetween(startDate,endDate);
262            EarnCode earnCodeObj = TkServiceLocator.getEarnCodeService().getEarnCode(earnCode, endDate);
263            if(earnCodeObj != null && earnCodeObj.getAllowNegativeAccrualBalance().equals("N")) {
264                    AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCodeObj.getAccrualCategory(), endDate);
265                    if(accrualCategory != null) {
266                                    java.util.Date nextIntervalDate = TkServiceLocator.getAccrualService().getNextAccrualIntervalDate(accrualCategory.getAccrualEarnInterval(), endDate);
267                                    // get the usage checking cut off Date, normally it's the day before the next interval date
268                                    java.util.Date usageEndDate = nextIntervalDate;
269                                    if(nextIntervalDate.compareTo(endDate) > 0) {
270                                            Calendar aCal = Calendar.getInstance();
271                                            aCal.setTime(nextIntervalDate);
272                                            aCal.add(Calendar.DAY_OF_YEAR, -1);
273                                            usageEndDate = aCal.getTime();
274                                    }
275                                    // use the end of the year as the interval date for usage checking of no-accrual hours,
276                                    // normally no-accrual hours are from banked/transferred system scheduled time offs
277                                    if(accrualCategory.getAccrualEarnInterval().equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.NO_ACCRUAL)) {
278                                            Calendar aCal = Calendar.getInstance();
279                                            aCal.setTime(endDate);
280                                            aCal.set(Calendar.MONTH, Calendar.DECEMBER);
281                                            aCal.set(Calendar.DAY_OF_MONTH, 31);
282                                            nextIntervalDate = aCal.getTime();
283                                            usageEndDate = nextIntervalDate;
284                                    }
285                                    BigDecimal availableBalance = TkServiceLocator.getLeaveSummaryService()
286                                                            .getLeaveBalanceForAccrCatUpToDate(TKContext.getTargetPrincipalId(), startDate, endDate, accrualCategory.getAccrualCategory(), usageEndDate);
287    
288                                    if(oldAmount!=null) {
289                                            if(!earnCodeChanged ||
290                                                            updatedLeaveBlock.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
291                                                    availableBalance = availableBalance.add(oldAmount.abs());
292                                            }
293                                    }
294                                    //multiply by days in span in case the user has also edited the start/end dates.
295                                    // daySpan for the same start/end dates is 0 so we need to add 1 to it
296                                    BigDecimal desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan+1));
297    //                              if(!TkConstants.EARN_CODE_TIME.equals(earnCodeObj.getRecordMethod())) {
298    //                                      desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan+1));
299    //                              } else {
300    //                                      desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan));
301    //                              }
302                                    
303                                    if(desiredUsage.compareTo(availableBalance) >  0 ) {
304                                            errors.add("Requested leave amount " + desiredUsage.toString() + " is greater than available leave balance " + availableBalance.toString());      //errorMessages
305                                    }
306                    }
307            }
308        
309            return errors;
310        }
311        
312        public static List<String> validateDates(String startDateS, String endDateS) {
313            List<String> errors = new ArrayList<String>();
314            if (errors.size() == 0 && StringUtils.isEmpty(startDateS)) errors.add("The start date is blank.");
315            if (errors.size() == 0 && StringUtils.isEmpty(endDateS)) errors.add("The end date is blank.");
316            return errors;
317        }
318    
319        public static List<String> validateTimes(String startTimeS, String endTimeS) {
320            List<String> errors = new ArrayList<String>();
321            if (errors.size() == 0 && startTimeS == null) errors.add("The start time is blank.");
322            if (errors.size() == 0 && endTimeS == null) errors.add("The end time is blank.");
323            return errors;
324        }
325    
326        
327    //    public static List<String> validateAvailableLeaveBalance(LeaveSummary ls, String earnCode, String leaveStartDateString, String leaveEndDateString,
328    //              BigDecimal leaveAmount, LeaveBlock updatedLeaveBlock) {
329    //      List<String> errors = new ArrayList<String>();
330    //      CalendarEntries calendarEntries = new CalendarEntries();
331    //      boolean earnCodeChanged = false;
332    //      BigDecimal oldAmount = null;
333    //      if(ls != null && CollectionUtils.isNotEmpty(ls.getLeaveSummaryRows())) {
334    //              if(updatedLeaveBlock != null) {
335    //                      if(!updatedLeaveBlock.getEarnCode().equals(earnCode)) {
336    //                              earnCodeChanged = true;
337    //                      }
338    //                      if(!updatedLeaveBlock.getLeaveAmount().equals(leaveAmount)) {
339    //                              oldAmount = updatedLeaveBlock.getLeaveAmount();
340    //                      }
341    //              }
342    //                      Date startDate = TKUtils.formatDateString(leaveStartDateString);
343    //                      Date endDate = TKUtils.formatDateString(leaveEndDateString);
344    //                      long daysSpan = TKUtils.getDaysBetween(startDate,endDate);
345    //              EarnCode earnCodeObj = TkServiceLocator.getEarnCodeService().getEarnCode(earnCode, endDate);
346    //              if(earnCodeObj != null && earnCodeObj.getAllowNegativeAccrualBalance().equals("N")) {
347    //                      AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCodeObj.getAccrualCategory(), endDate);
348    //                      if(accrualCategory != null) {
349    //                              LeaveSummaryRow validationRow = ls.getLeaveSummaryRowForAccrualCategory(accrualCategory.getLmAccrualCategoryId());
350    //                              if(ObjectUtils.isNotNull(validationRow)) {
351    //                                      BigDecimal availableBalance = validationRow.getLeaveBalance();
352    //                                      LeaveSummary ytdSummary = TkServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDateForAccrualCategory(TKContext.getTargetPrincipalId(), startDate, accrualCategory.getAccrualCategory());
353    //                                      if(ytdSummary != null) {
354    //                                              LeaveSummaryRow ytdSummaryRow = ytdSummary.getLeaveSummaryRowForAccrualCategory(accrualCategory.getLmAccrualCategoryId());
355    //                                              if(ytdSummaryRow != null)
356    //                                                      availableBalance = ytdSummaryRow.getLeaveBalance();
357    //                                      }
358    //
359    //                                      if(oldAmount!=null) {
360    //
361    //                                              if(!earnCodeChanged ||
362    //                                                              updatedLeaveBlock.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
363    //                                                              availableBalance = availableBalance.add(oldAmount.abs());
364    //                                              }
365    //
366    //                                              }
367    //                                              //multiply by days in span in case the user has also edited the start/end dates.
368    //                                      BigDecimal desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan+1));
369    //
370    //                                      if(desiredUsage.compareTo(availableBalance) >  0 ) {
371    //                                              errors.add("Requested leave amount is greater than available leave balance.");      //errorMessages
372    //                                      }
373    //                              }
374    //                      }
375    //              }
376    //      }
377    //      
378    //      return errors;
379    //    }
380        
381    
382        // KPME-2010
383        public static List<String> validateSpanningWeeks(LeaveCalendarWSForm lcf) {
384            List<String> errors = new ArrayList<String>();
385            
386            boolean spanningWeeks = lcf.getSpanningWeeks().equalsIgnoreCase("y");
387            
388            if (!spanningWeeks) {
389                    Date startDate = TKUtils.formatDateString(lcf.getStartDate());
390                    EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(lcf.getSelectedEarnCode(), startDate);
391                    DateTime startTemp, endTemp;
392            
393                    if (ec != null && !ec.getRecordMethod().equals(LMConstants.RECORD_METHOD.TIME)) {
394                        startTemp = new DateTime(startDate);
395                        endTemp = new DateTime(TKUtils.formatDateString(lcf.getEndDate()));
396                    } else {
397                        startTemp = new DateTime(TKUtils.convertDateStringToTimestamp(lcf.getStartDate()).getTime());
398                        endTemp = new DateTime(TKUtils.convertDateStringToTimestamp(lcf.getEndDate()).getTime());
399                    }
400                    
401                    boolean isOnlyWeekendSpan = true;
402                    while ((startTemp.isBefore(endTemp) || startTemp.isEqual(endTemp)) && isOnlyWeekendSpan) {
403                            if (startTemp.getDayOfWeek() != DateTimeConstants.SATURDAY && startTemp.getDayOfWeek() != DateTimeConstants.SUNDAY) {
404                                    isOnlyWeekendSpan = false;
405                            }
406                            startTemp = startTemp.plusDays(1);
407                    }
408                    if (isOnlyWeekendSpan) {
409                            errors.add("Weekend day is selected, but include weekends checkbox is not checked");            //errorMessages
410                    }
411            }
412            
413            return errors;
414        }
415        
416        public static List<String> validateParametersAccordingToSelectedEarnCodeRecordMethod(LeaveCalendarWSForm lcf) {
417            return validateParametersForLeaveEntry(lcf.getSelectedEarnCode(), lcf.getCalendarEntry(), lcf.getStartDate(), lcf.getEndDate(), lcf.getStartTime(), lcf.getEndTime(), lcf.getSelectedAssignment(), lcf.getLeaveCalendarDocument(), lcf.getLeaveBlockId());
418        }
419        
420        public static List<String> validateParametersForLeaveEntry(String selectedEarnCode, CalendarEntries leaveCalEntry, String startDateS, String endDateS, String startTimeS, String endTimeS, String selectedAssignment, LeaveCalendarDocument leaveCalendarDocument, String leaveBlockId) {
421            
422            java.sql.Date asOfDate = leaveCalEntry.getEndPeriodDate();
423            
424            List<String> errors = new ArrayList<String>();
425            if (StringUtils.isNotBlank(selectedEarnCode)) {
426                    EarnCode  earnCode = TkServiceLocator.getEarnCodeService().getEarnCode(selectedEarnCode, asOfDate);
427                    
428                    if(earnCode != null && earnCode.getRecordMethod().equalsIgnoreCase(TkConstants.EARN_CODE_TIME)) {
429                            
430                            errors.addAll(LeaveCalendarValidationUtil.validateDates(startDateS, endDateS));
431                            errors.addAll(LeaveCalendarValidationUtil.validateTimes(startTimeS, endTimeS));
432                            if (errors.size() > 0) return errors;
433                    
434                            Long startTime;
435                            Long endTime;
436                           
437                            startTime = TKUtils.convertDateStringToTimestampWithoutZone(startDateS, startTimeS).getTime();
438                            endTime = TKUtils.convertDateStringToTimestampWithoutZone(endDateS, endTimeS).getTime();
439                    
440                            errors.addAll(validateInterval(leaveCalEntry, startTime, endTime));
441                            if (errors.size() > 0) return errors;
442                            
443                            if (startTimeS == null) errors.add("The start time is blank.");
444                            if (endTimeS == null) errors.add("The end time is blank.");
445                            if (startTime - endTime == 0) errors.add("Start time and end time cannot be equivalent");
446                            
447                            if (errors.size() > 0) return errors;
448                    
449                            DateTime startTemp = new DateTime(startTime);
450                            DateTime endTemp = new DateTime(endTime);
451                    
452                            if (errors.size() == 0) {
453                                Hours hrs = Hours.hoursBetween(startTemp, endTemp);
454                                if (hrs.getHours() >= 24) errors.add("One leaveblock cannot exceed 24 hours");
455                            }
456                            if (errors.size() > 0) return errors;
457                            
458                            //Check that assignment is valid for both days
459                            AssignmentDescriptionKey assignKey = TkServiceLocator.getAssignmentService().getAssignmentDescriptionKey(selectedAssignment);
460                            Assignment assign = TkServiceLocator.getAssignmentService().getAssignment(assignKey, new Date(startTime));
461                            
462                            if ((startTime.compareTo(endTime) > 0 || endTime.compareTo(startTime) < 0)) {
463                                errors.add("The time or date is not valid.");
464                            }
465                            if (errors.size() > 0) return errors;
466                            
467    //                      boolean isRegularEarnCode = StringUtils.equals(assign.getJob().getPayTypeObj().getRegEarnCode(),selectedEarnCode);
468                            boolean isRegularEarnCode = true;
469                            errors.addAll(validateOverlap(startTime, endTime, startDateS, endTimeS,startTemp, endTemp, leaveCalEntry, leaveBlockId, isRegularEarnCode, earnCode.getRecordMethod()));
470                            if (errors.size() > 0) return errors;
471                    }
472                }
473            return errors;
474        }
475        
476        public static List<String> validateInterval(CalendarEntries payCalEntry, Long startTime, Long endTime) {
477            List<String> errors = new ArrayList<String>();
478            LocalDateTime pcb_ldt = payCalEntry.getBeginLocalDateTime();
479            LocalDateTime pce_ldt = payCalEntry.getEndLocalDateTime();
480            DateTimeZone utz = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
481            DateTime p_cal_b_dt = pcb_ldt.toDateTime(utz);
482            DateTime p_cal_e_dt = pce_ldt.toDateTime(utz);
483    
484            Interval payInterval = new Interval(p_cal_b_dt, p_cal_e_dt);
485            if (errors.size() == 0 && !payInterval.contains(startTime)) {
486                errors.add("The start date/time is outside the pay period");
487            }
488            if (errors.size() == 0 && !payInterval.contains(endTime) && p_cal_e_dt.getMillis() != endTime) {
489                errors.add("The end date/time is outside the pay period");
490            }
491            return errors;
492        }
493        
494        public static List<String> validateOverlap(Long startTime, Long endTime, String startDateS, String endTimeS, DateTime startTemp, DateTime endTemp, CalendarEntries calendarEntry, String lmLeaveBlockId, boolean isRegularEarnCode, String earnCodeType) {
495            List<String> errors = new ArrayList<String>();
496            Interval addedTimeblockInterval = new Interval(startTime, endTime);
497            List<Interval> dayInt = new ArrayList<Interval>();
498            String viewPrincipal = TKUser.getCurrentTargetPersonId();
499            
500            dayInt.add(addedTimeblockInterval);
501            List<Assignment> assignments = TkServiceLocator.getAssignmentService().getAssignmentsByCalEntryForLeaveCalendar(viewPrincipal, calendarEntry);
502                    List<String> assignmentKeys = new ArrayList<String>();
503            for(Assignment assign : assignments) {
504                    assignmentKeys.add(assign.getAssignmentKey());
505            }
506            
507            List<LeaveBlock> leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksForLeaveCalendar(viewPrincipal, calendarEntry.getBeginPeriodDate(), calendarEntry.getEndPeriodDate(), assignmentKeys);
508            for (LeaveBlock leaveBlock : leaveBlocks) {
509                     if (errors.size() == 0 && StringUtils.equals(earnCodeType, TkConstants.EARN_CODE_TIME) && leaveBlock.getBeginTimestamp() != null && leaveBlock.getEndTimestamp()!= null) {
510                    Interval leaveBlockInterval = new Interval(leaveBlock.getBeginTimestamp().getTime(), leaveBlock.getEndTimestamp().getTime());
511                    for (Interval intv : dayInt) {
512                        if (isRegularEarnCode && leaveBlockInterval.overlaps(intv) && (lmLeaveBlockId == null || lmLeaveBlockId.compareTo(leaveBlock.getLmLeaveBlockId()) != 0)) {
513                            errors.add("The leave block you are trying to add overlaps with an existing time block.");
514                        }
515                    }
516                     }
517            }
518    
519            return errors;
520        }
521    }