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.time.detail.web;
017    
018    import java.math.BigDecimal;
019    import java.sql.Date;
020    import java.sql.Timestamp;
021    import java.text.SimpleDateFormat;
022    import java.util.ArrayList;
023    import java.util.Collection;
024    import java.util.Collections;
025    import java.util.HashSet;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Set;
029    
030    import javax.servlet.http.HttpServletRequest;
031    import javax.servlet.http.HttpServletResponse;
032    
033    import org.apache.commons.lang.StringUtils;
034    import org.apache.struts.action.ActionForm;
035    import org.apache.struts.action.ActionForward;
036    import org.apache.struts.action.ActionMapping;
037    import org.joda.time.DateTime;
038    import org.joda.time.Interval;
039    import org.kuali.hr.lm.LMConstants;
040    import org.kuali.hr.lm.leaveblock.LeaveBlock;
041    import org.kuali.hr.lm.leavecalendar.validation.LeaveCalendarValidationUtil;
042    import org.kuali.hr.lm.util.LeaveBlockAggregate;
043    import org.kuali.hr.time.assignment.Assignment;
044    import org.kuali.hr.time.calendar.Calendar;
045    import org.kuali.hr.time.calendar.CalendarEntries;
046    import org.kuali.hr.time.calendar.TkCalendar;
047    import org.kuali.hr.time.earncode.EarnCode;
048    import org.kuali.hr.time.roles.TkUserRoles;
049    import org.kuali.hr.time.roles.UserRoles;
050    import org.kuali.hr.time.service.base.TkServiceLocator;
051    import org.kuali.hr.time.timeblock.TimeBlock;
052    import org.kuali.hr.time.timeblock.TimeBlockHistory;
053    import org.kuali.hr.time.timesheet.TimesheetDocument;
054    import org.kuali.hr.time.timesheet.web.TimesheetAction;
055    import org.kuali.hr.time.timesheet.web.TimesheetActionForm;
056    import org.kuali.hr.time.timesummary.AssignmentRow;
057    import org.kuali.hr.time.timesummary.EarnCodeSection;
058    import org.kuali.hr.time.timesummary.EarnGroupSection;
059    import org.kuali.hr.time.timesummary.TimeSummary;
060    import org.kuali.hr.time.util.TKContext;
061    import org.kuali.hr.time.util.TKUser;
062    import org.kuali.hr.time.util.TKUtils;
063    import org.kuali.hr.time.util.TkConstants;
064    import org.kuali.hr.time.util.TkTimeBlockAggregate;
065    import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
066    import org.kuali.rice.kew.service.KEWServiceLocator;
067    import org.kuali.rice.krad.exception.AuthorizationException;
068    import org.kuali.rice.krad.util.GlobalVariables;
069    
070    public class TimeDetailAction extends TimesheetAction {
071    
072        @Override
073        protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
074            super.checkTKAuthorization(form, methodToCall); // Checks for read access first.
075            TKUser user = TKContext.getUser();
076            UserRoles roles = TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId());
077            TimesheetDocument doc = TKContext.getCurrentTimesheetDocument();
078    
079            // Check for write access to Timeblock.
080            if (StringUtils.equals(methodToCall, "addTimeBlock") || StringUtils.equals(methodToCall, "deleteTimeBlock") || StringUtils.equals(methodToCall, "updateTimeBlock")) {
081                if (!roles.isDocumentWritable(doc)) {
082                    throw new AuthorizationException(roles.getPrincipalId(), "TimeDetailAction", "");
083                }
084            }
085        }
086    
087        @Override
088        public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
089            ActionForward forward = super.execute(mapping, form, request, response);
090            if (forward.getRedirect()) {
091                return forward;
092            }
093            if (TKContext.getCurrentTimesheetDocument() == null) {
094                return forward;
095            }
096            TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
097            tdaf.setAssignmentDescriptions(TkServiceLocator.getAssignmentService().getAssignmentDescriptions(TKContext.getCurrentTimesheetDocument(), false));
098    
099            // 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    }