1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.kpme.tklm.time.clocklog.service;
17
18 import java.math.BigDecimal;
19 import java.sql.Timestamp;
20 import java.util.ArrayList;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Set;
24
25 import org.apache.commons.collections.CollectionUtils;
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.log4j.Logger;
28 import org.joda.time.DateTime;
29 import org.joda.time.LocalDate;
30 import org.kuali.kpme.core.assignment.Assignment;
31 import org.kuali.kpme.core.calendar.entry.CalendarEntry;
32 import org.kuali.kpme.core.service.HrServiceLocator;
33 import org.kuali.kpme.core.util.HrContext;
34 import org.kuali.kpme.core.util.TKUtils;
35 import org.kuali.kpme.tklm.common.TkConstants;
36 import org.kuali.kpme.tklm.leave.block.LeaveBlock;
37 import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
38 import org.kuali.kpme.tklm.time.batch.EndPayPeriodJob;
39 import org.kuali.kpme.tklm.time.clocklog.ClockLog;
40 import org.kuali.kpme.tklm.time.clocklog.dao.ClockLogDao;
41 import org.kuali.kpme.tklm.time.service.TkServiceLocator;
42 import org.kuali.kpme.tklm.time.timeblock.TimeBlock;
43 import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
44 import org.kuali.kpme.tklm.time.workflow.TimesheetDocumentHeader;
45 import org.kuali.rice.krad.service.KRADServiceLocator;
46
47 public class ClockLogServiceImpl implements ClockLogService {
48
49 private static final Logger LOG = Logger.getLogger(ClockLogServiceImpl.class);
50
51 private ClockLogDao clockLogDao;
52
53 public ClockLogServiceImpl() {
54 }
55
56 public ClockLog saveClockLog(ClockLog clockLog) {
57 return KRADServiceLocator.getBusinessObjectService().save(clockLog);
58 }
59
60 @Override
61 public ClockLog processClockLog(DateTime clockDateTime, Assignment assignment,CalendarEntry pe, String ip, LocalDate asOfDate, TimesheetDocument td, String clockAction, boolean runRules, String principalId) {
62 return processClockLog(clockDateTime, assignment, pe, ip, asOfDate, td, clockAction, runRules, principalId, HrContext.getPrincipalId());
63 }
64
65 @Override
66 public synchronized ClockLog processClockLog(DateTime clockDateTime, Assignment assignment,CalendarEntry pe, String ip, LocalDate asOfDate, TimesheetDocument td, String clockAction, boolean runRules, String principalId, String userPrincipalId) {
67
68 DateTime roundedClockDateTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(clockDateTime, pe.getBeginPeriodFullDateTime().toLocalDate());
69
70 ClockLog lastClockLog = null;
71 if (StringUtils.equals(clockAction, TkConstants.LUNCH_OUT)) {
72 lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog(assignment.getPrincipalId(), TkConstants.CLOCK_IN);
73 } else if (StringUtils.equals(clockAction, TkConstants.CLOCK_OUT)
74 || StringUtils.equals(clockAction, TkConstants.CLOCK_IN)) {
75 lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog(assignment.getPrincipalId());
76 }
77
78 DateTime lastClockLogTime = lastClockLog != null ? lastClockLog.getClockDateTime() : null;
79 if (lastClockLog != null
80 && lastClockLogTime.withMillisOfSecond(0).equals(roundedClockDateTime.withMillisOfSecond(0))) {
81 roundedClockDateTime = roundedClockDateTime.withMillisOfSecond(lastClockLogTime.getMillisOfSecond() + 1);
82 }
83
84
85 ClockLog clockLog = buildClockLog(roundedClockDateTime, new Timestamp(System.currentTimeMillis()), assignment, td, clockAction, ip, userPrincipalId);
86
87 if (runRules) {
88 TkServiceLocator.getClockLocationRuleService().processClockLocationRule(clockLog, asOfDate);
89 }
90
91
92 if (StringUtils.equals(clockAction, TkConstants.CLOCK_OUT) || StringUtils.equals(clockAction, TkConstants.LUNCH_OUT)) {
93 processTimeBlock(clockLog, assignment, pe, td, clockAction, principalId, userPrincipalId);
94 } else {
95
96 KRADServiceLocator.getBusinessObjectService().save(clockLog);
97 }
98 return clockLog;
99 }
100
101 private void processTimeBlock(ClockLog clockLog, Assignment currentAssignment, CalendarEntry pe, TimesheetDocument td, String clockAction, String principalId, String userPrincipalId) {
102 LOG.info("in ClockLogServiceImpl.processTimeBlock");
103 ClockLog lastLog = null;
104 DateTime lastClockDateTime = null;
105 String beginClockLogId = null;
106 String endClockLogId = null;
107
108 if (StringUtils.equals(clockAction, TkConstants.LUNCH_OUT)) {
109 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(principalId, TkConstants.CLOCK_IN);
110 } else if (StringUtils.equals(clockAction, TkConstants.CLOCK_OUT)) {
111 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(principalId);
112 }
113 if (lastLog != null) {
114 lastClockDateTime = lastLog.getClockDateTime();
115 beginClockLogId = lastLog.getTkClockLogId();
116 }
117
118 KRADServiceLocator.getBusinessObjectService().save(clockLog);
119 endClockLogId = clockLog.getTkClockLogId();
120
121 DateTime beginDateTime = lastClockDateTime;
122 DateTime endDateTime = clockLog.getClockDateTime();
123
124
125 BigDecimal hours = TKUtils.getHoursBetween(beginDateTime.getMillis(), endDateTime.getMillis());
126 if(hours.compareTo(BigDecimal.ZERO) > 0) {
127
128 List<TimeBlock> newTimeBlocks = td.getTimeBlocks();
129 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(td.getTimeBlocks().size());
130 for (TimeBlock tb : td.getTimeBlocks()) {
131 referenceTimeBlocks.add(tb.copy());
132 }
133
134
135 List<TimeBlock> aList = TkServiceLocator.getTimeBlockService().buildTimeBlocks(currentAssignment,
136 currentAssignment.getJob().getPayTypeObj().getRegEarnCode(), td, beginDateTime, endDateTime,
137 BigDecimal.ZERO, BigDecimal.ZERO, true, false, userPrincipalId, beginClockLogId, endClockLogId);
138
139 newTimeBlocks.addAll(aList);
140
141 List<Assignment> assignments = td.getAssignments();
142 List<String> assignmentKeys = new ArrayList<String>();
143 for (Assignment assignment : assignments) {
144 assignmentKeys.add(assignment.getAssignmentKey());
145 }
146 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(principalId, td.getAsOfDate(), td.getDocEndDate(), assignmentKeys);
147
148
149 TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks, td.getAsOfDate());
150
151
152 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.CLOCK_OUT, newTimeBlocks, leaveBlocks, pe, td, principalId);
153
154
155 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, userPrincipalId);
156
157 LOG.info("in ClockLogServiceImpl.processTimeBlock, after saving time blocks, the size of the time blocks is " + newTimeBlocks.size());
158 }
159 }
160
161 private ClockLog buildClockLog(DateTime clockDateTime, Timestamp originalTimestamp, Assignment assignment, TimesheetDocument timesheetDocument, String clockAction, String ip, String userPrincipalId) {
162 ClockLog clockLog = new ClockLog();
163 clockLog.setDocumentId(timesheetDocument.getDocumentId());
164 clockLog.setPrincipalId(timesheetDocument.getPrincipalId());
165 clockLog.setJob(timesheetDocument.getJob(assignment.getJobNumber()));
166 clockLog.setJobNumber(assignment.getJobNumber());
167 clockLog.setWorkArea(assignment.getWorkArea());
168 clockLog.setTask(assignment.getTask());
169 clockLog.setClockTimestampTimezone(HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback().getID());
170 clockLog.setClockDateTime(clockDateTime);
171 clockLog.setClockAction(clockAction);
172 clockLog.setIpAddress(ip);
173 clockLog.setUserPrincipalId(userPrincipalId);
174
175 clockLog.setTimestamp(originalTimestamp);
176
177 return clockLog;
178 }
179
180 public void setClockLogDao(ClockLogDao clockLogDao) {
181 this.clockLogDao = clockLogDao;
182 }
183
184 public ClockLog getLastClockLog(String principalId) {
185 return clockLogDao.getLastClockLog(principalId);
186 }
187
188 public ClockLog getLastClockLog(String principalId, String clockAction) {
189 return clockLogDao.getLastClockLog(principalId, clockAction);
190 }
191
192 public ClockLog getLastClockLog(String principalId, String jobNumber, String workArea, String task, CalendarEntry calendarEntry) {
193 TimesheetDocumentHeader tdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(principalId, calendarEntry.getBeginPeriodFullDateTime(), calendarEntry.getEndPeriodFullDateTime());
194 if(tdh == null)
195 return null;
196 return clockLogDao.getLastClockLog(principalId, jobNumber, workArea, task, tdh.getDocumentId());
197
198 }
199
200 @Override
201 public ClockLog getClockLog(String tkClockLogId) {
202 return clockLogDao.getClockLog(tkClockLogId);
203 }
204
205 @Override
206 public void deleteClockLogsForDocumentId(String documentId) {
207 clockLogDao.deleteClockLogsForDocumentId(documentId);
208 }
209
210 public List<String> getUnapprovedIPWarning(List<TimeBlock> timeBlocks) {
211 List<String> warningMessages = new ArrayList<String>();
212 if (CollectionUtils.isNotEmpty(timeBlocks)) {
213 Set<String> aSet = new HashSet<String>();
214 for(TimeBlock tb : timeBlocks) {
215 if(tb.getClockLogCreated()) {
216 if(StringUtils.isNotEmpty(tb.getClockLogBeginId())){
217 ClockLog cl = TkServiceLocator.getClockLogService().getClockLog(tb.getClockLogBeginId());
218 if(cl == null || cl.isUnapprovedIP()) {
219 aSet.add(buildUnapprovedIPWarning(cl));
220 }
221 }
222 if(StringUtils.isNotEmpty(tb.getClockLogEndId())){
223 ClockLog cl = TkServiceLocator.getClockLogService().getClockLog(tb.getClockLogEndId());
224 if(cl == null || cl.isUnapprovedIP()) {
225 aSet.add(buildUnapprovedIPWarning(cl));
226 }
227 }
228 }
229 }
230 warningMessages.addAll(aSet);
231 }
232
233 return warningMessages;
234 }
235
236 public String buildUnapprovedIPWarning(ClockLog cl) {
237 String warning = "Warning: Action '" + TkConstants.CLOCK_ACTION_STRINGS.get(cl.getClockAction()) + "' taken at "
238 + cl.getClockTimestamp() + " was from an unapproved IP address - " + cl.getIpAddress();
239 return warning;
240 }
241
242 }