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