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.timesheet.service;
17  
18  import java.math.BigDecimal;
19  import java.sql.Timestamp;
20  import java.util.ArrayList;
21  import java.util.Date;
22  import java.util.LinkedList;
23  import java.util.List;
24  
25  import org.apache.commons.lang.StringUtils;
26  import org.apache.log4j.Logger;
27  import org.kuali.hr.job.Job;
28  import org.kuali.hr.time.assignment.Assignment;
29  import org.kuali.hr.time.calendar.CalendarEntries;
30  import org.kuali.hr.time.holidaycalendar.HolidayCalendar;
31  import org.kuali.hr.time.holidaycalendar.HolidayCalendarDateEntry;
32  import org.kuali.hr.time.principal.PrincipalHRAttributes;
33  import org.kuali.hr.time.service.base.TkServiceLocator;
34  import org.kuali.hr.time.timeblock.TimeBlock;
35  import org.kuali.hr.time.timesheet.TimesheetDocument;
36  import org.kuali.hr.time.util.TKContext;
37  import org.kuali.hr.time.util.TKUser;
38  import org.kuali.hr.time.util.TKUtils;
39  import org.kuali.hr.time.util.TkConstants;
40  import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
41  import org.kuali.rice.kew.api.WorkflowDocument;
42  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
43  import org.kuali.rice.kew.api.exception.WorkflowException;
44  import org.kuali.rice.kew.service.KEWServiceLocator;
45  import org.kuali.rice.kim.api.identity.Person;
46  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
47  
48  public class TimesheetServiceImpl implements TimesheetService {
49  
50      @SuppressWarnings("unused")
51      private static final Logger LOG = Logger.getLogger(TimesheetServiceImpl.class);
52  
53      @Override
54      public void routeTimesheet(String principalId, TimesheetDocument timesheetDocument) {
55          routeTimesheet(TkConstants.DOCUMENT_ACTIONS.ROUTE, principalId, timesheetDocument);
56      }
57  
58      @Override
59      public void routeTimesheet(String action, String principalId, TimesheetDocument timesheetDocument) {
60          timesheetAction(action, principalId, timesheetDocument);
61      }
62  
63      @Override
64      public void approveTimesheet(String principalId, TimesheetDocument timesheetDocument) {
65          timesheetAction(TkConstants.DOCUMENT_ACTIONS.APPROVE, principalId, timesheetDocument);
66      }
67  
68      @Override
69      public void approveTimesheet(String principalId, TimesheetDocument timesheetDocument, String action) {
70          timesheetAction(action, principalId, timesheetDocument);
71      }
72  
73      @Override
74      public void disapproveTimesheet(String principalId, TimesheetDocument timesheetDocument) {
75          timesheetAction(TkConstants.DOCUMENT_ACTIONS.DISAPPROVE, principalId, timesheetDocument);
76      }
77  
78      protected void timesheetAction(String action, String principalId, TimesheetDocument timesheetDocument) {
79          WorkflowDocument wd = null;
80          if (timesheetDocument != null) {
81                  String rhid = timesheetDocument.getDocumentId();
82                  wd = WorkflowDocumentFactory.loadDocument(principalId, rhid);
83  
84                  if (StringUtils.equals(action, TkConstants.DOCUMENT_ACTIONS.ROUTE)) {
85                      wd.route("Routing for Approval");
86                  } else if (StringUtils.equals(action, TkConstants.BATCH_JOB_ACTIONS.BATCH_JOB_ROUTE)) {
87                      wd.route("Batch job routing for Approval");
88                  } else if (StringUtils.equals(action, TkConstants.DOCUMENT_ACTIONS.APPROVE)) {
89                      if (TKContext.getUser().getCurrentTargetRoles().isSystemAdmin() &&
90                              !TKContext.getUser().getCurrentTargetRoles().isApproverForTimesheet(timesheetDocument)) {
91                          wd.superUserBlanketApprove("Superuser approving timesheet.");
92                      } else {
93                          wd.approve("Approving timesheet.");
94                      }
95                  } else if (StringUtils.equals(action, TkConstants.BATCH_JOB_ACTIONS.BATCH_JOB_APPROVE)) {
96                      wd.superUserBlanketApprove("Batch job superuser approving timesheet.");
97                  } else if (StringUtils.equals(action, TkConstants.DOCUMENT_ACTIONS.DISAPPROVE)) {
98                      if (TKContext.getUser().getCurrentTargetRoles().isSystemAdmin()
99                              && !TKContext.getUser().getCurrentTargetRoles().isApproverForTimesheet(timesheetDocument)) {
100                         wd.superUserDisapprove("Superuser disapproving timesheet.");
101                     } else {
102                         wd.disapprove("Disapproving timesheet.");
103                     }
104                 }
105 
106                 String kewStatus = KEWServiceLocator.getRouteHeaderService().getDocumentStatus(timesheetDocument.getDocumentId());                		
107                 if (!kewStatus.equals(timesheetDocument.getDocumentHeader().getDocumentStatus())) {
108                     timesheetDocument.getDocumentHeader().setDocumentStatus(kewStatus);
109                     TkServiceLocator.getTimesheetDocumentHeaderService().saveOrUpdate(timesheetDocument.getDocumentHeader());
110                 }
111                 
112         }
113     }
114 
115     @Override
116     public TimesheetDocument openTimesheetDocument(String principalId, CalendarEntries calendarDates) throws WorkflowException {
117         TimesheetDocument timesheetDocument = null;
118 
119         Date begin = calendarDates.getBeginPeriodDateTime();
120         Date end = calendarDates.getEndPeriodDateTime();
121 
122         TimesheetDocumentHeader header = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(principalId, begin, end);
123 
124         if (header == null) {
125             List<Assignment> activeAssignments = TkServiceLocator.getAssignmentService().getAssignmentsByPayEntry(principalId, calendarDates);
126             //TkServiceLocator.getAssignmentService().getAssignments(principalId, TKUtils.getTimelessDate(payCalendarDates.getEndPeriodDate()));
127             if (activeAssignments.size() == 0) {
128                 throw new RuntimeException("No active assignments for " + principalId + " for " + calendarDates.getEndPeriodDate());
129             }
130             
131             Person person = KimApiServiceLocator.getPersonService().getPerson(principalId);
132             String principalName = person != null ? person.getName() : StringUtils.EMPTY;
133             String endDateString = TKUtils.formatDate(new java.sql.Date(end.getTime()));
134             String timesheetDocumentTitle = TimesheetDocument.TIMESHEET_DOCUMENT_TYPE + " - " + principalName + " (" + principalId + ") - " + endDateString;
135             
136             timesheetDocument = this.initiateWorkflowDocument(principalId, begin, end, calendarDates, TimesheetDocument.TIMESHEET_DOCUMENT_TYPE, timesheetDocumentTitle);
137             //timesheetDocument.setPayCalendarEntry(calendarDates);
138             //this.loadTimesheetDocumentData(timesheetDocument, principalId, calendarDates);
139 
140             this.loadHolidaysOnTimesheet(timesheetDocument, principalId, begin, end);
141         } else {
142             timesheetDocument = this.getTimesheetDocument(header.getDocumentId());
143             timesheetDocument.setPayCalendarEntry(calendarDates);
144         }
145 
146         timesheetDocument.setTimeSummary(TkServiceLocator.getTimeSummaryService().getTimeSummary(timesheetDocument));
147         return timesheetDocument;
148     }
149 
150     public void loadHolidaysOnTimesheet(TimesheetDocument timesheetDocument, String principalId, Date beginDate, Date endDate) {
151         PrincipalHRAttributes principalCalendar = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, new java.sql.Date(beginDate.getTime()));
152         if (principalCalendar != null) {
153             HolidayCalendar holidayCalendar = TkServiceLocator.getHolidayCalendarService().getHolidayCalendarByGroup(principalCalendar.getHolidayCalendarGroup());
154             if (holidayCalendar != null) {
155                 List<HolidayCalendarDateEntry> lstHolidays = TkServiceLocator.getHolidayCalendarService().getHolidayCalendarDateEntriesForPayPeriod(holidayCalendar.getHrHolidayCalendarId(),
156                         beginDate, endDate);
157                 for (HolidayCalendarDateEntry holiday : lstHolidays) {
158                     Assignment holidayAssign = TkServiceLocator.getHolidayCalendarService().getAssignmentToApplyHolidays(timesheetDocument, TKUtils.getTimelessDate(endDate));
159                     if (holidayAssign != null) {
160                         BigDecimal holidayCalcHours = TkServiceLocator.getHolidayCalendarService().calculateHolidayHours(holidayAssign.getJob(), holiday.getHolidayHours());
161                         TimeBlock timeBlock = TkServiceLocator.getTimeBlockService().createTimeBlock(timesheetDocument, new Timestamp(holiday.getHolidayDate().getTime()),
162                                 new Timestamp(holiday.getHolidayDate().getTime()), holidayAssign, TkConstants.HOLIDAY_EARN_CODE, holidayCalcHours, BigDecimal.ZERO, false, false);
163                         timesheetDocument.getTimeBlocks().add(timeBlock);
164                     }
165                 }
166 
167                 //If holidays are loaded will need to save them to the database
168                 if (!lstHolidays.isEmpty()) {
169                     TkServiceLocator.getTimeBlockService().saveTimeBlocks(new LinkedList<TimeBlock>(), timesheetDocument.getTimeBlocks());
170                 }
171             }
172         }
173 
174     }
175 
176     protected TimesheetDocument initiateWorkflowDocument(String principalId, Date payBeginDate,  Date payEndDate, CalendarEntries calendarEntries, String documentType, String title) throws WorkflowException {
177         TimesheetDocument timesheetDocument = null;
178         WorkflowDocument workflowDocument = null;
179 
180         workflowDocument = WorkflowDocumentFactory.createDocument(principalId, documentType, title);
181 
182         String status = workflowDocument.getStatus().getCode();
183         TimesheetDocumentHeader documentHeader = new TimesheetDocumentHeader(workflowDocument.getDocumentId(), principalId, payBeginDate, payEndDate, status);
184 
185         documentHeader.setDocumentId(workflowDocument.getDocumentId().toString());
186         documentHeader.setDocumentStatus("I");
187 
188         TkServiceLocator.getTimesheetDocumentHeaderService().saveOrUpdate(documentHeader);
189         timesheetDocument = new TimesheetDocument(documentHeader);
190         timesheetDocument.setPayCalendarEntry(calendarEntries);
191         loadTimesheetDocumentData(timesheetDocument, principalId, calendarEntries);
192         TkServiceLocator.getTkSearchableAttributeService().updateSearchableAttribute(timesheetDocument, payEndDate);
193 
194         return timesheetDocument;
195     }
196 
197     public List<TimeBlock> getPrevDocumentTimeBlocks(String principalId, Date payBeginDate) {
198         TimesheetDocumentHeader prevTdh = TkServiceLocator.getTimesheetDocumentHeaderService().getPreviousDocumentHeader(principalId, payBeginDate);
199         if (prevTdh == null) {
200             return new ArrayList<TimeBlock>();
201         }
202         return TkServiceLocator.getTimeBlockService().getTimeBlocks(prevTdh.getDocumentId());
203     }
204 
205     @Override
206     public TimesheetDocument getTimesheetDocument(String documentId) {
207         TimesheetDocument timesheetDocument = null;
208         TimesheetDocumentHeader tdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(documentId);
209 
210         if (tdh != null) {
211             timesheetDocument = new TimesheetDocument(tdh);
212             CalendarEntries pce = TkServiceLocator.getCalendarService().getCalendarDatesByPayEndDate(tdh.getPrincipalId(), tdh.getPayEndDate(), null);
213             loadTimesheetDocumentData(timesheetDocument, tdh.getPrincipalId(), pce);
214 
215             timesheetDocument.setPayCalendarEntry(pce);
216         } else {
217             throw new RuntimeException("Could not find TimesheetDocumentHeader for DocumentID: " + documentId);
218         }
219         return timesheetDocument;
220     }
221 
222     protected void loadTimesheetDocumentData(TimesheetDocument tdoc, String principalId, CalendarEntries payCalEntry) {
223         List<Assignment> assignments = TkServiceLocator.getAssignmentService().getAssignmentsByPayEntry(principalId, payCalEntry);
224         List<Job> jobs = TkServiceLocator.getJobService().getJobs(principalId, TKUtils.getTimelessDate(payCalEntry.getEndPeriodDate()));
225         List<TimeBlock> timeBlocks = TkServiceLocator.getTimeBlockService().getTimeBlocks(tdoc.getDocumentHeader().getDocumentId());
226 
227         tdoc.setAssignments(assignments);
228         tdoc.setJobs(jobs);
229         tdoc.setTimeBlocks(timeBlocks);
230     }
231 
232     public boolean isSynchronousUser() {
233         List<Assignment> assignments = TkServiceLocator.getAssignmentService().getAssignments(TKUser.getCurrentTargetPerson().getPrincipalId(), TKUtils.getCurrentDate());
234         boolean isSynchronousUser = true;
235         for (Assignment assignment : assignments) {
236             isSynchronousUser &= assignment.isSynchronous();
237         }
238         return isSynchronousUser;
239     }
240 
241     //this is an admin function used for testing
242     public void deleteTimesheet(String documentId) {
243         TkServiceLocator.getTimeBlockService().deleteTimeBlocksAssociatedWithDocumentId(documentId);
244         TkServiceLocator.getTimesheetDocumentHeaderService().deleteTimesheetHeader(documentId);
245     }
246 
247     public TimeBlock resetWorkedHours(TimeBlock timeBlock) {
248         if (timeBlock.getBeginTime() != null && timeBlock.getEndTime() != null && StringUtils.equals(timeBlock.getEarnCodeType(), TkConstants.EARN_CODE_TIME)) {
249             BigDecimal hours = TKUtils.getHoursBetween(timeBlock.getBeginTime().getTime(), timeBlock.getEndTime().getTime());
250             timeBlock.setHours(hours);
251         }
252         return timeBlock;
253     }
254 
255     @Override
256     public void resetTimeBlock(List<TimeBlock> timeBlocks) {
257         for (TimeBlock tb : timeBlocks) {
258             resetWorkedHours(tb);
259         }
260         TkServiceLocator.getTimeBlockService().resetTimeHourDetail(timeBlocks);
261     }
262 
263 }