1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.kpme.tklm.time.missedpunch.service;
17
18 import java.math.BigDecimal;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.log4j.Logger;
24 import org.joda.time.DateTime;
25 import org.joda.time.DateTimeZone;
26 import org.joda.time.LocalDate;
27 import org.kuali.kpme.core.assignment.Assignment;
28 import org.kuali.kpme.core.assignment.AssignmentDescriptionKey;
29 import org.kuali.kpme.core.assignment.service.AssignmentService;
30 import org.kuali.kpme.core.batch.BatchJobUtil;
31 import org.kuali.kpme.core.calendar.entry.CalendarEntry;
32 import org.kuali.kpme.core.service.HrServiceLocator;
33 import org.kuali.kpme.core.service.timezone.TimezoneService;
34 import org.kuali.kpme.core.util.HrContext;
35 import org.kuali.kpme.core.util.TKUtils;
36 import org.kuali.kpme.tklm.common.TkConstants;
37 import org.kuali.kpme.tklm.leave.block.LeaveBlock;
38 import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
39 import org.kuali.kpme.tklm.time.clocklog.ClockLog;
40 import org.kuali.kpme.tklm.time.clocklog.service.ClockLogService;
41 import org.kuali.kpme.tklm.time.missedpunch.MissedPunch;
42 import org.kuali.kpme.tklm.time.missedpunch.MissedPunchDocument;
43 import org.kuali.kpme.tklm.time.missedpunch.dao.MissedPunchDao;
44 import org.kuali.kpme.tklm.time.rules.TkRuleControllerService;
45 import org.kuali.kpme.tklm.time.service.TkServiceLocator;
46 import org.kuali.kpme.tklm.time.timeblock.TimeBlock;
47 import org.kuali.kpme.tklm.time.timeblock.service.TimeBlockService;
48 import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
49 import org.kuali.kpme.tklm.time.timesheet.service.TimesheetService;
50 import org.kuali.rice.core.api.config.property.ConfigContext;
51 import org.kuali.rice.kew.api.WorkflowDocument;
52 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
53 import org.kuali.rice.kim.api.identity.IdentityService;
54 import org.kuali.rice.kim.api.identity.principal.Principal;
55 import org.kuali.rice.krad.service.BusinessObjectService;
56 import org.kuali.rice.krad.service.DocumentService;
57
58 public class MissedPunchServiceImpl implements MissedPunchService {
59
60 private static final Logger LOG = Logger.getLogger(MissedPunchServiceImpl.class);
61
62 private MissedPunchDao missedPunchDao;
63
64 private AssignmentService assignmentService;
65 private BusinessObjectService businessObjectService;
66 private ClockLogService clockLogService;
67 private DocumentService documentService;
68 private IdentityService identityService;
69 private TimeBlockService timeBlockService;
70 private TimesheetService timesheetService;
71 private TimezoneService timezoneService;
72 private TkRuleControllerService tkRuleControllerService;
73
74 @Override
75 public List<MissedPunchDocument> getMissedPunchDocumentsByTimesheetDocumentId(String timesheetDocumentId) {
76 List<MissedPunchDocument> missedPunchDocuments = new ArrayList<MissedPunchDocument>();
77
78 List<MissedPunch> missedPunches = getMissedPunchDao().getMissedPunchesByTimesheetDocumentId(timesheetDocumentId);
79 for (MissedPunch missedPunch : missedPunches) {
80 MissedPunchDocument missedPunchDocument = getMissedPunchDao().getMissedPunchDocument(missedPunch.getTkMissedPunchId());
81
82 if (missedPunchDocument != null) {
83 missedPunchDocuments.add(missedPunchDocument);
84 }
85 }
86
87 return missedPunchDocuments;
88 }
89
90 @Override
91 public MissedPunch getMissedPunchByClockLogId(String clockLogId) {
92 return getMissedPunchDao().getMissedPunchByClockLogId(clockLogId);
93 }
94
95 @Override
96 public void addClockLog(MissedPunch missedPunch, String ipAddress) {
97 TimesheetDocument timesheetDocument = getTimesheetService().getTimesheetDocument(missedPunch.getTimesheetDocumentId());
98 AssignmentDescriptionKey assignmentDescriptionKey = new AssignmentDescriptionKey(missedPunch.getJobNumber(), missedPunch.getWorkArea(), missedPunch.getTask());
99 Assignment assignment = HrServiceLocator.getAssignmentService().getAssignment(missedPunch.getPrincipalId(), assignmentDescriptionKey, LocalDate.fromDateFields(missedPunch.getActionDate()));
100 CalendarEntry calendarEntry = timesheetDocument.getCalendarEntry();
101
102
103 String dateString = TKUtils.formatDateTimeShort(missedPunch.getActionFullDateTime());
104 String longDateString = TKUtils.formatDateTimeLong(missedPunch.getActionFullDateTime());
105 String timeString = TKUtils.formatTimeShort(longDateString);
106
107 DateTime dateTimeWithUserZone = TKUtils.convertDateStringToDateTime(dateString, timeString);
108 DateTime actionDateTime = dateTimeWithUserZone.withZone(TKUtils.getSystemDateTimeZone());
109
110 String clockAction = missedPunch.getClockAction();
111 String principalId = timesheetDocument.getPrincipalId();
112
113 ClockLog clockLog = getClockLogService().processClockLog(actionDateTime, assignment, calendarEntry, ipAddress, LocalDate.now(), timesheetDocument, clockAction, false, principalId);
114
115 clockLog = TkServiceLocator.getClockLogService().saveClockLog(clockLog);
116 missedPunch.setTkClockLogId(clockLog.getTkClockLogId());
117
118 if (StringUtils.equals(clockLog.getClockAction(), TkConstants.CLOCK_OUT) ||
119 StringUtils.equals(clockLog.getClockAction(), TkConstants.LUNCH_OUT)) {
120 ClockLog lastClockLog = getClockLogService().getLastClockLog(missedPunch.getPrincipalId());
121
122
123 if (!clockLog.getTkClockLogId().equals(lastClockLog.getTkClockLogId())) {
124 String earnCode = assignment.getJob().getPayTypeObj().getRegEarnCode();
125 buildTimeBlockRunRules(lastClockLog, clockLog, timesheetDocument, assignment, earnCode, lastClockLog.getClockDateTime(), clockLog.getClockDateTime());
126 }
127 }
128 }
129
130 @Override
131 public void updateClockLog(MissedPunch missedPunch, String ipAddress) {
132 DateTime actionDateTime = missedPunch.getActionFullDateTime();
133
134 ClockLog clockLog = getClockLogService().getClockLog(missedPunch.getTkClockLogId());
135 if (clockLog != null && !clockLog.getClockDateTime().equals(actionDateTime)){
136 String clockLogEndId = null;
137 String clockLogBeginId = null;
138
139 List<TimeBlock> timeBlocks = getTimeBlockService().getTimeBlocksForClockLogEndId(clockLog.getTkClockLogId());
140 if (timeBlocks.isEmpty()) {
141 timeBlocks = getTimeBlockService().getTimeBlocksForClockLogBeginId(clockLog.getTkClockLogId());
142 if (!timeBlocks.isEmpty()) {
143 clockLogEndId = timeBlocks.get(0).getClockLogEndId();
144 }
145 } else {
146 clockLogBeginId = timeBlocks.get(0).getClockLogBeginId();
147 }
148
149 deleteClockLogAndTimeBlocks(clockLog, timeBlocks);
150
151 addClockLogAndTimeBlocks(missedPunch, ipAddress, clockLogEndId, clockLogBeginId);
152 }
153 }
154
155 private void deleteClockLogAndTimeBlocks(ClockLog clockLog, List<TimeBlock> timeBlocks) {
156 getBusinessObjectService().delete(clockLog);
157
158 for (TimeBlock timeBlock : timeBlocks) {
159 getTimeBlockService().deleteTimeBlock(timeBlock);
160 }
161 }
162
163 private void addClockLogAndTimeBlocks(MissedPunch missedPunch, String ipAddress, String logEndId, String logBeginId) {
164 TimesheetDocument timesheetDocument = getTimesheetService().getTimesheetDocument(missedPunch.getTimesheetDocumentId());
165 AssignmentDescriptionKey assignmentDescriptionKey = new AssignmentDescriptionKey(missedPunch.getJobNumber(), missedPunch.getWorkArea(), missedPunch.getTask());
166 Assignment assignment = HrServiceLocator.getAssignmentService().getAssignment(missedPunch.getPrincipalId(), assignmentDescriptionKey, LocalDate.fromDateFields(missedPunch.getActionDate()));
167 CalendarEntry calendarEntry = timesheetDocument.getCalendarEntry();
168 DateTime userActionDateTime = missedPunch.getActionFullDateTime();
169 DateTimeZone userTimeZone = HrServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
170 DateTime actionDateTime = new DateTime(userActionDateTime, userTimeZone).withZone(TKUtils.getSystemDateTimeZone());
171 String clockAction = missedPunch.getClockAction();
172 String principalId = timesheetDocument.getPrincipalId();
173
174 ClockLog clockLog = getClockLogService().processClockLog(actionDateTime, assignment, calendarEntry, ipAddress, LocalDate.now(), timesheetDocument, clockAction, false, principalId);
175
176 getClockLogService().saveClockLog(clockLog);
177 missedPunch.setActionFullDateTime(clockLog.getClockDateTime());
178 missedPunch.setTkClockLogId(clockLog.getTkClockLogId());
179
180 if (logEndId != null || logBeginId != null) {
181 ClockLog endLog = null;
182 ClockLog beginLog = null;
183
184 if (logEndId != null) {
185 endLog = getClockLogService().getClockLog(logEndId);
186 } else {
187 endLog = clockLog;
188 }
189
190 if (logBeginId != null) {
191 beginLog = getClockLogService().getClockLog(logBeginId);
192 } else {
193 beginLog = clockLog;
194 }
195
196 if (beginLog != null && endLog != null && beginLog.getClockTimestamp().before(endLog.getClockTimestamp())) {
197 String earnCode = assignment.getJob().getPayTypeObj().getRegEarnCode();
198 buildTimeBlockRunRules(beginLog, endLog, timesheetDocument, assignment, earnCode, beginLog.getClockDateTime(), endLog.getClockDateTime());
199 }
200 }
201 }
202
203 @Override
204 public void approveMissedPunchDocument(MissedPunchDocument missedPunchDocument) {
205 String batchUserPrincipalId = BatchJobUtil.getBatchUserPrincipalId();
206
207 if (batchUserPrincipalId != null) {
208 String documentNumber = missedPunchDocument.getDocumentNumber();
209 WorkflowDocument wd = WorkflowDocumentFactory.loadDocument(batchUserPrincipalId, documentNumber);
210 wd.superUserBlanketApprove("Batch job superuser approving missed punch document.");
211 } else {
212 String principalName = BatchJobUtil.getBatchUserPrincipalName();
213 LOG.error("Could not approve missed punch document due to missing batch user " + principalName);
214 }
215 }
216
217
218
219
220
221 private void buildTimeBlockRunRules(ClockLog beginClockLog, ClockLog endClockLog, TimesheetDocument tdoc, Assignment currentAssignment, String earnCode, DateTime beginDateTime, DateTime endDateTime) {
222
223 List<TimeBlock> newTimeBlocks = tdoc.getTimeBlocks();
224 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>();
225 boolean createNewTb = true;
226 for (TimeBlock tb : newTimeBlocks) {
227 if(beginClockLog != null && tb.getClockLogBeginId().equals(beginClockLog.getTkClockLogId())
228 && endClockLog != null && tb.getClockLogEndId().equals(endClockLog.getTkClockLogId())) {
229
230 createNewTb = false;
231 }
232 referenceTimeBlocks.add(tb.copy());
233 }
234
235 if(createNewTb) {
236
237 List<TimeBlock> blocks = getTimeBlockService().buildTimeBlocks(
238 currentAssignment, earnCode, tdoc, beginDateTime,
239 endDateTime, BigDecimal.ZERO, BigDecimal.ZERO, true, false, HrContext.getPrincipalId(),
240 beginClockLog != null ? beginClockLog.getTkClockLogId() : null,
241 endClockLog != null ? endClockLog.getTkClockLogId() : null);
242
243 newTimeBlocks.addAll(blocks);
244 }
245
246 List<Assignment> assignments = tdoc.getAssignments();
247 List<String> assignmentKeys = new ArrayList<String>();
248 for (Assignment assignment : assignments) {
249 assignmentKeys.add(assignment.getAssignmentKey());
250 }
251 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(tdoc.getPrincipalId(), tdoc.getAsOfDate(), tdoc.getDocEndDate(), assignmentKeys);
252
253
254 getTimesheetService().resetTimeBlock(newTimeBlocks, tdoc.getAsOfDate());
255
256 getTkRuleControllerService().applyRules(
257 TkConstants.ACTIONS.CLOCK_OUT, newTimeBlocks, leaveBlocks,
258 tdoc.getCalendarEntry(),
259 tdoc, tdoc.getPrincipalId()
260 );
261
262 getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, HrContext.getPrincipalId());
263 }
264
265 public MissedPunchDao getMissedPunchDao() {
266 return missedPunchDao;
267 }
268
269 public void setMissedPunchDao(MissedPunchDao missedPunchDao) {
270 this.missedPunchDao = missedPunchDao;
271 }
272
273 public AssignmentService getAssignmentService() {
274 return assignmentService;
275 }
276
277 public void setAssignmentService(AssignmentService assignmentService) {
278 this.assignmentService = assignmentService;
279 }
280
281 public BusinessObjectService getBusinessObjectService() {
282 return businessObjectService;
283 }
284
285 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
286 this.businessObjectService = businessObjectService;
287 }
288
289 public ClockLogService getClockLogService() {
290 return clockLogService;
291 }
292
293 public void setClockLogService(ClockLogService clockLogService) {
294 this.clockLogService = clockLogService;
295 }
296
297 public DocumentService getDocumentService() {
298 return documentService;
299 }
300
301 public void setDocumentService(DocumentService documentService) {
302 this.documentService = documentService;
303 }
304
305 public IdentityService getIdentityService() {
306 return identityService;
307 }
308
309 public void setIdentityService(IdentityService identityService) {
310 this.identityService = identityService;
311 }
312
313 public TimeBlockService getTimeBlockService() {
314 return timeBlockService;
315 }
316
317 public void setTimeBlockService(TimeBlockService timeBlockService) {
318 this.timeBlockService = timeBlockService;
319 }
320
321 public TimesheetService getTimesheetService() {
322 return timesheetService;
323 }
324
325 public void setTimesheetService(TimesheetService timesheetService) {
326 this.timesheetService = timesheetService;
327 }
328
329 public TimezoneService getTimezoneService() {
330 return timezoneService;
331 }
332
333 public void setTimezoneService(TimezoneService timezoneService) {
334 this.timezoneService = timezoneService;
335 }
336
337 public TkRuleControllerService getTkRuleControllerService() {
338 return tkRuleControllerService;
339 }
340
341 public void setTkRuleControllerService(TkRuleControllerService tkRuleControllerService) {
342 this.tkRuleControllerService = tkRuleControllerService;
343 }
344
345 @Override
346 public MissedPunchDocument getMissedPunchDocumentByMissedPunchId(String tkMissedPunchId) {
347 return missedPunchDao.getMissedPunchDocument(tkMissedPunchId);
348 }
349
350 }