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 }