001 /**
002 * Copyright 2004-2012 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.timesheet.service;
017
018 import java.math.BigDecimal;
019 import java.sql.Timestamp;
020 import java.util.ArrayList;
021 import java.util.Date;
022 import java.util.LinkedList;
023 import java.util.List;
024
025 import org.apache.commons.lang.StringUtils;
026 import org.apache.log4j.Logger;
027 import org.kuali.hr.job.Job;
028 import org.kuali.hr.time.assignment.Assignment;
029 import org.kuali.hr.time.calendar.CalendarEntries;
030 import org.kuali.hr.time.holidaycalendar.HolidayCalendar;
031 import org.kuali.hr.time.holidaycalendar.HolidayCalendarDateEntry;
032 import org.kuali.hr.time.principal.PrincipalHRAttributes;
033 import org.kuali.hr.time.service.base.TkServiceLocator;
034 import org.kuali.hr.time.timeblock.TimeBlock;
035 import org.kuali.hr.time.timesheet.TimesheetDocument;
036 import org.kuali.hr.time.util.TKContext;
037 import org.kuali.hr.time.util.TKUser;
038 import org.kuali.hr.time.util.TKUtils;
039 import org.kuali.hr.time.util.TkConstants;
040 import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
041 import org.kuali.rice.kew.api.WorkflowDocument;
042 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
043 import org.kuali.rice.kew.api.exception.WorkflowException;
044 import org.kuali.rice.kew.service.KEWServiceLocator;
045
046 public class TimesheetServiceImpl implements TimesheetService {
047
048 @SuppressWarnings("unused")
049 private static final Logger LOG = Logger.getLogger(TimesheetServiceImpl.class);
050
051 @Override
052 public void routeTimesheet(String principalId, TimesheetDocument timesheetDocument) {
053 routeTimesheet(TkConstants.DOCUMENT_ACTIONS.ROUTE, principalId, timesheetDocument);
054 }
055
056 @Override
057 public void routeTimesheet(String action, String principalId, TimesheetDocument timesheetDocument) {
058 timesheetAction(action, principalId, timesheetDocument);
059 }
060
061 @Override
062 public void approveTimesheet(String principalId, TimesheetDocument timesheetDocument) {
063 timesheetAction(TkConstants.DOCUMENT_ACTIONS.APPROVE, principalId, timesheetDocument);
064 }
065
066 @Override
067 public void approveTimesheet(String principalId, TimesheetDocument timesheetDocument, String action) {
068 timesheetAction(action, principalId, timesheetDocument);
069 }
070
071 @Override
072 public void disapproveTimesheet(String principalId, TimesheetDocument timesheetDocument) {
073 timesheetAction(TkConstants.DOCUMENT_ACTIONS.DISAPPROVE, principalId, timesheetDocument);
074 }
075
076 protected void timesheetAction(String action, String principalId, TimesheetDocument timesheetDocument) {
077 WorkflowDocument wd = null;
078 if (timesheetDocument != null) {
079 String rhid = timesheetDocument.getDocumentId();
080 wd = WorkflowDocumentFactory.loadDocument(principalId, rhid);
081
082 if (StringUtils.equals(action, TkConstants.DOCUMENT_ACTIONS.ROUTE)) {
083 wd.route("Routing for Approval");
084 } else if (StringUtils.equals(action, TkConstants.BATCH_JOB_ACTIONS.BATCH_JOB_ROUTE)) {
085 wd.route("Batch job routing for Approval");
086 } else if (StringUtils.equals(action, TkConstants.DOCUMENT_ACTIONS.APPROVE)) {
087 if (TKContext.getUser().getCurrentTargetRoles().isSystemAdmin() &&
088 !TKContext.getUser().getCurrentTargetRoles().isApproverForTimesheet(timesheetDocument)) {
089 wd.superUserBlanketApprove("Superuser approving timesheet.");
090 } else {
091 wd.approve("Approving timesheet.");
092 }
093 } else if (StringUtils.equals(action, TkConstants.BATCH_JOB_ACTIONS.BATCH_JOB_APPROVE)) {
094 wd.superUserBlanketApprove("Batch job superuser approving timesheet.");
095 } else if (StringUtils.equals(action, TkConstants.DOCUMENT_ACTIONS.DISAPPROVE)) {
096 if (TKContext.getUser().getCurrentTargetRoles().isSystemAdmin()
097 && !TKContext.getUser().getCurrentTargetRoles().isApproverForTimesheet(timesheetDocument)) {
098 wd.superUserDisapprove("Superuser disapproving timesheet.");
099 } else {
100 wd.disapprove("Disapproving timesheet.");
101 }
102 }
103
104 String kewStatus = KEWServiceLocator.getRouteHeaderService().getDocumentStatus(timesheetDocument.getDocumentId());
105 if (!kewStatus.equals(timesheetDocument.getDocumentHeader().getDocumentStatus())) {
106 timesheetDocument.getDocumentHeader().setDocumentStatus(kewStatus);
107 TkServiceLocator.getTimesheetDocumentHeaderService().saveOrUpdate(timesheetDocument.getDocumentHeader());
108 }
109
110 }
111 }
112
113 @Override
114 public TimesheetDocument openTimesheetDocument(String principalId, CalendarEntries calendarDates) throws WorkflowException {
115 TimesheetDocument timesheetDocument = null;
116
117 Date begin = calendarDates.getBeginPeriodDateTime();
118 Date end = calendarDates.getEndPeriodDateTime();
119
120 TimesheetDocumentHeader header = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(principalId, begin, end);
121
122 if (header == null) {
123 List<Assignment> activeAssignments = TkServiceLocator.getAssignmentService().getAssignmentsByPayEntry(principalId, calendarDates);
124 //TkServiceLocator.getAssignmentService().getAssignments(principalId, TKUtils.getTimelessDate(payCalendarDates.getEndPeriodDate()));
125 if (activeAssignments.size() == 0) {
126 throw new RuntimeException("No active assignments for " + principalId + " for " + calendarDates.getEndPeriodDate());
127 }
128 timesheetDocument = this.initiateWorkflowDocument(principalId, begin, end, TimesheetDocument.TIMESHEET_DOCUMENT_TYPE, TimesheetDocument.TIMESHEET_DOCUMENT_TITLE);
129 timesheetDocument.setPayCalendarEntry(calendarDates);
130 this.loadTimesheetDocumentData(timesheetDocument, principalId, calendarDates);
131
132 this.loadHolidaysOnTimesheet(timesheetDocument, principalId, begin, end);
133 } else {
134 timesheetDocument = this.getTimesheetDocument(header.getDocumentId());
135 timesheetDocument.setPayCalendarEntry(calendarDates);
136 }
137
138 timesheetDocument.setTimeSummary(TkServiceLocator.getTimeSummaryService().getTimeSummary(timesheetDocument));
139 return timesheetDocument;
140 }
141
142 public void loadHolidaysOnTimesheet(TimesheetDocument timesheetDocument, String principalId, Date beginDate, Date endDate) {
143 PrincipalHRAttributes principalCalendar = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, new java.sql.Date(beginDate.getTime()));
144 if (principalCalendar != null) {
145 HolidayCalendar holidayCalendar = TkServiceLocator.getHolidayCalendarService().getHolidayCalendarByGroup(principalCalendar.getHolidayCalendarGroup());
146 if (holidayCalendar != null) {
147 List<HolidayCalendarDateEntry> lstHolidays = TkServiceLocator.getHolidayCalendarService().getHolidayCalendarDateEntriesForPayPeriod(holidayCalendar.getHrHolidayCalendarId(),
148 beginDate, endDate);
149 for (HolidayCalendarDateEntry holiday : lstHolidays) {
150 Assignment holidayAssign = TkServiceLocator.getHolidayCalendarService().getAssignmentToApplyHolidays(timesheetDocument, TKUtils.getTimelessDate(endDate));
151 if (holidayAssign != null) {
152 BigDecimal holidayCalcHours = TkServiceLocator.getHolidayCalendarService().calculateHolidayHours(holidayAssign.getJob(), holiday.getHolidayHours());
153 TimeBlock timeBlock = TkServiceLocator.getTimeBlockService().createTimeBlock(timesheetDocument, new Timestamp(holiday.getHolidayDate().getTime()),
154 new Timestamp(holiday.getHolidayDate().getTime()), holidayAssign, TkConstants.HOLIDAY_EARN_CODE, holidayCalcHours, BigDecimal.ZERO, false, false);
155 timesheetDocument.getTimeBlocks().add(timeBlock);
156 }
157 }
158
159 //If holidays are loaded will need to save them to the database
160 if (!lstHolidays.isEmpty()) {
161 TkServiceLocator.getTimeBlockService().saveTimeBlocks(new LinkedList<TimeBlock>(), timesheetDocument.getTimeBlocks());
162 }
163 }
164 }
165
166 }
167
168 protected TimesheetDocument initiateWorkflowDocument(String principalId, Date payBeginDate, Date payEndDate, String documentType, String title) throws WorkflowException {
169 TimesheetDocument timesheetDocument = null;
170 WorkflowDocument workflowDocument = null;
171
172 workflowDocument = WorkflowDocumentFactory.createDocument(principalId, documentType, title);
173
174 String status = workflowDocument.getStatus().getCode();
175 TimesheetDocumentHeader documentHeader = new TimesheetDocumentHeader(workflowDocument.getDocumentId(), principalId, payBeginDate, payEndDate, status);
176
177 documentHeader.setDocumentId(workflowDocument.getDocumentId().toString());
178 documentHeader.setDocumentStatus("I");
179
180 TkServiceLocator.getTimesheetDocumentHeaderService().saveOrUpdate(documentHeader);
181 timesheetDocument = new TimesheetDocument(documentHeader);
182
183 TkServiceLocator.getTkSearchableAttributeService().updateSearchableAttribute(timesheetDocument, payEndDate);
184
185 return timesheetDocument;
186 }
187
188 public List<TimeBlock> getPrevDocumentTimeBlocks(String principalId, Date payBeginDate) {
189 TimesheetDocumentHeader prevTdh = TkServiceLocator.getTimesheetDocumentHeaderService().getPreviousDocumentHeader(principalId, payBeginDate);
190 if (prevTdh == null) {
191 return new ArrayList<TimeBlock>();
192 }
193 return TkServiceLocator.getTimeBlockService().getTimeBlocks(prevTdh.getDocumentId());
194 }
195
196 @Override
197 public TimesheetDocument getTimesheetDocument(String documentId) {
198 TimesheetDocument timesheetDocument = null;
199 TimesheetDocumentHeader tdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(documentId);
200
201 if (tdh != null) {
202 timesheetDocument = new TimesheetDocument(tdh);
203 CalendarEntries pce = TkServiceLocator.getCalendarService().getCalendarDatesByPayEndDate(tdh.getPrincipalId(), tdh.getPayEndDate(), null);
204 loadTimesheetDocumentData(timesheetDocument, tdh.getPrincipalId(), pce);
205
206 timesheetDocument.setPayCalendarEntry(pce);
207 } else {
208 throw new RuntimeException("Could not find TimesheetDocumentHeader for DocumentID: " + documentId);
209 }
210 return timesheetDocument;
211 }
212
213 protected void loadTimesheetDocumentData(TimesheetDocument tdoc, String principalId, CalendarEntries payCalEntry) {
214 List<Assignment> assignments = TkServiceLocator.getAssignmentService().getAssignmentsByPayEntry(principalId, payCalEntry);
215 List<Job> jobs = TkServiceLocator.getJobService().getJobs(principalId, TKUtils.getTimelessDate(payCalEntry.getEndPeriodDate()));
216 List<TimeBlock> timeBlocks = TkServiceLocator.getTimeBlockService().getTimeBlocks(tdoc.getDocumentHeader().getDocumentId());
217
218 tdoc.setAssignments(assignments);
219 tdoc.setJobs(jobs);
220 tdoc.setTimeBlocks(timeBlocks);
221 }
222
223 public boolean isSynchronousUser() {
224 List<Assignment> assignments = TkServiceLocator.getAssignmentService().getAssignments(TKUser.getCurrentTargetPerson().getPrincipalId(), TKUtils.getCurrentDate());
225 boolean isSynchronousUser = true;
226 for (Assignment assignment : assignments) {
227 isSynchronousUser &= assignment.isSynchronous();
228 }
229 return isSynchronousUser;
230 }
231
232 //this is an admin function used for testing
233 public void deleteTimesheet(String documentId) {
234 TkServiceLocator.getTimeBlockService().deleteTimeBlocksAssociatedWithDocumentId(documentId);
235 TkServiceLocator.getTimesheetDocumentHeaderService().deleteTimesheetHeader(documentId);
236 }
237
238 public TimeBlock resetWorkedHours(TimeBlock timeBlock) {
239 if (timeBlock.getBeginTime() != null && timeBlock.getEndTime() != null && StringUtils.equals(timeBlock.getEarnCodeType(), TkConstants.EARN_CODE_TIME)) {
240 BigDecimal hours = TKUtils.getHoursBetween(timeBlock.getBeginTime().getTime(), timeBlock.getEndTime().getTime());
241 timeBlock.setHours(hours);
242 }
243 return timeBlock;
244 }
245
246 @Override
247 public void resetTimeBlock(List<TimeBlock> timeBlocks) {
248 for (TimeBlock tb : timeBlocks) {
249 resetWorkedHours(tb);
250 }
251 TkServiceLocator.getTimeBlockService().resetTimeHourDetail(timeBlocks);
252 }
253
254 }