1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.kpme.tklm.time.clock.web;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.struts.action.ActionForm;
21 import org.apache.struts.action.ActionForward;
22 import org.apache.struts.action.ActionMapping;
23 import org.joda.time.DateTime;
24 import org.joda.time.DateTimeZone;
25 import org.joda.time.Interval;
26 import org.joda.time.LocalDate;
27 import org.joda.time.format.DateTimeFormat;
28 import org.joda.time.format.DateTimeFormatter;
29 import org.json.simple.JSONArray;
30 import org.json.simple.JSONValue;
31 import org.kuali.kpme.core.api.assignment.Assignment;
32 import org.kuali.kpme.core.api.assignment.AssignmentDescriptionKey;
33 import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
34 import org.kuali.kpme.core.api.earncode.EarnCodeContract;
35 import org.kuali.kpme.core.api.namespace.KPMENamespace;
36 import org.kuali.kpme.core.api.workarea.WorkArea;
37 import org.kuali.kpme.core.document.calendar.CalendarDocument;
38 import org.kuali.kpme.core.role.KPMERole;
39 import org.kuali.kpme.core.service.HrServiceLocator;
40 import org.kuali.kpme.core.util.HrConstants;
41 import org.kuali.kpme.core.util.HrContext;
42 import org.kuali.kpme.core.util.TKUtils;
43 import org.kuali.kpme.tklm.api.common.TkConstants;
44 import org.kuali.kpme.tklm.api.leave.block.LeaveBlock;
45 import org.kuali.kpme.tklm.api.time.clocklog.ClockLog;
46 import org.kuali.kpme.tklm.api.time.timeblock.TimeBlock;
47 import org.kuali.kpme.tklm.time.clocklog.exception.InvalidClockLogException;
48 import org.kuali.kpme.tklm.time.rules.lunch.department.DeptLunchRule;
49 import org.kuali.kpme.tklm.time.service.TkServiceLocator;
50 import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
51 import org.kuali.kpme.tklm.time.timesheet.web.TimesheetAction;
52 import org.kuali.kpme.tklm.time.workflow.TimesheetDocumentHeader;
53 import org.kuali.rice.core.api.config.property.ConfigContext;
54 import org.kuali.rice.core.api.util.Truth;
55 import org.kuali.rice.krad.exception.AuthorizationException;
56 import org.kuali.rice.krad.util.GlobalVariables;
57
58 import javax.servlet.http.HttpServletRequest;
59 import javax.servlet.http.HttpServletResponse;
60 import java.math.BigDecimal;
61 import java.text.SimpleDateFormat;
62 import java.util.*;
63
64 public class ClockAction extends TimesheetAction {
65
66 public static final SimpleDateFormat SDF = new SimpleDateFormat("EEE, MMMM d yyyy HH:mm:ss, zzzz");
67 public static final String SEPERATOR = "[****]+";
68 public static final String DOCUMENT_NOT_INITIATE_ERROR = "New Timesheet document could not be found. Please initiate the document first.";
69 public static final String TIME_BLOCK_OVERLAP_ERROR = "User has already logged time for this clock period.";
70
71
72 @Override
73 protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
74 super.checkTKAuthorization(form, methodToCall);
75
76 ClockActionForm clockActionForm = (ClockActionForm) form;
77
78 String principalId = GlobalVariables.getUserSession().getPrincipalId();
79 CalendarDocument timesheetDocument = TkServiceLocator.getTimesheetService().getTimesheetDocument(clockActionForm.getDocumentId());
80
81 if (StringUtils.equals(methodToCall, "clockAction") ||
82 StringUtils.equals(methodToCall, "addTimeBlock") ||
83 StringUtils.equals(methodToCall, "editTimeBlock") ||
84 StringUtils.equals(methodToCall, "distributeTimeBlocks") ||
85 StringUtils.equals(methodToCall, "saveNewTimeBlocks") ||
86 StringUtils.equals(methodToCall, "deleteTimeBlock")) {
87 if (!HrServiceLocator.getHRPermissionService().canEditCalendarDocument(principalId, timesheetDocument)) {
88 throw new AuthorizationException(GlobalVariables.getUserSession().getPrincipalId(), "ClockAction", "");
89 }
90 }
91 }
92
93
94 @Override
95 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
96 ActionForward actionForward = super.execute(mapping, form, request, response);
97
98 ClockActionForm clockActionForm = (ClockActionForm) form;
99
100 TimesheetDocument timesheetDocument = clockActionForm.getTimesheetDocument();
101 clockActionForm.setShowClockButton(true);
102 if (timesheetDocument != null) {
103 DateTimeFormatter formatter = DateTimeFormat.forPattern("MM/dd/yyyy");
104 String fromDateString = formatter.print(timesheetDocument.getCalendarEntry().getBeginPeriodLocalDateTime());
105 String toDateString = formatter.print(timesheetDocument.getCalendarEntry().getEndPeriodLocalDateTime());
106
107 clockActionForm.setDistributionPeriod(fromDateString +" - "+toDateString);
108 if (!timesheetDocument.getDocumentHeader().getDocumentStatus().equals(HrConstants.ROUTE_STATUS.ENROUTE)
109 && !timesheetDocument.getDocumentHeader().getDocumentStatus().equals(HrConstants.ROUTE_STATUS.FINAL)) {
110
111 String targetPrincipalId = HrContext.getTargetPrincipalId();
112 if (targetPrincipalId != null) {
113 clockActionForm.setPrincipalId(targetPrincipalId);
114 }
115
116 if (StringUtils.equals(GlobalVariables.getUserSession().getPrincipalId(), HrContext.getTargetPrincipalId())) {
117 clockActionForm.setAssignmentDescriptions(timesheetDocument.getAssignmentDescriptions(true, LocalDate.now()));
118 } else {
119 clockActionForm.setAssignmentDescriptions(timesheetDocument.getAssignmentDescriptionsOfApprovals(true));
120 }
121
122 String ipAddress = TKUtils.getIPAddressFromRequest(request);
123 Map<String, String> assignmentMap = timesheetDocument.getAssignmentDescriptions(true, LocalDate.now());
124 String principalId = HrContext.getPrincipalId();
125
126 if(StringUtils.equals(targetPrincipalId, principalId)){
127 Map<String, String> assignmentDescriptionMap = new TreeMap<String, String>();
128
129 DateTime currentDateTime = new DateTime();
130 for (Map.Entry<String, String> entry : assignmentMap.entrySet()) {
131 Assignment assignment = timesheetDocument.getAssignment(AssignmentDescriptionKey.get(entry.getKey()), LocalDate.now());
132 String allowActionFromInvalidLocation = ConfigContext.getCurrentContextConfig().getProperty(TkConstants.ALLOW_CLOCKING_EMPLOYEE_FROM_INVALID_LOCATION);
133 if(!Truth.strToBooleanIgnoreCase(allowActionFromInvalidLocation)) {
134 boolean isInValid = TkServiceLocator.getClockLocationRuleService().isInvalidIPClockLocation(assignment.getGroupKeyCode(), assignment.getDept(), assignment.getWorkArea(), assignment.getPrincipalId(), assignment.getJobNumber(), ipAddress, currentDateTime.toLocalDate());
135 if (!isInValid) {
136 assignmentDescriptionMap.put(entry.getKey(), entry.getValue());
137 }
138 } else {
139 assignmentDescriptionMap.put(entry.getKey(), entry.getValue());
140 }
141 }
142 clockActionForm.setAssignmentDescriptions(assignmentDescriptionMap);
143 }else{
144 clockActionForm.setAssignmentDescriptions(assignmentMap);
145 }
146
147 if (clockActionForm.getEditTimeBlockId() != null) {
148 clockActionForm.setCurrentTimeBlock(TkServiceLocator.getTimeBlockService().getTimeBlock(clockActionForm.getEditTimeBlockId()));
149 }
150
151 ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog(targetPrincipalId);
152 if (lastClockLog != null) {
153 DateTime lastClockDateTime = lastClockLog.getClockDateTime();
154 String lastClockZone = lastClockLog.getClockTimestampTimezone();
155 if (StringUtils.isEmpty(lastClockZone)) {
156 lastClockZone = TKUtils.getSystemTimeZone();
157 }
158
159
160
161 DateTimeZone zone = DateTimeZone.forID(lastClockZone);
162 DateTime clockWithZone = lastClockDateTime.withZone(zone);
163 clockActionForm.setLastClockTimeWithZone(clockWithZone.toDate());
164 clockActionForm.setLastClockTimestamp(lastClockDateTime.toDate());
165 clockActionForm.setLastClockAction(lastClockLog.getClockAction());
166 }
167
168 if (lastClockLog == null || StringUtils.equals(lastClockLog.getClockAction(), TkConstants.CLOCK_OUT)) {
169 clockActionForm.setCurrentClockAction(TkConstants.CLOCK_IN);
170 } else {
171
172
173 if (StringUtils.equals(lastClockLog.getClockAction(), TkConstants.LUNCH_OUT)) {
174 clockActionForm.setCurrentClockAction(TkConstants.LUNCH_IN);
175 clockActionForm.setShowClockButton(false);
176 } else {
177 clockActionForm.setCurrentClockAction(TkConstants.CLOCK_OUT);
178 }
179
180 String selectedAssignment = new AssignmentDescriptionKey(lastClockLog.getGroupKeyCode(), lastClockLog.getJobNumber(), lastClockLog.getWorkArea(), lastClockLog.getTask()).toAssignmentKeyString();
181 clockActionForm.setSelectedAssignment(selectedAssignment);
182 Assignment assignment = timesheetDocument.getAssignment(AssignmentDescriptionKey.get(selectedAssignment), LocalDate.now());
183 Map<String, String> assignmentDesc = HrServiceLocator.getAssignmentService().getAssignmentDescriptions(assignment);
184 clockActionForm.setAssignmentDescriptions(assignmentDesc);
185 }
186
187
188
189
190
191
192
193
194 if (StringUtils.equals(GlobalVariables.getUserSession().getPrincipalId(), HrContext.getTargetPrincipalId())) {
195 clockActionForm.setClockButtonEnabled(true);
196 clockActionForm.setProxyClockAction(false);
197 } else {
198 clockActionForm.setProxyClockAction(true);
199 clockActionForm.setProxyClockActionTargetUser(HrContext.getTargetName());
200 boolean isApproverOrReviewerForCurrentAssignment = false;
201 String selectedAssignment = StringUtils.EMPTY;
202 if (clockActionForm.getAssignmentDescriptions() != null) {
203 if (clockActionForm.getAssignmentDescriptions().size() == 1) {
204 for (String assignment : clockActionForm.getAssignmentDescriptions().keySet()) {
205 selectedAssignment = assignment;
206 }
207 } else {
208 selectedAssignment = clockActionForm.getSelectedAssignment();
209 }
210 }
211
212 if(StringUtils.isNotBlank(selectedAssignment)) {
213 Assignment assignment = HrServiceLocator.getAssignmentService().getAssignmentForTargetPrincipal(AssignmentDescriptionKey.get(selectedAssignment), LocalDate.now());
214 if (assignment != null) {
215 Long workArea = assignment.getWorkArea();
216 String dept = assignment.getJob().getDept();
217 String groupKeyCode = assignment.getJob().getGroupKeyCode();
218
219
220
221 DateTime startOfToday = LocalDate.now().toDateTimeAtStartOfDay();
222
223 String location = HrServiceLocator.getHrGroupKeyService().getHrGroupKey(groupKeyCode, startOfToday.toLocalDate()).getLocationId();
224
225
226 isApproverOrReviewerForCurrentAssignment =
227 HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER.getRoleName(), workArea, startOfToday)
228
229 || HrServiceLocator.getKPMERoleService().principalHasRole(principalId, KPMENamespace.KPME_TK.getNamespaceCode(), KPMERole.TIME_SYSTEM_ADMINISTRATOR.getRoleName(), startOfToday)
230 || HrServiceLocator.getKPMERoleService().principalHasRoleInLocation(principalId, KPMENamespace.KPME_TK.getNamespaceCode(), KPMERole.TIME_LOCATION_ADMINISTRATOR.getRoleName(), location, startOfToday)
231
232 || HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER_DELEGATE.getRoleName(), workArea, startOfToday)
233 || HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.REVIEWER.getRoleName(), workArea, startOfToday)
234 || HrServiceLocator.getKPMERoleService().principalHasRoleInDepartment(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR.getRoleName(), dept, groupKeyCode, startOfToday)
235 || HrServiceLocator.getKPMERoleService().principalHasRoleInDepartment(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR_DELEGATE.getRoleName(), dept, groupKeyCode, startOfToday);
236 }
237 } else {
238 if (CollectionUtils.isNotEmpty(clockActionForm.getAssignmentDescriptions().entrySet())) {
239
240 isApproverOrReviewerForCurrentAssignment = true;
241 }
242
243 }
244 clockActionForm.setClockButtonEnabled(isApproverOrReviewerForCurrentAssignment);
245 }
246
247
248
249
250 clockActionForm.setShowLunchButton(false);
251 assignShowDistributeButton(clockActionForm);
252
253 if (clockActionForm.isShowLunchButton()) {
254
255
256
257
258 Map<String, Boolean> assignmentDeptLunchRuleMap = new HashMap<String, Boolean>();
259 for (Assignment a : timesheetDocument.getAssignmentMap().get(LocalDate.now())) {
260 String key = AssignmentDescriptionKey.getAssignmentKeyString(a);
261 DeptLunchRule deptLunchRule = TkServiceLocator.getDepartmentLunchRuleService().getDepartmentLunchRule(a.getDept(), a.getWorkArea(), clockActionForm.getPrincipalId(), a.getJobNumber(), a.getGroupKeyCode(), LocalDate.now());
262 assignmentDeptLunchRuleMap.put(key, deptLunchRule != null);
263 }
264 clockActionForm.setAssignmentLunchMap(assignmentDeptLunchRuleMap);
265 }
266 } else {
267 clockActionForm.setErrorMessage("Your current timesheet is already submitted for Approval. Clock action is not allowed on this timesheet.");
268 }
269 }
270
271 return actionForward;
272 }
273
274 public void assignShowDistributeButton(ClockActionForm caf) {
275 caf.setShowDistrubuteButton(false);
276
277 TimesheetDocument timesheetDocument = caf.getTimesheetDocument();
278 List<Assignment> listOfAssignments = caf.getTimesheetDocument().getAssignmentMap().get(LocalDate.now());
279 if(listOfAssignments == null || listOfAssignments.isEmpty()) {
280 listOfAssignments = caf.getTimesheetDocument().getAssignmentMap().get(timesheetDocument.getDocEndDate());
281 }
282 if (timesheetDocument != null && listOfAssignments != null) {
283 int eligibleAssignmentCount = 0;
284 for (Assignment a : listOfAssignments) {
285 WorkArea aWorkArea = HrServiceLocator.getWorkAreaService().getWorkArea(a.getWorkArea(), timesheetDocument.getDocEndDate());
286 if(aWorkArea != null && aWorkArea.isHrsDistributionF()) {
287 eligibleAssignmentCount++;
288 }
289
290
291 if (eligibleAssignmentCount > 1) {
292 caf.setShowDistrubuteButton(true);
293 break;
294 }
295 }
296 }
297 }
298
299 public ActionForward clockAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception, InvalidClockLogException {
300 ClockActionForm caf = (ClockActionForm) form;
301 DateTime currentDateTime = new DateTime();
302
303
304 if (StringUtils.isBlank(caf.getSelectedAssignment())) {
305 caf.setErrorMessage("No assignment selected.");
306 return mapping.findForward("basic");
307 }
308 String pId = HrContext.getTargetPrincipalId();
309 ClockLog previousClockLog = TkServiceLocator.getClockLogService().getLastClockLog(pId);
310 if(previousClockLog != null && StringUtils.equals(caf.getCurrentClockAction(), previousClockLog.getClockAction())){
311 caf.setErrorMessage("The operation is already performed.");
312 return mapping.findForward("basic");
313 }
314 String ip = TKUtils.getIPAddressFromRequest(request);
315
316 Assignment assignment = caf.getTimesheetDocument().getAssignment(AssignmentDescriptionKey.get(caf.getSelectedAssignment()), LocalDate.now());
317 Long jbNum = assignment.getJobNumber();
318 Long wa = assignment.getWorkArea();
319 String dept= assignment.getDept();
320 String grpKeyCode = assignment.getGroupKeyCode();
321
322 try {
323 if (StringUtils.equals(pId, HrContext.getPrincipalId())) {
324 TkServiceLocator.getClockLogService().invalidIpCheck(grpKeyCode, dept, wa, pId, jbNum, ip, LocalDate.now(), false);
325 }
326 }
327 catch (InvalidClockLogException e)
328 {
329 caf.setErrorMessage("Could not take the action as Action taken from "+ ip + ", is not a valid IP address.");
330 return mapping.findForward("basic");
331 }
332
333
334 if (pId.equalsIgnoreCase(HrContext.getPrincipalId())) {
335 String allowActionFromInvalidLocaiton = ConfigContext.getCurrentContextConfig().getProperty(TkConstants.ALLOW_CLOCKING_EMPLOYEE_FROM_INVALID_LOCATION);
336 if(StringUtils.equals(allowActionFromInvalidLocaiton, "false")) {
337 boolean isInValid = TkServiceLocator.getClockLocationRuleService().isInvalidIPClockLocation(assignment.getGroupKeyCode(), assignment.getDept(), assignment.getWorkArea(), assignment.getPrincipalId(), assignment.getJobNumber(), ip, currentDateTime.toLocalDate());
338 if(isInValid){
339 caf.setErrorMessage("Could not take the action as Action taken from "+ ip + ", is not a valid IP address.");
340 return mapping.findForward("basic");
341 }
342 }
343 }
344
345 List<Assignment> lstAssingmentAsOfToday = HrServiceLocator.getAssignmentService().getAssignments(pId, LocalDate.now());
346 boolean foundValidAssignment = false;
347 for(Assignment assign : lstAssingmentAsOfToday){
348 if((assign.getJobNumber().compareTo(assignment.getJobNumber()) ==0) &&
349 (assign.getWorkArea().compareTo(assignment.getWorkArea()) == 0) &&
350 (assign.getTask().compareTo(assignment.getTask()) == 0)){
351 foundValidAssignment = true;
352 break;
353 }
354 }
355
356 if(!foundValidAssignment){
357 caf.setErrorMessage("Assignment is not effective as of today");
358 return mapping.findForward("basic");
359 }
360
361 LocalDate beginDate = LocalDate.now();
362 DateTime clockTimeWithGraceRule = new DateTime(beginDate.toDateTimeAtCurrentTime());
363 clockTimeWithGraceRule = TkServiceLocator.getGracePeriodService().processGracePeriodRule(clockTimeWithGraceRule, beginDate);
364
365
366 if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_IN) || StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_IN) || StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_OUT) || StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_OUT)) {
367 ClockLog lastLog = null;
368 if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_IN)) {
369 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(pId, TkConstants.LUNCH_OUT);
370 } else if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_IN)) {
371 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(pId);
372 }else if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_OUT)) {
373 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(pId, TkConstants.LUNCH_IN);
374 } else if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_OUT)) {
375 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(pId);
376 }
377 if (lastLog != null) {
378 if (lastLog.getClockDateTime().withMillisOfSecond(0).equals(clockTimeWithGraceRule.withMillisOfSecond(0))) {
379 clockTimeWithGraceRule = clockTimeWithGraceRule.withMillisOfSecond(lastLog.getClockDateTime().getMillisOfSecond() + 1);
380 }
381 }
382 Set<String> regularEarnCodes = new HashSet<String>();
383 for(Assignment assign : caf.getTimesheetDocument().getAllAssignments()) {
384 regularEarnCodes.add(assign.getJob().getPayTypeObj().getRegEarnCode());
385 }
386 List<TimeBlock> tbList = caf.getTimesheetDocument().getTimeBlocks();
387 for(TimeBlock tb : tbList) {
388 String earnCode = tb.getEarnCode();
389 boolean isRegularEarnCode = StringUtils.equals(assignment.getJob().getPayTypeObj().getRegEarnCode(), earnCode);
390 EarnCodeContract earnCodeObj = HrServiceLocator.getEarnCodeService().getEarnCode(earnCode, caf.getTimesheetDocument().getAsOfDate());
391 if(earnCodeObj != null && HrConstants.EARN_CODE_TIME.equals(earnCodeObj.getEarnCodeType())) {
392 Interval clockInterval = new Interval(tb.getBeginDateTime(), tb.getEndDateTime());
393 if((isRegularEarnCode || regularEarnCodes.contains(earnCodeObj.getEarnCode())) && clockInterval.contains(clockTimeWithGraceRule.getMillis())) {
394 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
395 return mapping.findForward("basic");
396 }else if(StringUtils.equals(caf.getCurrentClockAction(),TkConstants.CLOCK_OUT) || StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_OUT) && (isRegularEarnCode || regularEarnCodes.contains(earnCodeObj.getEarnCode()))){
397 Interval currentClockInterval = new Interval(lastLog.getClockDateTime(),clockTimeWithGraceRule);
398 if(clockInterval.contains(currentClockInterval) || currentClockInterval.contains(clockInterval)){
399 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
400 return mapping.findForward("basic");
401 }
402 }
403 }
404 }
405 }
406
407
408
409
410
411
412 if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_OUT) || StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_OUT)) {
413 ClockLog lastLog = null;
414 String inAction = "";
415 String outAction = "";
416 if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_OUT)) {
417 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(pId, TkConstants.CLOCK_IN);
418 inAction = TkConstants.LUNCH_IN;
419 outAction = TkConstants.LUNCH_OUT;
420 } else if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_OUT)) {
421 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(pId);
422 inAction = TkConstants.CLOCK_IN;
423 outAction = TkConstants.CLOCK_OUT;
424 }
425
426 TimesheetDocument previousTimeDoc = TkServiceLocator.getTimesheetService().getTimesheetDocument(previousClockLog.getDocumentId());
427
428
429
430 if (StringUtils.equals(((ClockActionForm) form).getDocumentId(),previousTimeDoc.getDocumentId())) {
431 DateTime currentCalendarEntryBeginDate = ((ClockActionForm) form).getTimesheetDocument().getCalendarEntry().getBeginPeriodFullDateTime();
432 DateTime currentCalendarEntryEndDate = ((ClockActionForm) form).getTimesheetDocument().getCalendarEntry().getEndPeriodFullDateTime();
433
434 Interval currentCalendarInterval = new Interval(currentCalendarEntryBeginDate,currentCalendarEntryEndDate);
435 DateTimeZone userTimeZone = DateTimeZone.forID(HrServiceLocator.getTimezoneService().getUserTimezone(pId));
436 DateTimeZone systemTimeZone = TKUtils.getSystemDateTimeZone();
437
438 if (!currentCalendarInterval.contains(TKUtils.convertDateTimeToDifferentTimezone(previousClockLog.getClockDateTime(), systemTimeZone, userTimeZone))) {
439 TimesheetDocumentHeader prevTdh = TkServiceLocator.getTimesheetDocumentHeaderService().getPreviousDocumentHeader(pId,currentCalendarEntryBeginDate);
440 if (prevTdh != null) {
441 previousTimeDoc = TkServiceLocator.getTimesheetService().getTimesheetDocument(prevTdh.getDocumentId());
442 }
443 }
444 }
445
446 if(previousTimeDoc != null) {
447 CalendarEntry previousCalEntry = previousTimeDoc.getCalendarEntry();
448 DateTime previousEndPeriodDateTime = previousCalEntry.getEndPeriodFullDateTime();
449
450 DateTimeZone userTimezone = DateTimeZone.forID(HrServiceLocator.getTimezoneService().getUserTimezone(pId));
451 DateTimeZone systemTimeZone = TKUtils.getSystemDateTimeZone();
452
453 DateTime outLogDateTime = TKUtils.convertTimeForDifferentTimeZone(previousEndPeriodDateTime, systemTimeZone, userTimezone);
454
455
456 if(currentDateTime.isAfter(outLogDateTime.getMillis())) {
457 CalendarEntry nextCalendarEntry = HrServiceLocator.getCalendarEntryService().getNextCalendarEntryByCalendarId(previousCalEntry.getHrCalendarId(), previousCalEntry);
458 DateTime beginNextPeriodDateTime = nextCalendarEntry.getBeginPeriodFullDateTime();
459
460 DateTime inLogDateTime = TKUtils.convertDateTimeToDifferentTimezone(beginNextPeriodDateTime, userTimezone, systemTimeZone);
461
462 TimesheetDocumentHeader nextTdh = TkServiceLocator.getTimesheetDocumentHeaderService()
463 .getDocumentHeader(pId, nextCalendarEntry.getBeginPeriodFullDateTime(), nextCalendarEntry.getEndPeriodFullDateTime());
464 if(nextTdh == null) {
465 caf.setErrorMessage(DOCUMENT_NOT_INITIATE_ERROR);
466 return mapping.findForward("basic");
467 }
468 TimesheetDocument nextTimeDoc = TkServiceLocator.getTimesheetService().getTimesheetDocument(nextTdh.getDocumentId());
469 if(nextTimeDoc == null) {
470 caf.setErrorMessage(DOCUMENT_NOT_INITIATE_ERROR);
471 return mapping.findForward("basic");
472 }
473
474 if (lastLog != null) {
475
476
477 DateTime endDateTime = new DateTime(outLogDateTime.getMillis());
478 endDateTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(outLogDateTime, previousCalEntry.getBeginPeriodFullDateTime().toLocalDate());
479
480
481
482 if (lastLog.getClockDateTime().withMillisOfSecond(0).equals(endDateTime.withMillisOfSecond(0))) {
483 endDateTime = endDateTime.withMillisOfSecond(lastLog.getClockDateTime().getMillisOfSecond() + 1);
484 }
485 boolean validation = this.validateOverlapping(previousTimeDoc.getAsOfDate(), previousTimeDoc.getTimeBlocks(), lastLog.getClockDateTime(), endDateTime,assignment);
486 if(!validation) {
487 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
488 return mapping.findForward("basic");
489 }
490
491
492
493 endDateTime = currentDateTime;
494 endDateTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(currentDateTime, nextCalendarEntry.getBeginPeriodFullDateTime().toLocalDate());
495
496
497
498
499 if (lastLog.getClockDateTime().withMillisOfSecond(0).equals(endDateTime.withMillisOfSecond(0))) {
500 endDateTime = endDateTime.withMillisOfSecond(lastLog.getClockDateTime().getMillisOfSecond() + 1);
501 }
502 validation = this.validateOverlapping(nextTimeDoc.getAsOfDate(), nextTimeDoc.getTimeBlocks(), inLogDateTime, endDateTime,assignment);
503 if(!validation) {
504 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
505 return mapping.findForward("basic");
506 }
507 }
508
509
510 ClockLog outLog = TkServiceLocator.getClockLogService().processClockLog(pId, previousTimeDoc.getDocumentId(), outLogDateTime, assignment, previousCalEntry, ip,
511 previousEndPeriodDateTime.toLocalDate(), outAction, true);
512
513
514 ClockLog inLog = TkServiceLocator.getClockLogService().processClockLog(pId, nextTimeDoc.getDocumentId(), inLogDateTime, assignment, nextCalendarEntry, ip,
515 beginNextPeriodDateTime.toLocalDate(), inAction, true);
516
517
518 ClockLog finalOutLog = TkServiceLocator.getClockLogService().processClockLog(pId, nextTimeDoc.getDocumentId(), currentDateTime, assignment, nextCalendarEntry, ip,
519 currentDateTime.toLocalDate(), caf.getCurrentClockAction(), true);
520
521
522 ClockLog.Builder clBuilder = ClockLog.Builder.create(finalOutLog);
523 clBuilder.setCreateTime(finalOutLog.getCreateTime().plusSeconds(5));
524 finalOutLog = TkServiceLocator.getClockLogService().saveClockLog(clBuilder.build());
525
526 caf.setClockLog(finalOutLog);
527 return mapping.findForward("basic");
528
529 } else {
530 if (lastLog != null) {
531
532 DateTime endDateTime = new DateTime();
533 endDateTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(endDateTime, caf.getCalendarEntry().getBeginPeriodFullDateTime().toLocalDate());
534 if (lastLog.getClockDateTime().withMillisOfSecond(0).equals(endDateTime.withMillisOfSecond(0))) {
535 endDateTime = endDateTime.withMillisOfSecond(lastLog.getClockDateTime().getMillisOfSecond() + 1);
536 }
537
538
539
540
541
542
543
544 boolean validation = this.validateOverlapping(caf.getTimesheetDocument().getAsOfDate(), caf.getTimesheetDocument().getTimeBlocks(), lastLog.getClockDateTime(), endDateTime,assignment);
545 if(!validation) {
546 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
547 return mapping.findForward("basic");
548 }
549 }
550 }
551 }
552 }
553
554 ClockLog clockLog = TkServiceLocator.getClockLogService().processClockLog(pId, caf.getTimesheetDocument().getDocumentId(), new DateTime(), assignment, caf.getCalendarEntry(), ip,
555 beginDate, caf.getCurrentClockAction(), true);
556
557 caf.setClockLog(clockLog);
558 return mapping.findForward("basic");
559
560 }
561
562 public boolean validateOverlapping(LocalDate asOfDate, List<TimeBlock> tbList, DateTime beginDateTime, DateTime endDateTime, Assignment assignment) {
563 Interval clockInterval = new Interval(beginDateTime, endDateTime);
564 if(clockInterval != null) {
565 for(TimeBlock tb : tbList) {
566 String earnCode = tb.getEarnCode();
567 boolean isRegularEarnCode = StringUtils.equals(assignment.getJob().getPayTypeObj().getRegEarnCode(),earnCode);
568 EarnCodeContract earnCodeObj = HrServiceLocator.getEarnCodeService().getEarnCode(earnCode, asOfDate);
569 if(isRegularEarnCode && earnCodeObj != null && HrConstants.EARN_CODE_TIME.equals(earnCodeObj.getEarnCodeType())) {
570 if(clockInterval.overlaps(new Interval(tb.getBeginDateTime(), tb.getEndDateTime()))) {
571 return false;
572 }
573 }
574 }
575 return true;
576 }
577 return false;
578 }
579
580
581 public ActionForward distributeTimeBlocks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
582 ClockActionForm caf = (ClockActionForm) form;
583 caf.findTimeBlocksToDistribute();
584 return mapping.findForward("tb");
585 }
586
587
588 public ActionForward editTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
589 ClockActionForm caf = (ClockActionForm) form;
590 TimeBlock tb = caf.getCurrentTimeBlock();
591 caf.setCurrentAssignmentKey(tb.getAssignmentKey());
592 caf.populateAssignmentsForSelectedTimeBlock(tb);
593 ActionForward forward = mapping.findForward("et");
594
595 return new ActionForward(forward.getPath() + "?editTimeBlockId=" + tb.getTkTimeBlockId().toString());
596
597 }
598 public ActionForward addTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
599 ClockActionForm caf = (ClockActionForm) form;
600 TimeBlock currentTb = caf.getCurrentTimeBlock();
601 List<TimeBlock> newTimeBlocks = caf.getTimesheetDocument().getTimeBlocks();
602 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(caf.getTimesheetDocument().getTimeBlocks().size());
603 for (TimeBlock tb : caf.getTimesheetDocument().getTimeBlocks()) {
604 referenceTimeBlocks.add(TimeBlock.Builder.create(tb).build());
605 }
606
607 TkServiceLocator.getTimeBlockService().saveOrUpdateTimeBlocks(referenceTimeBlocks, newTimeBlocks, HrContext.getPrincipalId());
608
609 ActionForward forward = mapping.findForward("et");
610
611 return new ActionForward(forward.getPath() + "?editTimeBlockId=" + currentTb.getTkTimeBlockId().toString());
612 }
613
614 public ActionForward saveNewTimeBlocks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
615 ClockActionForm caf = (ClockActionForm)form;
616 String tbId = caf.getTbId();
617 String timesheetDocId = caf.getTsDocId();
618
619 String[] assignments = caf.getNewAssignDesCol().split(SEPERATOR);
620 String[] beginDates = caf.getNewBDCol().split(SEPERATOR);
621 String[] beginTimes = caf.getNewBTCol().split(SEPERATOR);
622 String[] endDates = caf.getNewEDCol().split(SEPERATOR);
623 String[] endTimes = caf.getNewETCol().split(SEPERATOR);
624 String[] hrs = caf.getNewHrsCol().split(SEPERATOR);
625 String earnCode = TkServiceLocator.getTimeBlockService().getTimeBlock(tbId).getEarnCode();
626 TimesheetDocument tsDoc = TkServiceLocator.getTimesheetService().getTimesheetDocument(timesheetDocId);
627 List<TimeBlock> newTbList = new ArrayList<TimeBlock>();
628 if(tsDoc != null) {
629 for(TimeBlock oldTB : tsDoc.getTimeBlocks()) {
630 if(!(oldTB.getTkTimeBlockId().compareTo(tbId) == 0)) {
631 newTbList.add(oldTB);
632 }
633 }
634 }
635 for(int i = 0; i < hrs.length; i++) {
636 BigDecimal hours = new BigDecimal(hrs[i]);
637 DateTime beginDateTime = TKUtils.convertDateStringToDateTime(beginDates[i], beginTimes[i]);
638 DateTime endDateTime = TKUtils.convertDateStringToDateTime(endDates[i], endTimes[i]);
639 String assignString = assignments[i];
640 Assignment assignment = HrServiceLocator.getAssignmentService().getAssignment(assignString);
641
642 TimeBlock tb = TkServiceLocator.getTimeBlockService().createTimeBlock(tsDoc.getPrincipalId(), tsDoc.getDocumentId(), beginDateTime, endDateTime, assignment, earnCode, hours,BigDecimal.ZERO, false, false, HrContext.getPrincipalId());
643 newTbList.add(tb);
644 }
645 TkServiceLocator.getTimeBlockService().resetTimeHourDetail(newTbList);
646
647 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTbList, Collections.<LeaveBlock>emptyList(), tsDoc.getCalendarEntry(), tsDoc, tsDoc.getPrincipalId());
648
649 TkServiceLocator.getTimeBlockService().saveTimeBlocks(newTbList);
650 TimeBlock oldTB = TkServiceLocator.getTimeBlockService().getTimeBlock(tbId);
651 TkServiceLocator.getTimeBlockService().deleteTimeBlockAndHandleMissedPunch(oldTB, true);
652 return mapping.findForward("basic");
653 }
654
655 public ActionForward validateNewTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
656 ClockActionForm caf = (ClockActionForm)form;
657 String tbId = caf.getTbId();
658 String[] assignments = caf.getNewAssignDesCol().split(SEPERATOR);
659 String[] beginDates = caf.getNewBDCol().split(SEPERATOR);
660 String[] beginTimes = caf.getNewBTCol().split(SEPERATOR);
661 String[] endDates = caf.getNewEDCol().split(SEPERATOR);
662 String[] endTimes = caf.getNewETCol().split(SEPERATOR);
663 String[] hrs = caf.getNewHrsCol().split(SEPERATOR);
664
665 List<Interval> newIntervals = new ArrayList<Interval>();
666 JSONArray errorMsgList = new JSONArray();
667
668
669 if(assignments.length != beginDates.length ||
670 assignments.length!= beginTimes.length ||
671 assignments.length != endDates.length ||
672 assignments.length != endTimes.length ||
673 assignments.length != hrs.length) {
674 errorMsgList.add("All fields are required");
675 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
676 return mapping.findForward("ws");
677 }
678
679 for(int i = 0; i < hrs.length; i++) {
680 String index = String.valueOf(i+1);
681
682
683 BigDecimal dc = new BigDecimal(hrs[i]);
684 if (dc.compareTo(new BigDecimal("0")) == 0) {
685 errorMsgList.add("The entered hours for entry " + index + " is not valid.");
686 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
687 return mapping.findForward("ws");
688 }
689
690
691
692 DateTime beginDateTime = TKUtils.convertDateStringToDateTimeWithoutZone(beginDates[i], beginTimes[i]);
693 DateTime endDateTime = TKUtils.convertDateStringToDateTimeWithoutZone(endDates[i], endTimes[i]);
694 if ((beginDateTime.compareTo(endDateTime) > 0 || endDateTime.compareTo(beginDateTime) < 0)) {
695 errorMsgList.add("The time or date for entry " + index + " is not valid.");
696 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
697 return mapping.findForward("ws");
698 }
699
700
701 Interval addedTimeblockInterval = new Interval(beginDateTime, endDateTime);
702 newIntervals.add(addedTimeblockInterval);
703 for (TimeBlock timeBlock : caf.getTimesheetDocument().getTimeBlocks()) {
704 if(timeBlock.getTkTimeBlockId().equals(tbId)) {
705 continue;
706 }
707 if(timeBlock.getHours().compareTo(BigDecimal.ZERO) == 0) {
708 continue;
709 }
710 DateTimeZone dateTimeZone = HrServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
711 DateTime timeBlockBeginTimestamp = new DateTime(timeBlock.getBeginDateTime(), dateTimeZone).withZone(TKUtils.getSystemDateTimeZone());
712 DateTime timeBlockEndTimestamp = new DateTime(timeBlock.getEndDateTime(), dateTimeZone).withZone(TKUtils.getSystemDateTimeZone());
713 Interval timeBlockInterval = new Interval(timeBlockBeginTimestamp, timeBlockEndTimestamp);
714 if (timeBlockInterval.overlaps(addedTimeblockInterval)) {
715 errorMsgList.add("The time block you are trying to add for entry " + index + " overlaps with an existing time block.");
716 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
717 return mapping.findForward("ws");
718 }
719 }
720 }
721
722 if(newIntervals.size() > 1 ) {
723 for(Interval intv1 : newIntervals) {
724 for(Interval intv2 : newIntervals) {
725 if(intv1.equals(intv2)) {
726 continue;
727 }
728 if (intv1.overlaps(intv2)) {
729 errorMsgList.add("There is time overlap between the entries.");
730 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
731 return mapping.findForward("ws");
732 }
733 }
734 }
735 }
736
737 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
738 return mapping.findForward("ws");
739 }
740
741 private Boolean isPrincipalAnyProcessorInWorkArea(String principalId, Long tbWorkArea, LocalDate asOfDate) {
742 Boolean flag = false;
743 Set<Long> workAreas = new HashSet<Long>();
744 workAreas.addAll(HrServiceLocator.getKPMERoleService().getWorkAreasForPrincipalInRole(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR.getRoleName(), LocalDate.now().toDateTimeAtStartOfDay(), true));
745 workAreas.addAll(HrServiceLocator.getKPMERoleService().getWorkAreasForPrincipalInRole(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR_DELEGATE.getRoleName(), LocalDate.now().toDateTimeAtStartOfDay(), true));
746
747 List<WorkArea> workAreaList = HrServiceLocator.getWorkAreaService().getWorkAreasForList(new ArrayList<Long>(workAreas), asOfDate);
748 for (WorkArea wa : workAreaList) {
749 if (wa.getWorkArea().compareTo(tbWorkArea) == 0) {
750 return true;
751 }
752 }
753 return false;
754 }
755 }