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.sql.Date;
019    import java.sql.Timestamp;
020    import java.text.SimpleDateFormat;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.Collections;
024    import java.util.HashSet;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Set;
028    
029    import javax.servlet.http.HttpServletRequest;
030    import javax.servlet.http.HttpServletResponse;
031    
032    import org.apache.commons.lang.StringUtils;
033    import org.apache.struts.action.ActionForm;
034    import org.apache.struts.action.ActionForward;
035    import org.apache.struts.action.ActionMapping;
036    import org.joda.time.DateTime;
037    import org.joda.time.Interval;
038    import org.kuali.hr.time.assignment.Assignment;
039    import org.kuali.hr.time.calendar.Calendar;
040    import org.kuali.hr.time.calendar.CalendarEntries;
041    import org.kuali.hr.time.calendar.TkCalendar;
042    import org.kuali.hr.time.roles.TkUserRoles;
043    import org.kuali.hr.time.roles.UserRoles;
044    import org.kuali.hr.time.service.base.TkServiceLocator;
045    import org.kuali.hr.time.timeblock.TimeBlock;
046    import org.kuali.hr.time.timeblock.TimeBlockHistory;
047    import org.kuali.hr.time.timesheet.TimesheetDocument;
048    import org.kuali.hr.time.timesheet.web.TimesheetAction;
049    import org.kuali.hr.time.timesheet.web.TimesheetActionForm;
050    import org.kuali.hr.time.timesummary.AssignmentRow;
051    import org.kuali.hr.time.timesummary.EarnCodeSection;
052    import org.kuali.hr.time.timesummary.EarnGroupSection;
053    import org.kuali.hr.time.timesummary.TimeSummary;
054    import org.kuali.hr.time.util.TKContext;
055    import org.kuali.hr.time.util.TKUser;
056    import org.kuali.hr.time.util.TKUtils;
057    import org.kuali.hr.time.util.TkConstants;
058    import org.kuali.hr.time.util.TkTimeBlockAggregate;
059    import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
060    import org.kuali.rice.kew.service.KEWServiceLocator;
061    import org.kuali.rice.krad.exception.AuthorizationException;
062    import org.kuali.rice.krad.util.GlobalVariables;
063    
064    public class TimeDetailAction extends TimesheetAction {
065    
066        @Override
067        protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
068            super.checkTKAuthorization(form, methodToCall); // Checks for read access first.
069            TKUser user = TKContext.getUser();
070            UserRoles roles = TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId());
071            TimesheetDocument doc = TKContext.getCurrentTimesheetDocument();
072    
073            // Check for write access to Timeblock.
074            if (StringUtils.equals(methodToCall, "addTimeBlock") || StringUtils.equals(methodToCall, "deleteTimeBlock") || StringUtils.equals(methodToCall, "updateTimeBlock")) {
075                if (!roles.isDocumentWritable(doc)) {
076                    throw new AuthorizationException(roles.getPrincipalId(), "TimeDetailAction", "");
077                }
078            }
079        }
080    
081        @Override
082        public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
083            ActionForward forward = super.execute(mapping, form, request, response);
084            if (forward.getRedirect()) {
085                return forward;
086            }
087            TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
088            tdaf.setAssignmentDescriptions(TkServiceLocator.getAssignmentService().getAssignmentDescriptions(TKContext.getCurrentTimesheetDocument(), false));
089    
090            // Handle User preference / timezone information (pushed up from TkCalendar to avoid duplication)
091            // Set calendar
092            CalendarEntries payCalendarEntry = tdaf.getPayCalendarDates();
093            Calendar payCalendar = TkServiceLocator.getCalendarService().getCalendar(payCalendarEntry.getHrCalendarId());
094            
095            //List<TimeBlock> timeBlocks = TkServiceLocator.getTimeBlockService().getTimeBlocks(Long.parseLong(tdaf.getTimesheetDocument().getDocumentHeader().getTimesheetDocumentId()));
096            List<TimeBlock> timeBlocks = TKContext.getCurrentTimesheetDocument().getTimeBlocks();
097            
098            this.assignStypeClassMapForTimeSummary(tdaf,timeBlocks);
099            
100            List<Interval> intervals = TKUtils.getFullWeekDaySpanForCalendarEntry(payCalendarEntry);
101            TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(timeBlocks, payCalendarEntry, payCalendar, true, intervals);
102            TkCalendar cal = TkCalendar.getCalendar(aggregate);
103            cal.assignAssignmentStyle(tdaf.getAssignStyleClassMap());
104            tdaf.setTkCalendar(cal);
105         
106            this.populateCalendarAndPayPeriodLists(request, tdaf);
107    
108            tdaf.setTimeBlockString(ActionFormUtils.getTimeBlocksJson(aggregate.getFlattenedTimeBlockList()));
109    
110            tdaf.setOvertimeEarnCodes(TkServiceLocator.getEarnCodeService().getOvertimeEarnCodesStrs(TKContext.getCurrentTimesheetDocument().getAsOfDate()));
111    
112            if (StringUtils.equals(TKContext.getCurrentTimesheetDocument().getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())) {
113                    tdaf.setWorkingOnItsOwn("true");
114            }
115            
116            tdaf.setDocEditable("false");
117            if (TKContext.getUser().isSystemAdmin()) {
118                tdaf.setDocEditable("true");
119            } else {
120                boolean docFinal = TKContext.getCurrentTimesheetDocument().getDocumentHeader().getDocumentStatus().equals(TkConstants.ROUTE_STATUS.FINAL);
121                if (!docFinal) {
122                    if(StringUtils.equals(TKContext.getCurrentTimesheetDocument().getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())
123                                    || TKContext.getUser().isSystemAdmin() 
124                                    || TKContext.getUser().isLocationAdmin() 
125                                    || TKContext.getUser().isDepartmentAdmin() 
126                                    || TKContext.getUser().isReviewer() 
127                                    || TKContext.getUser().isApprover()) {
128                        tdaf.setDocEditable("true");
129                    }
130                    
131                        //if the timesheet has been approved by at least one of the approvers, the employee should not be able to edit it
132                        if (StringUtils.equals(TKContext.getCurrentTimesheetDocument().getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())
133                                    && TKContext.getCurrentTimesheetDocument().getDocumentHeader().getDocumentStatus().equals(TkConstants.ROUTE_STATUS.ENROUTE)) {
134                                    Collection actions = KEWServiceLocator.getActionTakenService().findByDocIdAndAction(TKContext.getCurrentTimesheetDocument().getDocumentHeader().getDocumentId(), TkConstants.DOCUMENT_ACTIONS.APPROVE);
135                                    if(!actions.isEmpty()) {
136                                            tdaf.setDocEditable("false");  
137                                    }
138                            }
139                }
140            }
141    
142            return forward;
143        }
144    
145        // use lists of time blocks and leave blocks to build the style class map and assign css class to associated summary rows
146            private void assignStypeClassMapForTimeSummary(TimeDetailActionForm tdaf, List<TimeBlock> timeBlocks) throws Exception {
147                    TimeSummary ts = TkServiceLocator.getTimeSummaryService().getTimeSummary(TKContext.getCurrentTimesheetDocument());
148            tdaf.setAssignStyleClassMap(ActionFormUtils.buildAssignmentStyleClassMap(timeBlocks));
149            Map<String, String> aMap = tdaf.getAssignStyleClassMap();
150            // set css classes for each assignment row
151            for (EarnGroupSection earnGroupSection : ts.getSections()) {
152                for (EarnCodeSection section : earnGroupSection.getEarnCodeSections()) {
153                    for (AssignmentRow assignRow : section.getAssignmentsRows()) {
154                        if (assignRow.getAssignmentKey() != null && aMap.containsKey(assignRow.getAssignmentKey())) {
155                            assignRow.setCssClass(aMap.get(assignRow.getAssignmentKey()));
156                        } else {
157                            assignRow.setCssClass("");
158                        }
159                    }
160                }
161    
162            }
163            tdaf.setTimeSummary(ts);
164            ActionFormUtils.validateHourLimit(tdaf);
165            ActionFormUtils.addWarningTextFromEarnGroup(tdaf);
166            ActionFormUtils.addUnapprovedIPWarningFromClockLog(tdaf);
167            }
168    
169            private void populateCalendarAndPayPeriodLists(HttpServletRequest request, TimeDetailActionForm tdaf) {
170                    List<TimesheetDocumentHeader> documentHeaders = (List<TimesheetDocumentHeader>) TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeadersForPrincipalId(GlobalVariables.getUserSession().getPrincipalId());
171            SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
172            if(tdaf.getCalendarYears().isEmpty()) {
173                    // get calendar year drop down list contents
174                    Set<String> yearSet = new HashSet<String>();
175                    
176                    for(TimesheetDocumentHeader tdh : documentHeaders) {
177                            yearSet.add(sdf.format(tdh.getPayBeginDate()));
178                    }
179                    List<String> yearList = new ArrayList<String>(yearSet);
180                    Collections.sort(yearList);
181                    Collections.reverse(yearList);  // newest on top
182                    tdaf.setCalendarYears(yearList);
183            }
184            // if selected calendar year is passed in
185            if(request.getParameter("selectedCY")!= null) {
186                    tdaf.setSelectedCalendarYear(request.getParameter("selectedCY").toString());
187            }
188            // if there is no selected calendr year, use the year of current pay calendar entry
189            if(StringUtils.isEmpty(tdaf.getSelectedCalendarYear())) {
190                    tdaf.setSelectedCalendarYear(sdf.format(tdaf.getPayCalendarDates().getBeginPeriodDate()));
191            }
192            if(tdaf.getPayPeriodsMap().isEmpty()) {
193                    List<CalendarEntries> payPeriodList = new ArrayList<CalendarEntries>();
194                    for(TimesheetDocumentHeader tdh : documentHeaders) {
195                            if(sdf.format(tdh.getPayBeginDate()).equals(tdaf.getSelectedCalendarYear())) {
196                        CalendarEntries pe = TkServiceLocator.getCalendarEntriesService().getCalendarEntriesByBeginAndEndDate(tdh.getPayBeginDate(), tdh.getPayEndDate());
197                                    payPeriodList.add(pe);
198                            }
199                    }
200                    tdaf.setPayPeriodsMap(ActionFormUtils.getPayPeriodsMap(payPeriodList));
201            }
202            if(request.getParameter("selectedPP")!= null) {
203                    tdaf.setSelectedPayPeriod(request.getParameter("selectedPP").toString());
204            }
205            if(StringUtils.isEmpty(tdaf.getSelectedPayPeriod())) {
206                    tdaf.setSelectedPayPeriod(tdaf.getPayCalendarDates().getHrCalendarEntriesId());
207            }
208            }
209    
210    
211        /**
212         * This method involves creating an object-copy of every TimeBlock on the
213         * time sheet for overtime re-calculation.
214         *
215         * @throws Exception
216         */
217        public ActionForward deleteTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
218            TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
219            //Grab timeblock to be deleted from form
220            List<TimeBlock> timeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
221            TimeBlock deletedTimeBlock = null;
222            for (TimeBlock tb : timeBlocks) {
223                if (tb.getTkTimeBlockId().compareTo(tdaf.getTkTimeBlockId()) == 0) {
224                    deletedTimeBlock = tb;
225                    break;
226                }
227            }
228            if (deletedTimeBlock == null) {
229                return mapping.findForward("basic");
230            }
231            //Remove from the list of timeblocks
232            List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(tdaf.getTimesheetDocument().getTimeBlocks().size());
233            for (TimeBlock b : tdaf.getTimesheetDocument().getTimeBlocks()) {
234                referenceTimeBlocks.add(b.copy());
235            }
236    
237            // simple pointer, for clarity
238            List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
239            newTimeBlocks.remove(deletedTimeBlock);
240    
241            //Delete timeblock
242            TkServiceLocator.getTimeBlockService().deleteTimeBlock(deletedTimeBlock);
243            // Add a row to the history table
244            TimeBlockHistory tbh = new TimeBlockHistory(deletedTimeBlock);
245            tbh.setActionHistory(TkConstants.ACTIONS.DELETE_TIME_BLOCK);
246            TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
247            //reset time block
248            TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks);
249            TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, tdaf.getPayCalendarDates(), tdaf.getTimesheetDocument(), TKContext.getPrincipalId());
250            TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks);
251    
252            return mapping.findForward("basic");
253        }
254    
255        /**
256         * This method involves creating an object-copy of every TimeBlock on the
257         * time sheet for overtime re-calculation.
258         *
259         * @throws Exception
260         */
261        public ActionForward addTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
262            TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
263                    this.changeTimeBlocks(tdaf);
264            
265            ActionFormUtils.validateHourLimit(tdaf);
266            ActionFormUtils.addWarningTextFromEarnGroup(tdaf);
267    
268            return mapping.findForward("basic");
269        }
270        
271        private void removeOldTimeBlock(TimeDetailActionForm tdaf) {
272              if (tdaf.getTkTimeBlockId() != null) {
273                  TimeBlock tb = TkServiceLocator.getTimeBlockService().getTimeBlock(tdaf.getTkTimeBlockId());
274                  if (tb != null) {
275                      TimeBlockHistory tbh = new TimeBlockHistory(tb);
276                      TkServiceLocator.getTimeBlockService().deleteTimeBlock(tb);
277            
278                      // mark the original timeblock as deleted in the history table
279                              tbh.setActionHistory(TkConstants.ACTIONS.DELETE_TIME_BLOCK);
280                              TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
281            
282                              // delete the timeblock from the memory
283                      tdaf.getTimesheetDocument().getTimeBlocks().remove(tb);
284                  }
285              }
286        }
287        
288        
289        // add/update time blocks 
290            private void changeTimeBlocks(TimeDetailActionForm tdaf) {
291                    Timestamp overtimeBeginTimestamp = null;
292            Timestamp overtimeEndTimestamp = null;
293            boolean isClockLogCreated = false;
294            
295            // This is for updating a timeblock or changing
296            // 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.
297            if (tdaf.getTkTimeBlockId() != null) {
298                TimeBlock tb = TkServiceLocator.getTimeBlockService().getTimeBlock(tdaf.getTkTimeBlockId());
299                if (tb != null) {
300                        isClockLogCreated = tb.getClockLogCreated();
301                        if (StringUtils.isNotEmpty(tdaf.getOvertimePref())) {
302                            overtimeBeginTimestamp = tb.getBeginTimestamp();
303                            overtimeEndTimestamp = tb.getEndTimestamp();
304                        }
305                }
306                this.removeOldTimeBlock(tdaf);
307            }
308    
309            Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(tdaf.getTimesheetDocument(), tdaf.getSelectedAssignment());
310    
311    
312            // Surgery point - Need to construct a Date/Time with Appropriate Timezone.
313            Timestamp startTime = TKUtils.convertDateStringToTimestamp(tdaf.getStartDate(), tdaf.getStartTime());
314            Timestamp endTime = TKUtils.convertDateStringToTimestamp(tdaf.getEndDate(), tdaf.getEndTime());
315    
316            // We need a  cloned reference set so we know whether or not to
317            // persist any potential changes without making hundreds of DB calls.
318            List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(tdaf.getTimesheetDocument().getTimeBlocks().size());
319            for (TimeBlock tb : tdaf.getTimesheetDocument().getTimeBlocks()) {
320                referenceTimeBlocks.add(tb.copy());
321            }
322    
323            // This is just a reference, for code clarity, the above list is actually
324            // separate at the object level.
325            List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
326            DateTime startTemp = new DateTime(startTime);
327            DateTime endTemp = new DateTime(endTime);
328            // KPME-1446 add spanningweeks to the calls below 
329            if (StringUtils.equals(tdaf.getAcrossDays(), "y")
330                    && !(endTemp.getDayOfYear() - startTemp.getDayOfYear() <= 1
331                    && endTemp.getHourOfDay() == 0)) {
332                List<TimeBlock> timeBlocksToAdd = TkServiceLocator.getTimeBlockService().buildTimeBlocksSpanDates(assignment,
333                        tdaf.getSelectedEarnCode(), tdaf.getTimesheetDocument(), startTime,
334                        endTime, tdaf.getHours(), tdaf.getAmount(), isClockLogCreated, Boolean.parseBoolean(tdaf.getLunchDeleted()), tdaf.getSpanningWeeks());
335                for (TimeBlock tb : timeBlocksToAdd) {
336                    if (!newTimeBlocks.contains(tb)) {
337                        newTimeBlocks.add(tb);
338                    }
339                }
340            } else {
341                List<TimeBlock> timeBlocksToAdd = TkServiceLocator.getTimeBlockService().buildTimeBlocks(assignment,
342                        tdaf.getSelectedEarnCode(), tdaf.getTimesheetDocument(), startTime,
343                        endTime, tdaf.getHours(), tdaf.getAmount(), isClockLogCreated, Boolean.parseBoolean(tdaf.getLunchDeleted()));
344                for (TimeBlock tb : timeBlocksToAdd) {
345                    if (!newTimeBlocks.contains(tb)) {
346                        newTimeBlocks.add(tb);
347                    }
348                }
349            }
350    
351            //reset time block
352            TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks);
353    
354            // apply overtime pref
355            for (TimeBlock tb : newTimeBlocks) {
356                if (tb.getBeginTimestamp().equals(overtimeBeginTimestamp) && tb.getEndTimestamp().equals(overtimeEndTimestamp) && StringUtils.isNotEmpty(tdaf.getOvertimePref())) {
357                    tb.setOvertimePref(tdaf.getOvertimePref());
358                }
359    
360            }
361    
362            TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, tdaf.getPayCalendarDates(), tdaf.getTimesheetDocument(), TKContext.getPrincipalId());
363            TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks);
364            }
365    
366        public ActionForward updateTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
367    
368            TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
369            Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(tdaf.getTimesheetDocument(), tdaf.getSelectedAssignment());
370    
371            //Grab timeblock to be updated from form
372            List<TimeBlock> timeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
373            TimeBlock updatedTimeBlock = null;
374            for (TimeBlock tb : timeBlocks) {
375                if (tb.getTkTimeBlockId().compareTo(tdaf.getTkTimeBlockId()) == 0) {
376                    updatedTimeBlock = tb;
377                    tb.setJobNumber(assignment.getJobNumber());
378                    tb.setWorkArea(assignment.getWorkArea());
379                    tb.setTask(assignment.getTask());
380                    break;
381                }
382            }
383    
384            TkServiceLocator.getTimeBlockService().updateTimeBlock(updatedTimeBlock);
385    
386            TimeBlockHistory tbh = new TimeBlockHistory(updatedTimeBlock);
387            tbh.setActionHistory(TkConstants.ACTIONS.UPDATE_TIME_BLOCK);
388            TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
389            tdaf.setMethodToCall("addTimeBlock");
390            return mapping.findForward("basic");
391        }
392    
393    
394        public ActionForward actualTimeInquiry(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
395            TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
396            return mapping.findForward("ati");
397        }
398    
399        public ActionForward deleteLunchDeduction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
400    
401            TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
402            String timeHourDetailId = tdaf.getTkTimeHourDetailId();
403            TkServiceLocator.getTimeBlockService().deleteLunchDeduction(timeHourDetailId);
404    
405            List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
406            
407            TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks);
408            
409            // KPME-1340
410            TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, tdaf.getPayCalendarDates(), tdaf.getTimesheetDocument(), TKContext.getPrincipalId());
411            TkServiceLocator.getTimeBlockService().saveTimeBlocks(newTimeBlocks);
412            TKContext.getCurrentTimesheetDocument().setTimeBlocks(newTimeBlocks);
413            
414            return mapping.findForward("basic");
415        }
416          
417      public ActionForward gotoCurrentPayPeriod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
418              String viewPrincipal = TKUser.getCurrentTargetPerson().getPrincipalId();
419              Date currentDate = TKUtils.getTimelessDate(null);
420          CalendarEntries pce = TkServiceLocator.getCalendarService().getCurrentCalendarDates(viewPrincipal, currentDate);
421          TimesheetDocument td = TkServiceLocator.getTimesheetService().openTimesheetDocument(viewPrincipal, pce);
422          setupDocumentOnFormContext((TimesheetActionForm)form, td);
423              return mapping.findForward("basic");
424      }
425      
426      //Triggered by changes of pay period drop down list, reload the whole page based on the selected pay period
427      public ActionForward changeCalendarYear(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
428              
429              TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
430              if(request.getParameter("selectedCY") != null) {
431                      tdaf.setSelectedCalendarYear(request.getParameter("selectedCY").toString());
432              }
433              return mapping.findForward("basic");
434      }
435      
436      //Triggered by changes of pay period drop down list, reload the whole page based on the selected pay period
437      public ActionForward changePayPeriod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
438              TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
439              if(request.getParameter("selectedPP") != null) {
440                      tdaf.setSelectedPayPeriod(request.getParameter("selectedPP").toString());
441              CalendarEntries pce = TkServiceLocator.getCalendarEntriesService()
442                            .getCalendarEntries(request.getParameter("selectedPP").toString());
443                      if(pce != null) {
444                              String viewPrincipal = TKUser.getCurrentTargetPerson().getPrincipalId();
445                              TimesheetDocument td = TkServiceLocator.getTimesheetService().openTimesheetDocument(viewPrincipal, pce);
446                              setupDocumentOnFormContext((TimesheetActionForm)form, td);
447                      }
448              }
449              return mapping.findForward("basic");
450      }
451    
452    }