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.time.detail.web;
17  
18  import java.math.BigDecimal;
19  import java.sql.Date;
20  import java.sql.Timestamp;
21  import java.text.SimpleDateFormat;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import javax.servlet.http.HttpServletRequest;
31  import javax.servlet.http.HttpServletResponse;
32  
33  import org.apache.commons.lang.StringUtils;
34  import org.apache.struts.action.ActionForm;
35  import org.apache.struts.action.ActionForward;
36  import org.apache.struts.action.ActionMapping;
37  import org.joda.time.DateTime;
38  import org.joda.time.Interval;
39  import org.kuali.hr.lm.LMConstants;
40  import org.kuali.hr.lm.leaveblock.LeaveBlock;
41  import org.kuali.hr.lm.leavecalendar.validation.LeaveCalendarValidationUtil;
42  import org.kuali.hr.lm.util.LeaveBlockAggregate;
43  import org.kuali.hr.time.assignment.Assignment;
44  import org.kuali.hr.time.calendar.Calendar;
45  import org.kuali.hr.time.calendar.CalendarEntries;
46  import org.kuali.hr.time.calendar.TkCalendar;
47  import org.kuali.hr.time.earncode.EarnCode;
48  import org.kuali.hr.time.roles.TkUserRoles;
49  import org.kuali.hr.time.roles.UserRoles;
50  import org.kuali.hr.time.service.base.TkServiceLocator;
51  import org.kuali.hr.time.timeblock.TimeBlock;
52  import org.kuali.hr.time.timeblock.TimeBlockHistory;
53  import org.kuali.hr.time.timesheet.TimesheetDocument;
54  import org.kuali.hr.time.timesheet.web.TimesheetAction;
55  import org.kuali.hr.time.timesheet.web.TimesheetActionForm;
56  import org.kuali.hr.time.timesummary.AssignmentRow;
57  import org.kuali.hr.time.timesummary.EarnCodeSection;
58  import org.kuali.hr.time.timesummary.EarnGroupSection;
59  import org.kuali.hr.time.timesummary.TimeSummary;
60  import org.kuali.hr.time.util.TKContext;
61  import org.kuali.hr.time.util.TKUser;
62  import org.kuali.hr.time.util.TKUtils;
63  import org.kuali.hr.time.util.TkConstants;
64  import org.kuali.hr.time.util.TkTimeBlockAggregate;
65  import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
66  import org.kuali.rice.kew.service.KEWServiceLocator;
67  import org.kuali.rice.krad.exception.AuthorizationException;
68  import org.kuali.rice.krad.util.GlobalVariables;
69  
70  public class TimeDetailAction extends TimesheetAction {
71  
72      @Override
73      protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
74          super.checkTKAuthorization(form, methodToCall); // Checks for read access first.
75          TKUser user = TKContext.getUser();
76          UserRoles roles = TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId());
77          TimesheetDocument doc = TKContext.getCurrentTimesheetDocument();
78  
79          // Check for write access to Timeblock.
80          if (StringUtils.equals(methodToCall, "addTimeBlock") || StringUtils.equals(methodToCall, "deleteTimeBlock") || StringUtils.equals(methodToCall, "updateTimeBlock")) {
81              if (!roles.isDocumentWritable(doc)) {
82                  throw new AuthorizationException(roles.getPrincipalId(), "TimeDetailAction", "");
83              }
84          }
85      }
86  
87      @Override
88      public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
89          ActionForward forward = super.execute(mapping, form, request, response);
90          if (forward.getRedirect()) {
91              return forward;
92          }
93          if (TKContext.getCurrentTimesheetDocument() == null) {
94              return forward;
95          }
96          TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
97          tdaf.setAssignmentDescriptions(TkServiceLocator.getAssignmentService().getAssignmentDescriptions(TKContext.getCurrentTimesheetDocument(), false));
98  
99          // Handle User preference / timezone information (pushed up from TkCalendar to avoid duplication)
100         // Set calendar
101         CalendarEntries payCalendarEntry = tdaf.getPayCalendarDates();
102         Calendar payCalendar = TkServiceLocator.getCalendarService().getCalendar(payCalendarEntry != null ? payCalendarEntry.getHrCalendarId() : null);
103         
104         //List<TimeBlock> timeBlocks = TkServiceLocator.getTimeBlockService().getTimeBlocks(Long.parseLong(tdaf.getTimesheetDocument().getDocumentHeader().getTimesheetDocumentId()));
105         List<TimeBlock> timeBlocks = TKContext.getCurrentTimesheetDocument().getTimeBlocks();
106         // get leave blocks
107         List<Assignment> timeAssignments = TKContext.getCurrentTimesheetDocument().getAssignments();
108         List<String> tAssignmentKeys = new ArrayList<String>();
109         for(Assignment assign : timeAssignments) {
110         	tAssignmentKeys.add(assign.getAssignmentKey());
111         }
112         List<LeaveBlock> leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(TKContext.getCurrentTimesheetDocument().getPrincipalId(), 
113         					payCalendarEntry.getBeginPeriodDate(), payCalendarEntry.getEndPeriodDate(), tAssignmentKeys);
114         List<LeaveBlock> balanceTransferLeaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(TKContext.getCurrentTimesheetDocument().getPrincipalId(),
115         		 payCalendarEntry.getBeginPeriodDate(), payCalendarEntry.getEndPeriodDate(), LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
116 //        List<String> warnings = tdaf.getWarnings();
117         Map<String, Set<String>> allMessages = LeaveCalendarValidationUtil.getWarningMessagesForLeaveBlocks(balanceTransferLeaveBlocks);
118         Map<String, Set<String>> transactionalMessages = LeaveCalendarValidationUtil.validatePendingTransactions(TKContext.getTargetPrincipalId(),
119         		payCalendarEntry.getBeginPeriodDate(), payCalendarEntry.getEndPeriodDate());
120 
121         List<String> infoMessages = tdaf.getInfoMessages();
122         infoMessages.addAll(allMessages.get("infoMessages"));
123         infoMessages.addAll(transactionalMessages.get("infoMessages"));
124 
125         List<String> warningMessages = tdaf.getWarningMessages();
126         warningMessages.addAll(allMessages.get("warningMessages"));
127         warningMessages.addAll(transactionalMessages.get("warningMessages"));
128 
129         List<String> actionMessages = tdaf.getActionMessages();
130         actionMessages.addAll(allMessages.get("actionMessages"));
131         actionMessages.addAll(transactionalMessages.get("actionMessages"));
132 
133         tdaf.setInfoMessages(infoMessages);
134         tdaf.setWarningMessages(warningMessages);
135         tdaf.setActionMessages(actionMessages);
136 
137         this.assignStypeClassMapForTimeSummary(tdaf,timeBlocks, leaveBlocks);
138         
139         List<Interval> intervals = TKUtils.getFullWeekDaySpanForCalendarEntry(payCalendarEntry);
140         LeaveBlockAggregate lbAggregate = new LeaveBlockAggregate(leaveBlocks, payCalendarEntry, intervals);
141         TkTimeBlockAggregate tbAggregate = new TkTimeBlockAggregate(timeBlocks, payCalendarEntry, payCalendar, true,intervals);
142         // use both time aggregate and leave aggregate to populate the calendar
143         TkCalendar cal = TkCalendar.getCalendar(tbAggregate, lbAggregate);
144         cal.assignAssignmentStyle(tdaf.getAssignStyleClassMap());
145         tdaf.setTkCalendar(cal);
146      
147         this.populateCalendarAndPayPeriodLists(request, tdaf);
148 
149         tdaf.setTimeBlockString(ActionFormUtils.getTimeBlocksJson(tbAggregate.getFlattenedTimeBlockList()));
150         tdaf.setLeaveBlockString(ActionFormUtils.getLeaveBlocksJson(lbAggregate.getFlattenedLeaveBlockList()));
151 
152         tdaf.setOvertimeEarnCodes(TkServiceLocator.getEarnCodeService().getOvertimeEarnCodesStrs(TKContext.getCurrentTimesheetDocument().getAsOfDate()));
153 
154         if (StringUtils.equals(TKContext.getCurrentTimesheetDocument().getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())) {
155         	tdaf.setWorkingOnItsOwn("true");
156         }
157         
158         tdaf.setDocEditable("false");
159         if (TKContext.getUser().isSystemAdmin()) {
160             tdaf.setDocEditable("true");
161         } else {
162             boolean docFinal = TKContext.getCurrentTimesheetDocument().getDocumentHeader().getDocumentStatus().equals(TkConstants.ROUTE_STATUS.FINAL);
163             if (!docFinal) {
164             	if(StringUtils.equals(TKContext.getCurrentTimesheetDocument().getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())
165 	            		|| TKContext.getUser().isSystemAdmin() 
166 	            		|| TKContext.getUser().isLocationAdmin() 
167 	            		|| TKContext.getUser().isDepartmentAdmin() 
168 	            		|| TKContext.getUser().isReviewer() 
169 	            		|| TKContext.getUser().isApprover()) {
170                     tdaf.setDocEditable("true");
171                 }
172             	
173 	            //if the timesheet has been approved by at least one of the approvers, the employee should not be able to edit it
174 	            if (StringUtils.equals(TKContext.getCurrentTimesheetDocument().getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())
175 	            		&& TKContext.getCurrentTimesheetDocument().getDocumentHeader().getDocumentStatus().equals(TkConstants.ROUTE_STATUS.ENROUTE)) {
176 		        	Collection actions = KEWServiceLocator.getActionTakenService().findByDocIdAndAction(TKContext.getCurrentTimesheetDocument().getDocumentHeader().getDocumentId(), TkConstants.DOCUMENT_ACTIONS.APPROVE);
177 	        		if(!actions.isEmpty()) {
178 	        			tdaf.setDocEditable("false");  
179 	        		}
180 		        }
181             }
182         }
183 
184         return forward;
185     }
186 
187     // use lists of time blocks and leave blocks to build the style class map and assign css class to associated summary rows
188 	private void assignStypeClassMapForTimeSummary(TimeDetailActionForm tdaf, List<TimeBlock> timeBlocks, List<LeaveBlock> leaveBlocks) throws Exception {
189 		TimeSummary ts = TkServiceLocator.getTimeSummaryService().getTimeSummary(TKContext.getCurrentTimesheetDocument());
190         tdaf.setAssignStyleClassMap(ActionFormUtils.buildAssignmentStyleClassMap(timeBlocks, leaveBlocks));
191         Map<String, String> aMap = tdaf.getAssignStyleClassMap();
192         // set css classes for each assignment row
193         for (EarnGroupSection earnGroupSection : ts.getSections()) {
194             for (EarnCodeSection section : earnGroupSection.getEarnCodeSections()) {
195                 for (AssignmentRow assignRow : section.getAssignmentsRows()) {
196                     if (assignRow.getAssignmentKey() != null && aMap.containsKey(assignRow.getAssignmentKey())) {
197                         assignRow.setCssClass(aMap.get(assignRow.getAssignmentKey()));
198                     } else {
199                         assignRow.setCssClass("");
200                     }
201                 }
202             }
203 
204         }
205         tdaf.setTimeSummary(ts);
206         ActionFormUtils.validateHourLimit(tdaf);
207         ActionFormUtils.addWarningTextFromEarnGroup(tdaf);
208         ActionFormUtils.addUnapprovedIPWarningFromClockLog(tdaf);
209 	}
210 
211 	private void populateCalendarAndPayPeriodLists(HttpServletRequest request, TimeDetailActionForm tdaf) {
212 		List<TimesheetDocumentHeader> documentHeaders = (List<TimesheetDocumentHeader>) TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeadersForPrincipalId(TKContext.getTargetPrincipalId());
213         SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
214         if(tdaf.getCalendarYears().isEmpty()) {
215         	// get calendar year drop down list contents
216 	        Set<String> yearSet = new HashSet<String>();
217 	        
218 	        for(TimesheetDocumentHeader tdh : documentHeaders) {
219 	        	yearSet.add(sdf.format(tdh.getBeginDate()));
220 	        }
221 	        List<String> yearList = new ArrayList<String>(yearSet);
222 	        Collections.sort(yearList);
223 	        Collections.reverse(yearList);	// newest on top
224 	        tdaf.setCalendarYears(yearList);
225         }
226         // if selected calendar year is passed in
227         if(request.getParameter("selectedCY")!= null) {
228         	tdaf.setSelectedCalendarYear(request.getParameter("selectedCY").toString());
229         }
230         // if there is no selected calendr year, use the year of current pay calendar entry
231         if(StringUtils.isEmpty(tdaf.getSelectedCalendarYear())) {
232         	tdaf.setSelectedCalendarYear(sdf.format(tdaf.getPayCalendarDates().getBeginPeriodDate()));
233         }
234         if(tdaf.getPayPeriodsMap().isEmpty()) {
235 	        List<CalendarEntries> payPeriodList = new ArrayList<CalendarEntries>();
236 	        for(TimesheetDocumentHeader tdh : documentHeaders) {
237 	        	if(sdf.format(tdh.getBeginDate()).equals(tdaf.getSelectedCalendarYear())) {
238                     CalendarEntries pe = TkServiceLocator.getCalendarEntriesService().getCalendarEntriesByBeginAndEndDate(tdh.getBeginDate(), tdh.getEndDate());
239 	        		payPeriodList.add(pe);
240 	        	}
241 	        }
242 	        tdaf.setPayPeriodsMap(ActionFormUtils.getPayPeriodsMap(payPeriodList));
243         }
244         if(request.getParameter("selectedPP")!= null) {
245         	tdaf.setSelectedPayPeriod(request.getParameter("selectedPP").toString());
246         }
247         if(StringUtils.isEmpty(tdaf.getSelectedPayPeriod())) {
248         	tdaf.setSelectedPayPeriod(tdaf.getPayCalendarDates().getHrCalendarEntriesId());
249         }
250 	}
251 
252 
253     /**
254      * This method involves creating an object-copy of every TimeBlock on the
255      * time sheet for overtime re-calculation.
256      *
257      * @throws Exception
258      */
259     public ActionForward deleteTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
260         TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
261         //Grab timeblock to be deleted from form
262         List<TimeBlock> timeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
263         TimeBlock deletedTimeBlock = null;
264         for (TimeBlock tb : timeBlocks) {
265             if (tb.getTkTimeBlockId().compareTo(tdaf.getTkTimeBlockId()) == 0) {
266                 deletedTimeBlock = tb;
267                 break;
268             }
269         }
270         if (deletedTimeBlock == null) {
271             return mapping.findForward("basic");
272         }
273         //Remove from the list of timeblocks
274         List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(tdaf.getTimesheetDocument().getTimeBlocks().size());
275         for (TimeBlock b : tdaf.getTimesheetDocument().getTimeBlocks()) {
276             referenceTimeBlocks.add(b.copy());
277         }
278 
279         // simple pointer, for clarity
280         List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
281         newTimeBlocks.remove(deletedTimeBlock);
282 
283         //Delete timeblock
284         TkServiceLocator.getTimeBlockService().deleteTimeBlock(deletedTimeBlock);
285         // Add a row to the history table
286         TimeBlockHistory tbh = new TimeBlockHistory(deletedTimeBlock);
287         tbh.setActionHistory(TkConstants.ACTIONS.DELETE_TIME_BLOCK);
288         TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
289         //reset time block
290         TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks);
291         TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, tdaf.getPayCalendarDates(), tdaf.getTimesheetDocument(), TKContext.getPrincipalId());
292         TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, TKContext.getPrincipalId());
293 
294         return mapping.findForward("basic");
295     }
296 
297     /**
298      * This method involves creating an object-copy of every TimeBlock on the
299      * time sheet for overtime re-calculation.
300      * Based on the form's timeBlockId or leaveBlockId, existing Time/Leave blocks will be deleted and new ones created
301      *
302      * @throws Exception
303      */
304     public ActionForward addTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
305         TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
306         
307         if(StringUtils.isNotEmpty(tdaf.getTkTimeBlockId())) {
308         	// the user is changing an existing time block, so need to delete this time block
309         	this.removeOldTimeBlock(tdaf);
310         } else if(StringUtils.isNotEmpty(tdaf.getLmLeaveBlockId())) {
311         	// the user is changing an existing leave block, so need to delete this leave block
312         	this.removeOldLeaveBlock(tdaf.getLmLeaveBlockId());
313         }
314         if(StringUtils.isNotEmpty(tdaf.getSelectedEarnCode())) {
315         	EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(tdaf.getSelectedEarnCode(), tdaf.getTimesheetDocument().getAsOfDate());
316         	if(ec != null && (ec.getLeavePlan() != null || ec.getEligibleForAccrual().equals("N"))) {	// leave blocks changes
317         		this.changeLeaveBlocks(tdaf);
318         	} else {	// time blocks changes
319         		this.changeTimeBlocks(tdaf);
320         	}
321         }
322         
323         ActionFormUtils.validateHourLimit(tdaf);
324         ActionFormUtils.addWarningTextFromEarnGroup(tdaf);
325 
326         return mapping.findForward("basic");
327     }
328     
329     private void removeOldTimeBlock(TimeDetailActionForm tdaf) {
330 	  if (tdaf.getTkTimeBlockId() != null) {
331 	      TimeBlock tb = TkServiceLocator.getTimeBlockService().getTimeBlock(tdaf.getTkTimeBlockId());
332 	      if (tb != null) {
333 	          TimeBlockHistory tbh = new TimeBlockHistory(tb);
334 	          TkServiceLocator.getTimeBlockService().deleteTimeBlock(tb);
335 	
336 	          // mark the original timeblock as deleted in the history table
337 			  tbh.setActionHistory(TkConstants.ACTIONS.DELETE_TIME_BLOCK);
338 			  TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
339 	
340 			  // delete the timeblock from the memory
341 	          tdaf.getTimesheetDocument().getTimeBlocks().remove(tb);
342 	      }
343 	  }
344     }
345     
346     private void removeOldLeaveBlock(String lbId) {
347   	  if (lbId != null) {
348   	      LeaveBlock lb = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lbId);
349   	      if (lb != null) {
350   	          TkServiceLocator.getLeaveBlockService().deleteLeaveBlock(lbId, TKContext.getPrincipalId());
351   	      }
352   	  }
353     }
354     
355     // add/update leave blocks 
356 	private void changeLeaveBlocks(TimeDetailActionForm tdaf) {
357 		DateTime beginDate = new DateTime(TKUtils.convertDateStringToTimestamp(tdaf.getStartDate()));
358 		DateTime endDate = new DateTime(TKUtils.convertDateStringToTimestamp(tdaf.getEndDate()));
359 		String selectedEarnCode = tdaf.getSelectedEarnCode();
360 		BigDecimal leaveAmount = tdaf.getLeaveAmount();
361 		
362 		String desc = "";	// there's no description field in time calendar pop window
363 		String spanningWeeks = tdaf.getSpanningWeeks();
364 		Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(tdaf.getTimesheetDocument(), tdaf.getSelectedAssignment());
365 		TkServiceLocator.getLeaveBlockService().addLeaveBlocks(beginDate, endDate, tdaf.getPayCalendarDates(), selectedEarnCode, leaveAmount, desc, assignment, 
366 				spanningWeeks, LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR, TKContext.getTargetPrincipalId());
367 	}
368 	
369     // add/update time blocks
370 	private void changeTimeBlocks(TimeDetailActionForm tdaf) {
371 		Timestamp overtimeBeginTimestamp = null;
372         Timestamp overtimeEndTimestamp = null;
373         boolean isClockLogCreated = false;
374         
375         // This is for updating a timeblock or changing
376         // If tkTimeBlockId is not null and the new timeblock is valid, delete the existing timeblock and a new one will be created after submitting the form.
377         if (tdaf.getTkTimeBlockId() != null) {
378             TimeBlock tb = TkServiceLocator.getTimeBlockService().getTimeBlock(tdaf.getTkTimeBlockId());
379             if (tb != null) {
380 	            isClockLogCreated = tb.getClockLogCreated();
381 	            if (StringUtils.isNotEmpty(tdaf.getOvertimePref())) {
382 	                overtimeBeginTimestamp = tb.getBeginTimestamp();
383 	                overtimeEndTimestamp = tb.getEndTimestamp();
384 	            }
385             }
386             // old time block is deleted from addTimeBlock method
387             // this.removeOldTimeBlock(tdaf);
388         }
389 
390         Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(tdaf.getTimesheetDocument(), tdaf.getSelectedAssignment());
391 
392 
393         // Surgery point - Need to construct a Date/Time with Appropriate Timezone.
394         Timestamp startTime = TKUtils.convertDateStringToTimestamp(tdaf.getStartDate(), tdaf.getStartTime());
395         Timestamp endTime = TKUtils.convertDateStringToTimestamp(tdaf.getEndDate(), tdaf.getEndTime());
396 
397         // We need a  cloned reference set so we know whether or not to
398         // persist any potential changes without making hundreds of DB calls.
399         List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(tdaf.getTimesheetDocument().getTimeBlocks().size());
400         for (TimeBlock tb : tdaf.getTimesheetDocument().getTimeBlocks()) {
401             referenceTimeBlocks.add(tb.copy());
402         }
403 
404         // This is just a reference, for code clarity, the above list is actually
405         // separate at the object level.
406         List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
407         DateTime startTemp = new DateTime(startTime);
408         DateTime endTemp = new DateTime(endTime);
409         // KPME-1446 add spanningweeks to the calls below 
410         if (StringUtils.equals(tdaf.getAcrossDays(), "y")
411                 && !(endTemp.getDayOfYear() - startTemp.getDayOfYear() <= 1
412                 && endTemp.getHourOfDay() == 0)) {
413             List<TimeBlock> timeBlocksToAdd = TkServiceLocator.getTimeBlockService().buildTimeBlocksSpanDates(assignment,
414                     tdaf.getSelectedEarnCode(), tdaf.getTimesheetDocument(), startTime,
415                     endTime, tdaf.getHours(), tdaf.getAmount(), isClockLogCreated, Boolean.parseBoolean(tdaf.getLunchDeleted()), tdaf.getSpanningWeeks(), TKContext.getPrincipalId());
416             for (TimeBlock tb : timeBlocksToAdd) {
417                 if (!newTimeBlocks.contains(tb)) {
418                     newTimeBlocks.add(tb);
419                 }
420             }
421         } else {
422             List<TimeBlock> timeBlocksToAdd = TkServiceLocator.getTimeBlockService().buildTimeBlocks(assignment,
423                     tdaf.getSelectedEarnCode(), tdaf.getTimesheetDocument(), startTime,
424                     endTime, tdaf.getHours(), tdaf.getAmount(), isClockLogCreated, Boolean.parseBoolean(tdaf.getLunchDeleted()), TKContext.getPrincipalId());
425             for (TimeBlock tb : timeBlocksToAdd) {
426                 if (!newTimeBlocks.contains(tb)) {
427                     newTimeBlocks.add(tb);
428                 }
429             }
430         }
431 
432         //reset time block
433         TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks);
434 
435         // apply overtime pref
436         // I changed start and end times comparison below. it used to be overtimeBeginTimestamp and overtimeEndTimestamp but
437         // for some reason, they're always null because, we have removed the time block before getting here. KPME-2162
438         for (TimeBlock tb : newTimeBlocks) {
439             if (tb.getBeginTimestamp().equals(startTime) && tb.getEndTimestamp().equals(endTime) && StringUtils.isNotEmpty(tdaf.getOvertimePref())) {
440                 tb.setOvertimePref(tdaf.getOvertimePref());
441             }
442 
443         }
444 
445         TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, tdaf.getPayCalendarDates(), tdaf.getTimesheetDocument(), TKContext.getPrincipalId());
446         TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, TKContext.getPrincipalId());
447 	}
448 
449     public ActionForward updateTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
450 
451         TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
452         Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(tdaf.getTimesheetDocument(), tdaf.getSelectedAssignment());
453 
454         //Grab timeblock to be updated from form
455         List<TimeBlock> timeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
456         TimeBlock updatedTimeBlock = null;
457         for (TimeBlock tb : timeBlocks) {
458             if (tb.getTkTimeBlockId().compareTo(tdaf.getTkTimeBlockId()) == 0) {
459                 updatedTimeBlock = tb;
460                 tb.setJobNumber(assignment.getJobNumber());
461                 tb.setWorkArea(assignment.getWorkArea());
462                 tb.setTask(assignment.getTask());
463                 break;
464             }
465         }
466 
467         TkServiceLocator.getTimeBlockService().updateTimeBlock(updatedTimeBlock);
468 
469         TimeBlockHistory tbh = new TimeBlockHistory(updatedTimeBlock);
470         tbh.setActionHistory(TkConstants.ACTIONS.UPDATE_TIME_BLOCK);
471         TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
472         tdaf.setMethodToCall("addTimeBlock");
473         return mapping.findForward("basic");
474     }
475 
476 
477     public ActionForward actualTimeInquiry(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
478         TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
479         return mapping.findForward("ati");
480     }
481 
482     public ActionForward deleteLunchDeduction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
483 
484         TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
485         String timeHourDetailId = tdaf.getTkTimeHourDetailId();
486         TkServiceLocator.getTimeBlockService().deleteLunchDeduction(timeHourDetailId);
487 
488         List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
489         
490         TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks);
491         
492         // KPME-1340
493         TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, tdaf.getPayCalendarDates(), tdaf.getTimesheetDocument(), TKContext.getPrincipalId());
494         TkServiceLocator.getTimeBlockService().saveTimeBlocks(newTimeBlocks);
495         TKContext.getCurrentTimesheetDocument().setTimeBlocks(newTimeBlocks);
496         
497         return mapping.findForward("basic");
498     }
499       
500   public ActionForward gotoCurrentPayPeriod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
501 	  String viewPrincipal = TKUser.getCurrentTargetPerson().getPrincipalId();
502 	  Date currentDate = TKUtils.getTimelessDate(null);
503       CalendarEntries pce = TkServiceLocator.getCalendarService().getCurrentCalendarDates(viewPrincipal, currentDate);
504       TimesheetDocument td = TkServiceLocator.getTimesheetService().openTimesheetDocument(viewPrincipal, pce);
505       setupDocumentOnFormContext((TimesheetActionForm)form, td);
506 	  return mapping.findForward("basic");
507   }
508   
509   //Triggered by changes of pay period drop down list, reload the whole page based on the selected pay period
510   public ActionForward changeCalendarYear(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
511 	  
512 	  TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
513 	  if(request.getParameter("selectedCY") != null) {
514 		  tdaf.setSelectedCalendarYear(request.getParameter("selectedCY").toString());
515 	  }
516 	  return mapping.findForward("basic");
517   }
518   
519   //Triggered by changes of pay period drop down list, reload the whole page based on the selected pay period
520   public ActionForward changePayPeriod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
521 	  TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
522 	  if(request.getParameter("selectedPP") != null) {
523 		  tdaf.setSelectedPayPeriod(request.getParameter("selectedPP").toString());
524           CalendarEntries pce = TkServiceLocator.getCalendarEntriesService()
525 		  	.getCalendarEntries(request.getParameter("selectedPP").toString());
526 		  if(pce != null) {
527 			  String viewPrincipal = TKUser.getCurrentTargetPerson().getPrincipalId();
528 			  TimesheetDocument td = TkServiceLocator.getTimesheetService().openTimesheetDocument(viewPrincipal, pce);
529 			  setupDocumentOnFormContext((TimesheetActionForm)form, td);
530 		  }
531 	  }
532 	  return mapping.findForward("basic");
533   }
534   
535   public ActionForward deleteLeaveBlock(ActionMapping mapping,ActionForm form, HttpServletRequest request,
536 			HttpServletResponse response) throws Exception {
537 	  TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
538 	  String leaveBlockId = tdaf.getLmLeaveBlockId();
539 
540       LeaveBlock blockToDelete = TkServiceLocator.getLeaveBlockService().getLeaveBlock(leaveBlockId);
541       if (blockToDelete != null && TkServiceLocator.getPermissionsService().canDeleteLeaveBlock(blockToDelete)) {
542 		    TkServiceLocator.getLeaveBlockService().deleteLeaveBlock(leaveBlockId, TKContext.getPrincipalId());
543       }
544       
545       // if the leave block is NOT eligible for accrual, rerun accrual service for the leave calendar the leave block is on
546       EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(blockToDelete.getEarnCode(), blockToDelete.getLeaveDate());
547       if(ec != null && ec.getEligibleForAccrual().equals("N")) {
548     	  CalendarEntries ce = TkServiceLocator.getCalendarService()
549 					.getCurrentCalendarDatesForLeaveCalendar(blockToDelete.getPrincipalId(), blockToDelete.getLeaveDate());
550     	  if(ce != null) {
551     		  TkServiceLocator.getLeaveAccrualService().runAccrual(blockToDelete.getPrincipalId(), ce.getBeginPeriodDate(), ce.getEndPeriodDate(), false);
552     	  }
553       }
554 		
555       return mapping.findForward("basic");
556 	}
557 
558 }