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 }