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.clocklog.service; 017 018 import java.math.BigDecimal; 019 import java.sql.Timestamp; 020 import java.util.ArrayList; 021 import java.util.HashSet; 022 import java.util.List; 023 import java.util.Set; 024 025 import org.apache.commons.collections.CollectionUtils; 026 import org.apache.commons.lang.StringUtils; 027 import org.kuali.hr.time.assignment.Assignment; 028 import org.kuali.hr.time.calendar.CalendarEntries; 029 import org.kuali.hr.time.clocklog.ClockLog; 030 import org.kuali.hr.time.clocklog.dao.ClockLogDao; 031 import org.kuali.hr.time.service.base.TkServiceLocator; 032 import org.kuali.hr.time.timeblock.TimeBlock; 033 import org.kuali.hr.time.timesheet.TimesheetDocument; 034 import org.kuali.hr.time.util.TKContext; 035 import org.kuali.hr.time.util.TkConstants; 036 import org.kuali.rice.krad.service.KRADServiceLocator; 037 import org.kuali.rice.krad.util.KRADConstants; 038 039 public class ClockLogServiceImpl implements ClockLogService { 040 041 private ClockLogDao clockLogDao; 042 043 public ClockLogServiceImpl() { 044 } 045 046 public void saveClockLog(ClockLog clockLog) { 047 clockLogDao.saveOrUpdate(clockLog); 048 } 049 050 @Override 051 public ClockLog processClockLog(Timestamp clockTimeStamp, Assignment assignment,CalendarEntries pe, String ip, java.sql.Date asOfDate, TimesheetDocument td, String clockAction, String principalId) { 052 return processClockLog(clockTimeStamp, assignment, pe, ip, asOfDate, td, clockAction, principalId, TKContext.getPrincipalId()); 053 } 054 055 @Override 056 public ClockLog processClockLog(Timestamp clockTimeStamp, Assignment assignment,CalendarEntries pe, String ip, java.sql.Date asOfDate, TimesheetDocument td, String clockAction, String principalId, String userPrincipalId) { 057 // process rules 058 Timestamp roundedClockTimestamp = TkServiceLocator.getGracePeriodService().processGracePeriodRule(clockTimeStamp, new java.sql.Date(pe.getBeginPeriodDateTime().getTime())); 059 060 ClockLog clockLog = buildClockLog(roundedClockTimestamp, new Timestamp(System.currentTimeMillis()), assignment, td, clockAction, ip, userPrincipalId); 061 TkServiceLocator.getClockLocationRuleService().processClockLocationRule(clockLog, asOfDate); 062 063 // If the clock action is clock out or lunch out, create a time block besides the clock log 064 if (StringUtils.equals(clockAction, TkConstants.CLOCK_OUT) || StringUtils.equals(clockAction, TkConstants.LUNCH_OUT)) { 065 processTimeBlock(clockLog, assignment, pe, td, clockAction, principalId, userPrincipalId); 066 } else { 067 //Save current clock log to get id for timeblock building 068 KRADServiceLocator.getBusinessObjectService().save(clockLog); 069 } 070 071 return clockLog; 072 } 073 074 private void processTimeBlock(ClockLog clockLog, Assignment assignment, CalendarEntries pe, TimesheetDocument td, String clockAction, String principalId, String userPrincipalId) { 075 ClockLog lastLog = null; 076 Timestamp lastClockTimestamp = null; 077 String beginClockLogId = null; 078 String endClockLogId = null; 079 080 if (StringUtils.equals(clockAction, TkConstants.LUNCH_OUT)) { 081 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(principalId, TkConstants.CLOCK_IN); 082 } else if (StringUtils.equals(clockAction, TkConstants.CLOCK_OUT)) { 083 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(principalId); 084 } 085 if (lastLog != null) { 086 lastClockTimestamp = lastLog.getClockTimestamp(); 087 beginClockLogId = lastLog.getTkClockLogId(); 088 } 089 //Save current clock log to get id for timeblock building 090 KRADServiceLocator.getBusinessObjectService().save(clockLog); 091 endClockLogId = clockLog.getTkClockLogId(); 092 093 long beginTime = lastClockTimestamp.getTime(); 094 Timestamp beginTimestamp = new Timestamp(beginTime); 095 Timestamp endTimestamp = clockLog.getClockTimestamp(); 096 097 // New Time Blocks, pointer reference 098 List<TimeBlock> newTimeBlocks = td.getTimeBlocks(); 099 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(td.getTimeBlocks().size()); 100 for (TimeBlock tb : td.getTimeBlocks()) { 101 referenceTimeBlocks.add(tb.copy()); 102 } 103 104 // Add TimeBlocks after we store our reference object! 105 List<TimeBlock> aList = TkServiceLocator.getTimeBlockService().buildTimeBlocks(assignment, assignment.getJob().getPayTypeObj().getRegEarnCode(), td, beginTimestamp, endTimestamp, BigDecimal.ZERO, BigDecimal.ZERO, true, false, userPrincipalId); 106 for (TimeBlock tb : aList) { 107 tb.setClockLogBeginId(beginClockLogId); 108 tb.setClockLogEndId(endClockLogId); 109 } 110 newTimeBlocks.addAll(aList); 111 112 //reset time block 113 TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks); 114 115 //apply any rules for this action 116 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.CLOCK_OUT, newTimeBlocks, pe, td, principalId); 117 118 //call persist method that only saves added/deleted/changed timeblocks 119 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, userPrincipalId); 120 } 121 122 @Override 123 public ClockLog buildClockLog(Timestamp clockTimestamp, Timestamp originalTimestamp, Assignment assignment, TimesheetDocument timesheetDocument, String clockAction, String ip) { 124 return buildClockLog(clockTimestamp, originalTimestamp, assignment, timesheetDocument, clockAction, ip, TKContext.getPrincipalId()); 125 } 126 127 @Override 128 public ClockLog buildClockLog(Timestamp clockTimestamp, Timestamp originalTimestamp, Assignment assignment, TimesheetDocument timesheetDocument, String clockAction, String ip, String userPrincipalId) { 129 String principalId = timesheetDocument.getPrincipalId(); 130 131 ClockLog clockLog = new ClockLog(); 132 clockLog.setPrincipalId(principalId); 133 // AssignmentDescriptionKey assignmentDesc = TkServiceLocator.getAssignmentService().getAssignmentDescriptionKey(selectedAssign); 134 // Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(timesheetDocument, selectedAssign); 135 clockLog.setJob(timesheetDocument.getJob(assignment.getJobNumber())); 136 clockLog.setJobNumber(assignment.getJobNumber()); 137 clockLog.setWorkArea(assignment.getWorkArea()); 138 clockLog.setTask(assignment.getTask()); 139 clockLog.setClockTimestampTimezone(TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback().getID()); 140 clockLog.setClockTimestamp(clockTimestamp); 141 clockLog.setClockAction(clockAction); 142 clockLog.setIpAddress(ip); 143 clockLog.setUserPrincipalId(userPrincipalId); 144 // timestamp should be the original time without Grace Period rule applied 145 clockLog.setTimestamp(originalTimestamp); 146 147 return clockLog; 148 } 149 150 public void setClockLogDao(ClockLogDao clockLogDao) { 151 this.clockLogDao = clockLogDao; 152 } 153 154 public ClockLog getLastClockLog(String principalId) { 155 return clockLogDao.getLastClockLog(principalId); 156 } 157 158 public ClockLog getLastClockLog(String principalId, String clockAction) { 159 return clockLogDao.getLastClockLog(principalId, clockAction); 160 } 161 162 public ClockLog getLastClockLog(String principalId, String jobNumber, String workArea, String task, CalendarEntries calendarEntry) { 163 return clockLogDao.getLastClockLog(principalId, jobNumber, workArea, task, calendarEntry); 164 } 165 166 @Override 167 public ClockLog getClockLog(String tkClockLogId) { 168 return clockLogDao.getClockLog(tkClockLogId); 169 } 170 171 public List<String> getUnapprovedIPWarning(List<TimeBlock> timeBlocks) { 172 List<String> warningMessages = new ArrayList<String>(); 173 if (CollectionUtils.isNotEmpty(timeBlocks)) { 174 Set<String> aSet = new HashSet<String>(); 175 for(TimeBlock tb : timeBlocks) { 176 if(tb.getClockLogCreated()) { 177 if(StringUtils.isNotEmpty(tb.getClockLogBeginId())){ 178 ClockLog cl = TkServiceLocator.getClockLogService().getClockLog(tb.getClockLogBeginId()); 179 if(cl.getUnapprovedIP()) { 180 aSet.add(buildUnapprovedIPWarning(cl)); 181 } 182 } 183 if(StringUtils.isNotEmpty(tb.getClockLogEndId())){ 184 ClockLog cl = TkServiceLocator.getClockLogService().getClockLog(tb.getClockLogEndId()); 185 if(cl.getUnapprovedIP()) { 186 aSet.add(buildUnapprovedIPWarning(cl)); 187 } 188 } 189 } 190 } 191 warningMessages.addAll(aSet); 192 } 193 194 return warningMessages; 195 } 196 197 public String buildUnapprovedIPWarning(ClockLog cl) { 198 String warning = "Warning: Action '" + TkConstants.CLOCK_ACTION_STRINGS.get(cl.getClockAction()) + "' taken at " 199 + cl.getClockTimestamp() + " was from an unapproved IP address - " + cl.getIpAddress(); 200 return warning; 201 } 202 203 }