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 java.math.BigDecimal;
19 import java.sql.Timestamp;
20 import java.text.SimpleDateFormat;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30
31 import org.apache.commons.collections.CollectionUtils;
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.struts.action.ActionForm;
34 import org.apache.struts.action.ActionForward;
35 import org.apache.struts.action.ActionMapping;
36 import org.joda.time.DateTime;
37 import org.joda.time.DateTimeZone;
38 import org.joda.time.Interval;
39 import org.joda.time.LocalDate;
40 import org.json.simple.JSONArray;
41 import org.json.simple.JSONValue;
42 import org.kuali.kpme.core.KPMENamespace;
43 import org.kuali.kpme.core.assignment.Assignment;
44 import org.kuali.kpme.core.assignment.AssignmentDescriptionKey;
45 import org.kuali.kpme.core.calendar.entry.CalendarEntry;
46 import org.kuali.kpme.core.document.calendar.CalendarDocument;
47 import org.kuali.kpme.core.earncode.EarnCode;
48 import org.kuali.kpme.core.role.KPMERole;
49 import org.kuali.kpme.core.service.HrServiceLocator;
50 import org.kuali.kpme.core.util.HrConstants;
51 import org.kuali.kpme.core.util.HrContext;
52 import org.kuali.kpme.core.util.TKUtils;
53 import org.kuali.kpme.core.workarea.WorkArea;
54 import org.kuali.kpme.tklm.common.TkConstants;
55 import org.kuali.kpme.tklm.leave.block.LeaveBlock;
56 import org.kuali.kpme.tklm.time.clocklog.ClockLog;
57 import org.kuali.kpme.tklm.time.rules.lunch.department.DeptLunchRule;
58 import org.kuali.kpme.tklm.time.rules.timecollection.TimeCollectionRule;
59 import org.kuali.kpme.tklm.time.service.TkServiceLocator;
60 import org.kuali.kpme.tklm.time.timeblock.TimeBlock;
61 import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
62 import org.kuali.kpme.tklm.time.timesheet.web.TimesheetAction;
63 import org.kuali.kpme.tklm.time.workflow.TimesheetDocumentHeader;
64 import org.kuali.rice.krad.exception.AuthorizationException;
65 import org.kuali.rice.krad.service.KRADServiceLocator;
66 import org.kuali.rice.krad.util.GlobalVariables;
67 import org.springframework.cache.annotation.CacheEvict;
68
69 public class ClockAction extends TimesheetAction {
70
71 public static final SimpleDateFormat SDF = new SimpleDateFormat("EEE, MMMM d yyyy HH:mm:ss, zzzz");
72 public static final String SEPERATOR = "[****]+";
73 public static final String DOCUMENT_NOT_INITIATE_ERROR = "New Timesheet document could not be found. Please initiate the document first.";
74 public static final String TIME_BLOCK_OVERLAP_ERROR = "User has already logged time for this clock period.";
75
76 @Override
77 protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
78 super.checkTKAuthorization(form, methodToCall);
79
80 ClockActionForm clockActionForm = (ClockActionForm) form;
81
82 String principalId = GlobalVariables.getUserSession().getPrincipalId();
83 CalendarDocument timesheetDocument = TkServiceLocator.getTimesheetService().getTimesheetDocument(clockActionForm.getDocumentId());
84
85 if (StringUtils.equals(methodToCall, "clockAction") ||
86 StringUtils.equals(methodToCall, "addTimeBlock") ||
87 StringUtils.equals(methodToCall, "editTimeBlock") ||
88 StringUtils.equals(methodToCall, "distributeTimeBlocks") ||
89 StringUtils.equals(methodToCall, "saveNewTimeBlocks") ||
90 StringUtils.equals(methodToCall, "deleteTimeBlock")) {
91 if (!HrServiceLocator.getHRPermissionService().canEditCalendarDocument(principalId, timesheetDocument)) {
92 throw new AuthorizationException(GlobalVariables.getUserSession().getPrincipalId(), "ClockAction", "");
93 }
94 }
95 }
96
97
98 @Override
99 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
100 ActionForward actionForward = super.execute(mapping, form, request, response);
101
102 ClockActionForm clockActionForm = (ClockActionForm) form;
103
104 TimesheetDocument timesheetDocument = clockActionForm.getTimesheetDocument();
105 clockActionForm.setShowClockButton(true);
106 if (timesheetDocument != null) {
107 if (!timesheetDocument.getDocumentHeader().getDocumentStatus().equals(HrConstants.ROUTE_STATUS.ENROUTE)
108 && !timesheetDocument.getDocumentHeader().getDocumentStatus().equals(HrConstants.ROUTE_STATUS.FINAL)) {
109
110 String targetPrincipalId = HrContext.getTargetPrincipalId();
111 if (targetPrincipalId != null) {
112 clockActionForm.setPrincipalId(targetPrincipalId);
113 }
114 clockActionForm.setAssignmentDescriptions(timesheetDocument.getAssignmentDescriptions(true));
115
116 if (clockActionForm.getEditTimeBlockId() != null) {
117 clockActionForm.setCurrentTimeBlock(TkServiceLocator.getTimeBlockService().getTimeBlock(clockActionForm.getEditTimeBlockId()));
118 }
119
120 ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog(targetPrincipalId);
121 if (lastClockLog != null) {
122 DateTime lastClockDateTime = lastClockLog.getClockDateTime();
123 String lastClockZone = lastClockLog.getClockTimestampTimezone();
124 if (StringUtils.isEmpty(lastClockZone)) {
125 lastClockZone = TKUtils.getSystemTimeZone();
126 }
127
128
129
130 DateTimeZone zone = DateTimeZone.forID(lastClockZone);
131 DateTime clockWithZone = lastClockDateTime.withZone(zone);
132 clockActionForm.setLastClockTimeWithZone(clockWithZone.toDate());
133 clockActionForm.setLastClockTimestamp(lastClockDateTime.toDate());
134 clockActionForm.setLastClockAction(lastClockLog.getClockAction());
135 }
136
137 if (lastClockLog == null || StringUtils.equals(lastClockLog.getClockAction(), TkConstants.CLOCK_OUT)) {
138 clockActionForm.setCurrentClockAction(TkConstants.CLOCK_IN);
139 } else {
140 if (StringUtils.equals(lastClockLog.getClockAction(), TkConstants.LUNCH_OUT) && TkServiceLocator.getSystemLunchRuleService().isShowLunchButton()) {
141 clockActionForm.setCurrentClockAction(TkConstants.LUNCH_IN);
142 clockActionForm.setShowClockButton(false);
143 } else {
144 clockActionForm.setCurrentClockAction(TkConstants.CLOCK_OUT);
145 }
146
147 String selectedAssignment = new AssignmentDescriptionKey(lastClockLog.getJobNumber(), lastClockLog.getWorkArea(), lastClockLog.getTask()).toAssignmentKeyString();
148 clockActionForm.setSelectedAssignment(selectedAssignment);
149 Assignment assignment = timesheetDocument.getAssignment(AssignmentDescriptionKey.get(selectedAssignment));
150 Map<String, String> assignmentDesc = HrServiceLocator.getAssignmentService().getAssignmentDescriptions(assignment);
151 clockActionForm.setAssignmentDescriptions(assignmentDesc);
152 }
153
154
155
156
157
158
159
160
161 if (StringUtils.equals(GlobalVariables.getUserSession().getPrincipalId(), HrContext.getTargetPrincipalId())) {
162 clockActionForm.setClockButtonEnabled(true);
163 } else {
164 boolean isApproverOrReviewerForCurrentAssignment = false;
165 String selectedAssignment = StringUtils.EMPTY;
166 if (clockActionForm.getAssignmentDescriptions() != null) {
167 if (clockActionForm.getAssignmentDescriptions().size() == 1) {
168 for (String assignment : clockActionForm.getAssignmentDescriptions().keySet()) {
169 selectedAssignment = assignment;
170 }
171 } else {
172 selectedAssignment = clockActionForm.getSelectedAssignment();
173 }
174 }
175
176 if(StringUtils.isNotBlank(selectedAssignment)) {
177 Assignment assignment = HrServiceLocator.getAssignmentService().getAssignmentForTargetPrincipal(AssignmentDescriptionKey.get(selectedAssignment), LocalDate.now());
178 if (assignment != null) {
179 Long workArea = assignment.getWorkArea();
180 String dept = assignment.getJob().getDept();
181 String principalId = HrContext.getPrincipalId();
182 DateTime startOfToday = LocalDate.now().toDateTimeAtStartOfDay();
183 isApproverOrReviewerForCurrentAssignment =
184 HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER.getRoleName(), workArea, startOfToday)
185 || HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER_DELEGATE.getRoleName(), workArea, startOfToday)
186 || HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.REVIEWER.getRoleName(), workArea, startOfToday)
187 || HrServiceLocator.getKPMERoleService().principalHasRoleInDepartment(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR.getRoleName(), dept, startOfToday)
188 || HrServiceLocator.getKPMERoleService().principalHasRoleInDepartment(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR_DELEGATE.getRoleName(), dept, startOfToday);
189 }
190 } else {
191 if (CollectionUtils.isNotEmpty(clockActionForm.getAssignmentDescriptions().entrySet())) {
192
193 isApproverOrReviewerForCurrentAssignment = true;
194 }
195
196 }
197 clockActionForm.setClockButtonEnabled(isApproverOrReviewerForCurrentAssignment);
198 }
199
200 clockActionForm.setShowLunchButton(TkServiceLocator.getSystemLunchRuleService().isShowLunchButton());
201 assignShowDistributeButton(clockActionForm);
202
203 if (clockActionForm.isShowLunchButton()) {
204
205
206
207
208 Map<String, Boolean> assignmentDeptLunchRuleMap = new HashMap<String, Boolean>();
209 for (Assignment a : timesheetDocument.getAssignments()) {
210 String key = AssignmentDescriptionKey.getAssignmentKeyString(a);
211 DeptLunchRule deptLunchRule = TkServiceLocator.getDepartmentLunchRuleService().getDepartmentLunchRule(a.getDept(), a.getWorkArea(), clockActionForm.getPrincipalId(), a.getJobNumber(), LocalDate.now());
212 assignmentDeptLunchRuleMap.put(key, deptLunchRule != null);
213 }
214 clockActionForm.setAssignmentLunchMap(assignmentDeptLunchRuleMap);
215 }
216 } else {
217 clockActionForm.setErrorMessage("Your current timesheet is already submitted for Approval. Clock action is not allowed on this timesheet.");
218 }
219 }
220
221 return actionForward;
222 }
223
224 public void assignShowDistributeButton(ClockActionForm caf) {
225 caf.setShowDistrubuteButton(false);
226
227 TimesheetDocument timesheetDocument = caf.getTimesheetDocument();
228 if (timesheetDocument != null) {
229 int eligibleAssignmentCount = 0;
230 for (Assignment a : timesheetDocument.getAssignments()) {
231 WorkArea aWorkArea = HrServiceLocator.getWorkAreaService().getWorkArea(a.getWorkArea(), timesheetDocument.getDocEndDate());
232 if(aWorkArea != null && aWorkArea.isHrsDistributionF()) {
233 eligibleAssignmentCount++;
234 }
235
236
237 if (eligibleAssignmentCount > 1) {
238 caf.setShowDistrubuteButton(true);
239 break;
240 }
241 }
242 }
243 }
244
245 public ActionForward clockAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
246 ClockActionForm caf = (ClockActionForm) form;
247
248
249
250 if (StringUtils.isBlank(caf.getSelectedAssignment())) {
251 caf.setErrorMessage("No assignment selected.");
252 return mapping.findForward("basic");
253 }
254 String pId = HrContext.getTargetPrincipalId();
255 ClockLog previousClockLog = TkServiceLocator.getClockLogService().getLastClockLog(pId);
256 if(previousClockLog != null && StringUtils.equals(caf.getCurrentClockAction(), previousClockLog.getClockAction())){
257 caf.setErrorMessage("The operation is already performed.");
258 return mapping.findForward("basic");
259 }
260 String ip = TKUtils.getIPAddressFromRequest(request);
261 Assignment assignment = caf.getTimesheetDocument().getAssignment(AssignmentDescriptionKey.get(caf.getSelectedAssignment()));
262
263 List<Assignment> lstAssingmentAsOfToday = HrServiceLocator.getAssignmentService().getAssignments(pId, LocalDate.now());
264 boolean foundValidAssignment = false;
265 for(Assignment assign : lstAssingmentAsOfToday){
266 if((assign.getJobNumber().compareTo(assignment.getJobNumber()) ==0) &&
267 (assign.getWorkArea().compareTo(assignment.getWorkArea()) == 0) &&
268 (assign.getTask().compareTo(assignment.getTask()) == 0)){
269 foundValidAssignment = true;
270 break;
271 }
272 }
273
274 if(!foundValidAssignment){
275 caf.setErrorMessage("Assignment is not effective as of today");
276 return mapping.findForward("basic");
277 }
278
279 LocalDate beginDate = LocalDate.now();
280 DateTime clockBeginDateTime = new DateTime(beginDate.toDateTimeAtCurrentTime());
281
282 if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_IN) || StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_IN)) {
283 List<TimeBlock> tbList = caf.getTimesheetDocument().getTimeBlocks();
284 for(TimeBlock tb : tbList) {
285 String earnCode = tb.getEarnCode();
286 boolean isRegularEarnCode = StringUtils.equals(assignment.getJob().getPayTypeObj().getRegEarnCode(),earnCode);
287 EarnCode earnCodeObj = HrServiceLocator.getEarnCodeService().getEarnCode(earnCode, caf.getTimesheetDocument().getAsOfDate());
288 if(earnCodeObj != null && HrConstants.EARN_CODE_TIME.equals(earnCodeObj.getEarnCodeType())) {
289 Interval clockInterval = new Interval(new DateTime(tb.getBeginTimestamp().getTime()), new DateTime(tb.getEndTimestamp().getTime()));
290 if(isRegularEarnCode && clockInterval.contains(clockBeginDateTime.getMillis())) {
291 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
292 return mapping.findForward("basic");
293 }
294 }
295 }
296 }
297
298 DateTime currentDateTime = new DateTime();
299
300
301
302
303 if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_OUT) || StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_OUT)) {
304 ClockLog lastLog = null;
305 String inAction = "";
306 String outAction = "";
307 if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.LUNCH_OUT)) {
308 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(pId, TkConstants.CLOCK_IN);
309 inAction = TkConstants.LUNCH_IN;
310 outAction = TkConstants.LUNCH_OUT;
311 } else if (StringUtils.equals(caf.getCurrentClockAction(), TkConstants.CLOCK_OUT)) {
312 lastLog = TkServiceLocator.getClockLogService().getLastClockLog(pId);
313 inAction = TkConstants.CLOCK_IN;
314 outAction = TkConstants.CLOCK_OUT;
315 }
316
317 TimesheetDocument previousTimeDoc = TkServiceLocator.getTimesheetService().getTimesheetDocument(previousClockLog.getDocumentId());
318 if(previousTimeDoc != null) {
319 CalendarEntry previousCalEntry = previousTimeDoc.getCalendarEntry();
320 DateTime previousEndPeriodDateTime = previousCalEntry.getEndPeriodFullDateTime();
321
322 if(currentDateTime.isAfter(previousEndPeriodDateTime.getMillis())) {
323
324
325
326 DateTimeZone userTimezone = DateTimeZone.forID(HrServiceLocator.getTimezoneService().getUserTimezone(pId));
327 DateTimeZone systemTimeZone = TKUtils.getSystemDateTimeZone();
328
329 DateTime outLogDateTime = TKUtils.convertTimeForDifferentTimeZone(previousEndPeriodDateTime, systemTimeZone, userTimezone);
330
331 CalendarEntry nextCalendarEntry = HrServiceLocator.getCalendarEntryService().getNextCalendarEntryByCalendarId(previousCalEntry.getHrCalendarId(), previousCalEntry);
332 DateTime beginNextPeriodDateTime = nextCalendarEntry.getBeginPeriodFullDateTime();
333
334 DateTime inLogDateTime = TKUtils.convertTimeForDifferentTimeZone(beginNextPeriodDateTime, systemTimeZone, userTimezone);
335
336 TimesheetDocumentHeader nextTdh = TkServiceLocator.getTimesheetDocumentHeaderService()
337 .getDocumentHeader(pId, nextCalendarEntry.getBeginPeriodFullDateTime(), nextCalendarEntry.getEndPeriodFullDateTime());
338 if(nextTdh == null) {
339 caf.setErrorMessage(DOCUMENT_NOT_INITIATE_ERROR);
340 return mapping.findForward("basic");
341 }
342 TimesheetDocument nextTimeDoc = TkServiceLocator.getTimesheetService().getTimesheetDocument(nextTdh.getDocumentId());
343 if(nextTimeDoc == null) {
344 caf.setErrorMessage(DOCUMENT_NOT_INITIATE_ERROR);
345 return mapping.findForward("basic");
346 }
347
348 if (lastLog != null) {
349
350
351 DateTime endDateTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(outLogDateTime, previousCalEntry.getBeginPeriodFullDateTime().toLocalDate());
352 boolean validation = this.validateOverlapping(previousTimeDoc.getAsOfDate(), previousTimeDoc.getTimeBlocks(), lastLog.getClockDateTime(), endDateTime,assignment);
353 if(!validation) {
354 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
355 return mapping.findForward("basic");
356 }
357
358
359
360 endDateTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(currentDateTime, nextCalendarEntry.getBeginPeriodFullDateTime().toLocalDate());
361 validation = this.validateOverlapping(nextTimeDoc.getAsOfDate(), nextTimeDoc.getTimeBlocks(), inLogDateTime, endDateTime,assignment);
362 if(!validation) {
363 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
364 return mapping.findForward("basic");
365 }
366 }
367
368
369 ClockLog outLog = TkServiceLocator.getClockLogService().processClockLog(outLogDateTime, assignment, previousCalEntry, ip,
370 previousEndPeriodDateTime.toLocalDate(), previousTimeDoc, outAction, true, pId);
371
372
373 ClockLog inLog = TkServiceLocator.getClockLogService().processClockLog(inLogDateTime, assignment, nextCalendarEntry, ip,
374 beginNextPeriodDateTime.toLocalDate(), nextTimeDoc, inAction, true, pId);
375
376
377 ClockLog finalOutLog = TkServiceLocator.getClockLogService().processClockLog(currentDateTime, assignment, nextCalendarEntry, ip,
378 currentDateTime.toLocalDate(), nextTimeDoc, caf.getCurrentClockAction(), true, pId);
379
380
381 Timestamp ts= finalOutLog.getTimestamp();
382 java.util.Calendar cal = java.util.Calendar.getInstance();
383 cal.setTimeInMillis(ts.getTime());
384 cal.add(java.util.Calendar.SECOND, 5);
385 Timestamp later = new Timestamp(cal.getTime().getTime());
386 finalOutLog.setTimestamp(later);
387 TkServiceLocator.getClockLogService().saveClockLog(finalOutLog);
388
389 caf.setClockLog(finalOutLog);
390 return mapping.findForward("basic");
391
392 } else {
393 if (lastLog != null) {
394
395 DateTime endDateTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(new DateTime(), caf.getCalendarEntry().getBeginPeriodFullDateTime().toLocalDate());
396
397 boolean validation = this.validateOverlapping(caf.getTimesheetDocument().getAsOfDate(), caf.getTimesheetDocument().getTimeBlocks(), lastLog.getClockDateTime(), endDateTime,assignment);
398 if(!validation) {
399 caf.setErrorMessage(TIME_BLOCK_OVERLAP_ERROR);
400 return mapping.findForward("basic");
401 }
402 }
403 }
404 }
405 }
406
407 ClockLog clockLog = TkServiceLocator.getClockLogService().processClockLog(new DateTime(), assignment, caf.getCalendarEntry(), ip,
408 beginDate, caf.getTimesheetDocument(), caf.getCurrentClockAction(), true, pId);
409
410 caf.setClockLog(clockLog);
411 return mapping.findForward("basic");
412
413 }
414
415 public boolean validateOverlapping(LocalDate asOfDate, List<TimeBlock> tbList, DateTime beginDateTime, DateTime endDateTime, Assignment assignment) {
416 Interval clockInterval = new Interval(beginDateTime, endDateTime);
417 if(clockInterval != null) {
418 for(TimeBlock tb : tbList) {
419 String earnCode = tb.getEarnCode();
420 boolean isRegularEarnCode = StringUtils.equals(assignment.getJob().getPayTypeObj().getRegEarnCode(),earnCode);
421 EarnCode earnCodeObj = HrServiceLocator.getEarnCodeService().getEarnCode(earnCode, asOfDate);
422 if(isRegularEarnCode && earnCodeObj != null && HrConstants.EARN_CODE_TIME.equals(earnCodeObj.getEarnCodeType())) {
423 if(clockInterval.contains(tb.getBeginDateTime().getMillis()) || clockInterval.contains(tb.getEndDateTime().getMillis())) {
424 return false;
425 }
426 }
427 }
428 return true;
429 }
430 return false;
431 }
432
433
434 public ActionForward distributeTimeBlocks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
435 ClockActionForm caf = (ClockActionForm) form;
436 caf.findTimeBlocksToDistribute();
437 return mapping.findForward("tb");
438 }
439
440
441 public ActionForward editTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
442 ClockActionForm caf = (ClockActionForm) form;
443 TimeBlock tb = caf.getCurrentTimeBlock();
444 caf.setCurrentAssignmentKey(tb.getAssignmentKey());
445 caf.populateAssignmentsForSelectedTimeBlock(tb);
446 ActionForward forward = mapping.findForward("et");
447
448 return new ActionForward(forward.getPath() + "?editTimeBlockId=" + tb.getTkTimeBlockId().toString());
449
450 }
451 public ActionForward addTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
452 ClockActionForm caf = (ClockActionForm) form;
453 TimeBlock currentTb = caf.getCurrentTimeBlock();
454 List<TimeBlock> newTimeBlocks = caf.getTimesheetDocument().getTimeBlocks();
455 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(caf.getTimesheetDocument().getTimeBlocks().size());
456 for (TimeBlock tb : caf.getTimesheetDocument().getTimeBlocks()) {
457 referenceTimeBlocks.add(tb.copy());
458 }
459
460 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, HrContext.getPrincipalId());
461
462 ActionForward forward = mapping.findForward("et");
463
464 return new ActionForward(forward.getPath() + "?editTimeBlockId=" + currentTb.getTkTimeBlockId().toString());
465 }
466
467 public ActionForward saveNewTimeBlocks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
468 ClockActionForm caf = (ClockActionForm)form;
469 String tbId = caf.getTbId();
470 String timesheetDocId = caf.getTsDocId();
471
472 String[] assignments = caf.getNewAssignDesCol().split(SEPERATOR);
473 String[] beginDates = caf.getNewBDCol().split(SEPERATOR);
474 String[] beginTimes = caf.getNewBTCol().split(SEPERATOR);
475 String[] endDates = caf.getNewEDCol().split(SEPERATOR);
476 String[] endTimes = caf.getNewETCol().split(SEPERATOR);
477 String[] hrs = caf.getNewHrsCol().split(SEPERATOR);
478 String earnCode = TkServiceLocator.getTimeBlockService().getTimeBlock(tbId).getEarnCode();
479 TimesheetDocument tsDoc = TkServiceLocator.getTimesheetService().getTimesheetDocument(timesheetDocId);
480 List<TimeBlock> newTbList = new ArrayList<TimeBlock>();
481 if(tsDoc != null) {
482 for(TimeBlock oldTB : tsDoc.getTimeBlocks()) {
483 if(!(oldTB.getTkTimeBlockId().compareTo(tbId) == 0)) {
484 newTbList.add(oldTB);
485 }
486 }
487 }
488 for(int i = 0; i < hrs.length; i++) {
489 BigDecimal hours = new BigDecimal(hrs[i]);
490 DateTime beginDateTime = TKUtils.convertDateStringToDateTime(beginDates[i], beginTimes[i]);
491 DateTime endDateTime = TKUtils.convertDateStringToDateTime(endDates[i], endTimes[i]);
492 String assignString = assignments[i];
493 Assignment assignment = HrServiceLocator.getAssignmentService().getAssignment(assignString);
494
495 TimeBlock tb = TkServiceLocator.getTimeBlockService().createTimeBlock(tsDoc, beginDateTime, endDateTime, assignment, earnCode, hours,BigDecimal.ZERO, false, false, HrContext.getPrincipalId());
496 newTbList.add(tb);
497 }
498 TkServiceLocator.getTimeBlockService().resetTimeHourDetail(newTbList);
499 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTbList, new ArrayList<LeaveBlock>(), tsDoc.getCalendarEntry(), tsDoc, tsDoc.getPrincipalId());
500 TkServiceLocator.getTimeBlockService().saveTimeBlocks(newTbList);
501 TimeBlock oldTB = TkServiceLocator.getTimeBlockService().getTimeBlock(tbId);
502 TkServiceLocator.getTimeBlockService().deleteTimeBlock(oldTB);
503 return mapping.findForward("basic");
504 }
505
506 public ActionForward validateNewTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
507 ClockActionForm caf = (ClockActionForm)form;
508 String tbId = caf.getTbId();
509 String[] assignments = caf.getNewAssignDesCol().split(SEPERATOR);
510 String[] beginDates = caf.getNewBDCol().split(SEPERATOR);
511 String[] beginTimes = caf.getNewBTCol().split(SEPERATOR);
512 String[] endDates = caf.getNewEDCol().split(SEPERATOR);
513 String[] endTimes = caf.getNewETCol().split(SEPERATOR);
514 String[] hrs = caf.getNewHrsCol().split(SEPERATOR);
515
516 List<Interval> newIntervals = new ArrayList<Interval>();
517 JSONArray errorMsgList = new JSONArray();
518
519
520 if(assignments.length != beginDates.length ||
521 assignments.length!= beginTimes.length ||
522 assignments.length != endDates.length ||
523 assignments.length != endTimes.length ||
524 assignments.length != hrs.length) {
525 errorMsgList.add("All fields are required");
526 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
527 return mapping.findForward("ws");
528 }
529
530 for(int i = 0; i < hrs.length; i++) {
531 String index = String.valueOf(i+1);
532
533
534 BigDecimal dc = new BigDecimal(hrs[i]);
535 if (dc.compareTo(new BigDecimal("0")) == 0) {
536 errorMsgList.add("The entered hours for entry " + index + " is not valid.");
537 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
538 return mapping.findForward("ws");
539 }
540
541
542
543 DateTime beginDateTime = TKUtils.convertDateStringToDateTimeWithoutZone(beginDates[i], beginTimes[i]);
544 DateTime endDateTime = TKUtils.convertDateStringToDateTimeWithoutZone(endDates[i], endTimes[i]);
545 if ((beginDateTime.compareTo(endDateTime) > 0 || endDateTime.compareTo(beginDateTime) < 0)) {
546 errorMsgList.add("The time or date for entry " + index + " is not valid.");
547 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
548 return mapping.findForward("ws");
549 }
550
551
552 Interval addedTimeblockInterval = new Interval(beginDateTime, endDateTime);
553 newIntervals.add(addedTimeblockInterval);
554 for (TimeBlock timeBlock : caf.getTimesheetDocument().getTimeBlocks()) {
555 if(timeBlock.getTkTimeBlockId().equals(tbId)) {
556 continue;
557 }
558 if(timeBlock.getHours().compareTo(BigDecimal.ZERO) == 0) {
559 continue;
560 }
561 DateTimeZone dateTimeZone = HrServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
562 DateTime timeBlockBeginTimestamp = new DateTime(timeBlock.getBeginTimestamp().getTime(), dateTimeZone).withZone(TKUtils.getSystemDateTimeZone());
563 DateTime timeBlockEndTimestamp = new DateTime(timeBlock.getEndTimestamp().getTime(), dateTimeZone).withZone(TKUtils.getSystemDateTimeZone());
564 Interval timeBlockInterval = new Interval(timeBlockBeginTimestamp, timeBlockEndTimestamp);
565 if (timeBlockInterval.overlaps(addedTimeblockInterval)) {
566 errorMsgList.add("The time block you are trying to add for entry " + index + " overlaps with an existing time block.");
567 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
568 return mapping.findForward("ws");
569 }
570 }
571 }
572
573 if(newIntervals.size() > 1 ) {
574 for(Interval intv1 : newIntervals) {
575 for(Interval intv2 : newIntervals) {
576 if(intv1.equals(intv2)) {
577 continue;
578 }
579 if (intv1.overlaps(intv2)) {
580 errorMsgList.add("There is time overlap between the entries.");
581 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
582 return mapping.findForward("ws");
583 }
584 }
585 }
586 }
587
588 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
589 return mapping.findForward("ws");
590 }
591
592 private Boolean isPrincipalAnyProcessorInWorkArea(String principalId, Long tbWorkArea, LocalDate asOfDate) {
593 Boolean flag = false;
594 Set<Long> workAreas = new HashSet<Long>();
595 workAreas.addAll(HrServiceLocator.getKPMERoleService().getWorkAreasForPrincipalInRole(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR.getRoleName(), LocalDate.now().toDateTimeAtStartOfDay(), true));
596 workAreas.addAll(HrServiceLocator.getKPMERoleService().getWorkAreasForPrincipalInRole(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR_DELEGATE.getRoleName(), LocalDate.now().toDateTimeAtStartOfDay(), true));
597 for (Long wa : workAreas) {
598 WorkArea workArea = HrServiceLocator.getWorkAreaService().getWorkArea(wa, asOfDate);
599 if (workArea!= null && tbWorkArea.compareTo(wa)==0) {
600 flag = true;
601 break;
602 }
603 }
604 return flag;
605 }
606
607 }