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.sql.Date;
19  import java.sql.Timestamp;
20  import java.text.SimpleDateFormat;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import javax.servlet.http.HttpServletRequest;
30  import javax.servlet.http.HttpServletResponse;
31  
32  import org.apache.commons.lang.StringUtils;
33  import org.apache.struts.action.ActionForm;
34  import org.apache.struts.action.ActionForward;
35  import org.apache.struts.action.ActionMapping;
36  import org.joda.time.DateTime;
37  import org.joda.time.Interval;
38  import org.kuali.hr.time.assignment.Assignment;
39  import org.kuali.hr.time.calendar.Calendar;
40  import org.kuali.hr.time.calendar.CalendarEntries;
41  import org.kuali.hr.time.calendar.TkCalendar;
42  import org.kuali.hr.time.roles.TkUserRoles;
43  import org.kuali.hr.time.roles.UserRoles;
44  import org.kuali.hr.time.service.base.TkServiceLocator;
45  import org.kuali.hr.time.timeblock.TimeBlock;
46  import org.kuali.hr.time.timeblock.TimeBlockHistory;
47  import org.kuali.hr.time.timesheet.TimesheetDocument;
48  import org.kuali.hr.time.timesheet.web.TimesheetAction;
49  import org.kuali.hr.time.timesheet.web.TimesheetActionForm;
50  import org.kuali.hr.time.timesummary.AssignmentRow;
51  import org.kuali.hr.time.timesummary.EarnCodeSection;
52  import org.kuali.hr.time.timesummary.EarnGroupSection;
53  import org.kuali.hr.time.timesummary.TimeSummary;
54  import org.kuali.hr.time.util.TKContext;
55  import org.kuali.hr.time.util.TKUser;
56  import org.kuali.hr.time.util.TKUtils;
57  import org.kuali.hr.time.util.TkConstants;
58  import org.kuali.hr.time.util.TkTimeBlockAggregate;
59  import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
60  import org.kuali.rice.kew.service.KEWServiceLocator;
61  import org.kuali.rice.krad.exception.AuthorizationException;
62  import org.kuali.rice.krad.util.GlobalVariables;
63  
64  public class TimeDetailAction extends TimesheetAction {
65  
66      @Override
67      protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
68          super.checkTKAuthorization(form, methodToCall); // Checks for read access first.
69          TKUser user = TKContext.getUser();
70          UserRoles roles = TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId());
71          TimesheetDocument doc = TKContext.getCurrentTimesheetDocument();
72  
73          // Check for write access to Timeblock.
74          if (StringUtils.equals(methodToCall, "addTimeBlock") || StringUtils.equals(methodToCall, "deleteTimeBlock") || StringUtils.equals(methodToCall, "updateTimeBlock")) {
75              if (!roles.isDocumentWritable(doc)) {
76                  throw new AuthorizationException(roles.getPrincipalId(), "TimeDetailAction", "");
77              }
78          }
79      }
80  
81      @Override
82      public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
83          ActionForward forward = super.execute(mapping, form, request, response);
84          if (forward.getRedirect()) {
85              return forward;
86          }
87          TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
88          tdaf.setAssignmentDescriptions(TkServiceLocator.getAssignmentService().getAssignmentDescriptions(TKContext.getCurrentTimesheetDocument(), false));
89  
90          // Handle User preference / timezone information (pushed up from TkCalendar to avoid duplication)
91          // Set calendar
92          CalendarEntries payCalendarEntry = tdaf.getPayCalendarDates();
93          Calendar payCalendar = TkServiceLocator.getCalendarService().getCalendar(payCalendarEntry.getHrCalendarId());
94          
95          //List<TimeBlock> timeBlocks = TkServiceLocator.getTimeBlockService().getTimeBlocks(Long.parseLong(tdaf.getTimesheetDocument().getDocumentHeader().getTimesheetDocumentId()));
96          List<TimeBlock> timeBlocks = TKContext.getCurrentTimesheetDocument().getTimeBlocks();
97          
98          this.assignStypeClassMapForTimeSummary(tdaf,timeBlocks);
99          
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 }