1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.kpme.tklm.time.detail.web;
17
18 import java.math.BigDecimal;
19 import java.sql.Timestamp;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Properties;
28 import java.util.Set;
29
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32
33 import org.apache.commons.collections.MapUtils;
34 import org.apache.commons.lang.ObjectUtils;
35 import org.apache.commons.lang.StringUtils;
36 import org.apache.commons.lang.SystemUtils;
37 import org.apache.struts.action.ActionForm;
38 import org.apache.struts.action.ActionForward;
39 import org.apache.struts.action.ActionMapping;
40 import org.joda.time.DateTime;
41 import org.joda.time.Interval;
42 import org.joda.time.LocalDate;
43 import org.kuali.kpme.core.accrualcategory.AccrualCategory;
44 import org.kuali.kpme.core.accrualcategory.rule.AccrualCategoryRule;
45 import org.kuali.kpme.core.assignment.Assignment;
46 import org.kuali.kpme.core.assignment.AssignmentDescriptionKey;
47 import org.kuali.kpme.core.calendar.Calendar;
48 import org.kuali.kpme.core.calendar.entry.CalendarEntry;
49 import org.kuali.kpme.core.earncode.EarnCode;
50 import org.kuali.kpme.core.principal.PrincipalHRAttributes;
51 import org.kuali.kpme.core.service.HrServiceLocator;
52 import org.kuali.kpme.core.util.HrConstants;
53 import org.kuali.kpme.core.util.HrContext;
54 import org.kuali.kpme.core.util.TKUtils;
55 import org.kuali.kpme.tklm.common.LMConstants;
56 import org.kuali.kpme.tklm.common.TkConstants;
57 import org.kuali.kpme.tklm.leave.block.LeaveBlock;
58 import org.kuali.kpme.tklm.leave.block.LeaveBlockAggregate;
59 import org.kuali.kpme.tklm.leave.calendar.validation.LeaveCalendarValidationUtil;
60 import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
61 import org.kuali.kpme.tklm.leave.transfer.BalanceTransfer;
62 import org.kuali.kpme.tklm.leave.transfer.validation.BalanceTransferValidationUtils;
63 import org.kuali.kpme.tklm.time.calendar.TkCalendar;
64 import org.kuali.kpme.tklm.time.detail.validation.TimeDetailValidationUtil;
65 import org.kuali.kpme.tklm.time.service.TkServiceLocator;
66 import org.kuali.kpme.tklm.time.timeblock.TimeBlock;
67 import org.kuali.kpme.tklm.time.timeblock.TimeBlockHistory;
68 import org.kuali.kpme.tklm.time.timehourdetail.TimeHourDetail;
69 import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
70 import org.kuali.kpme.tklm.time.timesheet.web.TimesheetAction;
71 import org.kuali.kpme.tklm.time.timesummary.AssignmentColumn;
72 import org.kuali.kpme.tklm.time.timesummary.AssignmentRow;
73 import org.kuali.kpme.tklm.time.timesummary.EarnCodeSection;
74 import org.kuali.kpme.tklm.time.timesummary.EarnGroupSection;
75 import org.kuali.kpme.tklm.time.timesummary.TimeSummary;
76 import org.kuali.kpme.tklm.time.util.TkContext;
77 import org.kuali.kpme.tklm.time.util.TkTimeBlockAggregate;
78 import org.kuali.rice.kew.api.KewApiServiceLocator;
79 import org.kuali.rice.kew.api.document.DocumentStatus;
80 import org.kuali.rice.kew.service.KEWServiceLocator;
81 import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
82 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
83 import org.kuali.rice.krad.exception.AuthorizationException;
84 import org.kuali.rice.krad.util.GlobalVariables;
85 import org.kuali.rice.krad.util.UrlFactory;
86
87 public class TimeDetailAction extends TimesheetAction {
88
89 @Override
90 protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
91 super.checkTKAuthorization(form, methodToCall);
92
93 TimeDetailActionForm timeDetailActionForm = (TimeDetailActionForm) form;
94
95 String principalId = GlobalVariables.getUserSession().getPrincipalId();
96 TimesheetDocument timesheetDocument = TkServiceLocator.getTimesheetService().getTimesheetDocument(timeDetailActionForm.getDocumentId());
97 if (StringUtils.equals(methodToCall, "addTimeBlock")
98 || StringUtils.equals(methodToCall, "deleteTimeBlock")
99 || StringUtils.equals(methodToCall, "updateTimeBlock")) {
100 if (!HrServiceLocator.getHRPermissionService().canEditCalendarDocument(principalId, timesheetDocument)) {
101 throw new AuthorizationException(principalId, "TimeDetailAction", "");
102 }
103 }
104 }
105
106 @Override
107 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
108 ActionForward forward = super.execute(mapping, form, request, response);
109
110 TimeDetailActionForm timeDetailActionForm = (TimeDetailActionForm) form;
111
112 CalendarEntry calendarEntry = timeDetailActionForm.getCalendarEntry();
113 TimesheetDocument timesheetDocument = timeDetailActionForm.getTimesheetDocument();
114
115
116 if (calendarEntry != null && timesheetDocument != null) {
117 List<String> assignmentKeys = new ArrayList<String>();
118 for (Assignment assignment : timesheetDocument.getAssignments()) {
119 assignmentKeys.add(assignment.getAssignmentKey());
120 }
121
122 timeDetailActionForm.setAssignmentDescriptions(timeDetailActionForm.getTimesheetDocument().getAssignmentDescriptions(false));
123
124 timeDetailActionForm.setDocEditable("false");
125 if (HrContext.isSystemAdmin()) {
126 timeDetailActionForm.setDocEditable("true");
127 } else {
128 DocumentStatus documentStatus = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(timeDetailActionForm.getDocumentId());
129 if (!DocumentStatus.FINAL.equals(documentStatus)
130 && !DocumentStatus.CANCELED.getCode().equals(documentStatus)
131 && !DocumentStatus.DISAPPROVED.getCode().equals(documentStatus)) {
132 if(StringUtils.equals(timesheetDocument.getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())
133 || HrContext.isSystemAdmin()
134 || TkContext.isLocationAdmin()
135 || HrContext.isReviewer()
136 || HrContext.isAnyApprover()
137 || HrContext.isAnyPayrollProcessor()) {
138 timeDetailActionForm.setDocEditable("true");
139 }
140
141
142 if (StringUtils.equals(timesheetDocument.getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())
143 && timesheetDocument.getDocumentHeader().getDocumentStatus().equals(HrConstants.ROUTE_STATUS.ENROUTE)) {
144 Collection actions = KEWServiceLocator.getActionTakenService().findByDocIdAndAction(timesheetDocument.getDocumentHeader().getDocumentId(), HrConstants.DOCUMENT_ACTIONS.APPROVE);
145 if (!actions.isEmpty()) {
146 timeDetailActionForm.setDocEditable("false");
147 }
148 }
149 } else if (DocumentStatus.FINAL.equals(documentStatus)) {
150 if(HrContext.isSystemAdmin()) {
151 timeDetailActionForm.setNotesEditable(Boolean.TRUE);
152 } else {
153 timeDetailActionForm.setNotesEditable(Boolean.FALSE);
154 }
155 }
156 }
157
158 List<TimeBlock> timeBlocks = TkServiceLocator.getTimesheetService().getTimesheetDocument(timeDetailActionForm.getDocumentId()).getTimeBlocks();
159 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(timesheetDocument.getPrincipalId(),
160 calendarEntry.getBeginPeriodFullDateTime().toLocalDate(), calendarEntry.getEndPeriodFullDateTime().toLocalDate(), assignmentKeys);
161
162
163 timeDetailActionForm.getTimesheetDocument().setTimeBlocks(timeBlocks);
164 assignStypeClassMapForTimeSummary(timeDetailActionForm,timeBlocks, leaveBlocks);
165
166 Calendar payCalendar = HrServiceLocator.getCalendarService().getCalendar(calendarEntry != null ? calendarEntry.getHrCalendarId() : null);
167
168 List<Interval> intervals = TKUtils.getFullWeekDaySpanForCalendarEntry(calendarEntry);
169 LeaveBlockAggregate lbAggregate = new LeaveBlockAggregate(leaveBlocks, calendarEntry, intervals);
170 TkTimeBlockAggregate tbAggregate = new TkTimeBlockAggregate(timeBlocks, calendarEntry, payCalendar, true,intervals);
171
172
173 TkCalendar cal = TkCalendar.getCalendar(tbAggregate, lbAggregate);
174 cal.assignAssignmentStyle(timeDetailActionForm.getAssignStyleClassMap());
175 timeDetailActionForm.setTkCalendar(cal);
176
177 timeDetailActionForm.setTimeBlockString(ActionFormUtils.getTimeBlocksJson(tbAggregate.getFlattenedTimeBlockList()));
178 timeDetailActionForm.setLeaveBlockString(ActionFormUtils.getLeaveBlocksJson(lbAggregate.getFlattenedLeaveBlockList()));
179
180 timeDetailActionForm.setOvertimeEarnCodes(HrServiceLocator.getEarnCodeService().getOvertimeEarnCodesStrs(timesheetDocument.getAsOfDate()));
181
182 if (StringUtils.equals(timesheetDocument.getPrincipalId(), GlobalVariables.getUserSession().getPrincipalId())) {
183 timeDetailActionForm.setWorkingOnItsOwn("true");
184 }
185
186 setMessages(timeDetailActionForm);
187
188 }
189
190 return forward;
191 }
192
193
194 private void assignStypeClassMapForTimeSummary(TimeDetailActionForm tdaf, List<TimeBlock> timeBlocks, List<LeaveBlock> leaveBlocks) throws Exception {
195 TimeSummary ts = TkServiceLocator.getTimeSummaryService().getTimeSummary(tdaf.getTimesheetDocument());
196 tdaf.setAssignStyleClassMap(ActionFormUtils.buildAssignmentStyleClassMap(timeBlocks, leaveBlocks));
197 Map<String, String> aMap = tdaf.getAssignStyleClassMap();
198
199 for (EarnGroupSection earnGroupSection : ts.getSections()) {
200 for (EarnCodeSection section : earnGroupSection.getEarnCodeSections()) {
201 for (AssignmentRow assignRow : section.getAssignmentsRows()) {
202 String assignmentCssStyle = MapUtils.getString(aMap, assignRow.getAssignmentKey());
203 assignRow.setCssClass(assignmentCssStyle);
204 for (AssignmentColumn assignmentColumn : assignRow.getAssignmentColumns().values()) {
205 assignmentColumn.setCssClass(assignmentCssStyle);
206 }
207 }
208 }
209
210 }
211 tdaf.setTimeSummary(ts);
212
213 ActionFormUtils.addWarningTextFromEarnGroup(tdaf);
214 ActionFormUtils.addUnapprovedIPWarningFromClockLog(tdaf);
215 }
216
217 protected void setMessages(TimeDetailActionForm timeDetailActionForm) {
218 String principalId = HrContext.getTargetPrincipalId();
219 TimesheetDocument timesheetDocument = timeDetailActionForm.getTimesheetDocument();
220 CalendarEntry calendarEntry = timeDetailActionForm.getCalendarEntry();
221
222 List<LeaveBlock> balanceTransferLeaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(timesheetDocument.getPrincipalId(),
223 calendarEntry.getBeginPeriodFullDateTime().toLocalDate(), calendarEntry.getEndPeriodFullDateTime().toLocalDate(), LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
224
225 Map<String, Set<String>> allMessages = LeaveCalendarValidationUtil.getWarningMessagesForLeaveBlocks(balanceTransferLeaveBlocks);
226
227
228 List<BalanceTransfer> losses = new ArrayList<BalanceTransfer>();
229 if (LmServiceLocator.getLeaveApprovalService().isActiveAssignmentFoundOnJobFlsaStatus(principalId, HrConstants.FLSA_STATUS_NON_EXEMPT, true)) {
230 PrincipalHRAttributes principalCalendar = HrServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, calendarEntry.getEndPeriodFullDateTime().toLocalDate());
231
232 Interval calendarInterval = new Interval(calendarEntry.getBeginPeriodDate().getTime(), calendarEntry.getEndPeriodDate().getTime());
233 Map<String,Set<LeaveBlock>> maxBalInfractions = new HashMap<String,Set<LeaveBlock>>();
234
235 if (principalCalendar != null) {
236 maxBalInfractions = LmServiceLocator.getAccrualCategoryMaxBalanceService().getMaxBalanceViolations(calendarEntry, principalId);
237
238 for (Entry<String,Set<LeaveBlock>> entry : maxBalInfractions.entrySet()) {
239 for (LeaveBlock lb : entry.getValue()) {
240 if (calendarInterval.contains(lb.getLeaveDate().getTime())) {
241 AccrualCategory accrualCat = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(lb.getAccrualCategory(), lb.getLeaveLocalDate());
242 AccrualCategoryRule aRule = HrServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(lb.getAccrualCategoryRuleId());
243 if (StringUtils.equals(aRule.getActionAtMaxBalance(),HrConstants.ACTION_AT_MAX_BALANCE.LOSE)) {
244 DateTime aDate = null;
245 if (StringUtils.equals(aRule.getMaxBalanceActionFrequency(), HrConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) {
246 aDate = HrServiceLocator.getLeavePlanService().getRolloverDayOfLeavePlan(principalCalendar.getLeavePlan(), lb.getLeaveLocalDate());
247 } else {
248 Calendar cal = HrServiceLocator.getCalendarService().getCalendarByPrincipalIdAndDate(principalId, new LocalDate(lb.getLeaveDate()), true);
249 CalendarEntry leaveEntry = HrServiceLocator.getCalendarEntryService().getCurrentCalendarEntryByCalendarId(cal.getHrCalendarId(), new DateTime(lb.getLeaveDate()));
250 aDate = new DateTime(leaveEntry.getEndPeriodDate());
251 }
252 aDate = aDate.minusDays(1);
253 if (calendarInterval.contains(aDate.getMillis()) && aDate.toDate().compareTo(calendarEntry.getEndPeriodDate()) <= 0) {
254
255 AccrualCategory accrualCategory = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(aRule.getLmAccrualCategoryId());
256 BigDecimal accruedBalance = LmServiceLocator.getAccrualService().getAccruedBalanceForPrincipal(principalId, accrualCategory, lb.getLeaveLocalDate());
257
258 BalanceTransfer loseTransfer = LmServiceLocator.getBalanceTransferService().initializeTransfer(principalId, lb.getAccrualCategoryRuleId(), accruedBalance, lb.getLeaveLocalDate());
259 boolean valid = BalanceTransferValidationUtils.validateTransfer(loseTransfer);
260 if (valid) {
261
262 losses.add(loseTransfer);
263 }
264 }
265 }
266
267
268 String message = "You have exceeded the maximum balance limit for '" + accrualCat.getAccrualCategory() + "' as of " + lb.getLeaveDate() + ". "
269 + "Depending upon the accrual category rules, leave over this limit may be forfeited.";
270
271 if (!StringUtils.contains(allMessages.get("warningMessages").toString(), "You have exceeded the maximum balance limit for '" + accrualCat.getAccrualCategory())) {
272 allMessages.get("warningMessages").add(message);
273 }
274 }
275 }
276 }
277 }
278 timeDetailActionForm.setForfeitures(losses);
279
280 Map<String, Set<String>> transactionalMessages = LeaveCalendarValidationUtil.validatePendingTransactions(HrContext.getTargetPrincipalId(), calendarEntry.getBeginPeriodFullDateTime().toLocalDate(), calendarEntry.getEndPeriodFullDateTime().toLocalDate());
281 allMessages.get("infoMessages").addAll(transactionalMessages.get("infoMessages"));
282 allMessages.get("warningMessages").addAll(transactionalMessages.get("warningMessages"));
283 allMessages.get("actionMessages").addAll(transactionalMessages.get("actionMessages"));
284
285 if (principalCalendar != null) {
286 Calendar calendar = HrServiceLocator.getCalendarService().getCalendarByPrincipalIdAndDate(principalId, calendarEntry.getEndPeriodFullDateTime().toLocalDate(), true);
287
288 if (calendar != null) {
289 List<CalendarEntry> leaveCalendarEntries = HrServiceLocator.getCalendarEntryService().getCalendarEntriesEndingBetweenBeginAndEndDate(calendar.getHrCalendarId(), calendarEntry.getBeginPeriodFullDateTime(), calendarEntry.getEndPeriodFullDateTime());
290
291 List<AccrualCategory> accrualCategories = HrServiceLocator.getAccrualCategoryService().getActiveLeaveAccrualCategoriesForLeavePlan(principalCalendar.getLeavePlan(), calendarEntry.getEndPeriodFullDateTime().toLocalDate());
292 for (AccrualCategory accrualCategory : accrualCategories) {
293 if (LmServiceLocator.getAccrualCategoryMaxCarryOverService().exceedsAccrualCategoryMaxCarryOver(accrualCategory.getAccrualCategory(), principalId, leaveCalendarEntries, calendarEntry.getEndPeriodFullDateTime().toLocalDate())) {
294 String message = "Your pending leave balance is greater than the annual max carry over for accrual category '" + accrualCategory.getAccrualCategory() + "' and upon approval, the excess balance will be lost.";
295 if (!allMessages.get("warningMessages").contains(message)) {
296 allMessages.get("warningMessages").add(message);
297 }
298 }
299 }
300 }
301 }
302 }
303
304 List<String> infoMessages = timeDetailActionForm.getInfoMessages();
305 infoMessages.addAll(allMessages.get("infoMessages"));
306
307 List<String> warningMessages = timeDetailActionForm.getWarningMessages();
308 warningMessages.addAll(allMessages.get("warningMessages"));
309
310 List<String> actionMessages = timeDetailActionForm.getActionMessages();
311 actionMessages.addAll(allMessages.get("actionMessages"));
312
313 timeDetailActionForm.setInfoMessages(infoMessages);
314 timeDetailActionForm.setWarningMessages(warningMessages);
315 timeDetailActionForm.setActionMessages(actionMessages);
316 }
317
318
319
320
321
322
323
324 public ActionForward deleteTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
325 TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
326
327 String principalId = HrContext.getPrincipalId();
328 String targetPrincipalId = HrContext.getTargetPrincipalId();
329 String documentId = tdaf.getDocumentId();
330
331
332 List<TimeBlock> timeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
333 TimeBlock deletedTimeBlock = null;
334 for (TimeBlock tb : timeBlocks) {
335 if (tb.getTkTimeBlockId().compareTo(tdaf.getTkTimeBlockId()) == 0) {
336 deletedTimeBlock = tb;
337 break;
338 }
339 }
340 if (deletedTimeBlock == null) {
341 return mapping.findForward("basic");
342 }
343
344 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(tdaf.getTimesheetDocument().getTimeBlocks().size());
345 for (TimeBlock b : tdaf.getTimesheetDocument().getTimeBlocks()) {
346 referenceTimeBlocks.add(b.copy());
347 }
348
349
350 List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
351 newTimeBlocks.remove(deletedTimeBlock);
352
353
354 TkServiceLocator.getTimeBlockService().deleteTimeBlock(deletedTimeBlock);
355
356 TimeBlockHistory tbh = new TimeBlockHistory(deletedTimeBlock);
357 tbh.setActionHistory(TkConstants.ACTIONS.DELETE_TIME_BLOCK);
358 TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
359
360 List<Assignment> assignments = tdaf.getTimesheetDocument().getAssignments();
361 List<String> assignmentKeys = new ArrayList<String>();
362 for (Assignment assignment : assignments) {
363 assignmentKeys.add(assignment.getAssignmentKey());
364 }
365 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(principalId, tdaf.getTimesheetDocument().getAsOfDate(), tdaf.getTimesheetDocument().getDocEndDate(), assignmentKeys);
366
367
368 TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks, tdaf.getTimesheetDocument().getAsOfDate());
369 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, leaveBlocks, tdaf.getCalendarEntry(), tdaf.getTimesheetDocument(), HrContext.getPrincipalId());
370 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, HrContext.getPrincipalId());
371
372 generateTimesheetChangedNotification(principalId, targetPrincipalId, documentId);
373
374 return mapping.findForward("basic");
375 }
376
377
378
379
380
381
382
383
384 public ActionForward addTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
385 TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
386
387 if(StringUtils.isNotEmpty(tdaf.getLmLeaveBlockId())) {
388 List<String> errors = TimeDetailValidationUtil.validateLeaveEntry(tdaf);
389 if(errors.isEmpty()) {
390
391
392 this.updateLeaveBlock(tdaf);
393 }
394 else {
395 tdaf.setErrorMessages(errors);
396 }
397 return mapping.findForward("basic");
398 }
399
400 if(StringUtils.isNotEmpty(tdaf.getSelectedEarnCode())) {
401 EarnCode ec = HrServiceLocator.getEarnCodeService().getEarnCode(tdaf.getSelectedEarnCode(), TKUtils.formatDateTimeStringNoTimezone(tdaf.getEndDate()).toLocalDate());
402 if(ec != null && ec.getLeavePlan() != null) {
403
404 List<String> errors = TimeDetailValidationUtil.validateLeaveEntry(tdaf);
405 if(errors.isEmpty()) {
406
407
408 this.changeLeaveBlocks(tdaf);
409 }
410 else {
411 tdaf.setErrorMessages(errors);
412 }
413 } else {
414
415 List<String> errors = TimeDetailValidationUtil.validateTimeEntryDetails(tdaf);
416 if(errors.isEmpty()) {
417
418
419 this.changeTimeBlocks(tdaf);
420 }
421 else {
422 tdaf.setErrorMessages(errors);
423 }
424 }
425 }
426
427
428 ActionFormUtils.addWarningTextFromEarnGroup(tdaf);
429 return mapping.findForward("basic");
430 }
431
432 private void removeOldTimeBlock(TimeDetailActionForm tdaf) {
433 if (tdaf.getTkTimeBlockId() != null) {
434 TimeBlock tb = TkServiceLocator.getTimeBlockService().getTimeBlock(tdaf.getTkTimeBlockId());
435 if (tb != null) {
436 TimeBlockHistory tbh = new TimeBlockHistory(tb);
437 TkServiceLocator.getTimeBlockService().deleteTimeBlock(tb);
438
439
440 tbh.setActionHistory(TkConstants.ACTIONS.DELETE_TIME_BLOCK);
441 TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
442
443
444 tdaf.getTimesheetDocument().getTimeBlocks().remove(tb);
445 }
446 }
447 }
448
449 private void removeOldLeaveBlock(String lbId) {
450 if (lbId != null) {
451 LeaveBlock lb = LmServiceLocator.getLeaveBlockService().getLeaveBlock(lbId);
452 if (lb != null) {
453 LmServiceLocator.getLeaveBlockService().deleteLeaveBlock(lbId, HrContext.getPrincipalId());
454 }
455 }
456 }
457
458
459
460
461
462
463
464
465 private void changeLeaveBlocks(TimeDetailActionForm tdaf) {
466 DateTime beginDate = null;
467 DateTime endDate = null;
468
469 if(tdaf.getStartTime() != null && tdaf.getEndTime() != null) {
470 beginDate = TKUtils.convertDateStringToDateTime(tdaf.getStartDate(), tdaf.getStartTime());
471 endDate = TKUtils.convertDateStringToDateTime(tdaf.getEndDate(), tdaf.getEndTime());
472 } else {
473
474 beginDate = TKUtils.formatDateTimeStringNoTimezone(tdaf.getStartDate());
475 endDate = TKUtils.formatDateTimeStringNoTimezone(tdaf.getEndDate());
476 }
477
478 String selectedEarnCode = tdaf.getSelectedEarnCode();
479 BigDecimal leaveAmount = tdaf.getLeaveAmount();
480
481 String desc = "";
482 String spanningWeeks = tdaf.getSpanningWeeks();
483 Assignment currentAssignment = tdaf.getTimesheetDocument().getAssignment(AssignmentDescriptionKey.get(tdaf.getSelectedAssignment()));
484
485 LmServiceLocator.getLeaveBlockService().addLeaveBlocks(beginDate, endDate, tdaf.getCalendarEntry(), selectedEarnCode, leaveAmount, desc, currentAssignment,
486 spanningWeeks, LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR, HrContext.getTargetPrincipalId());
487
488 List<Assignment> assignments = tdaf.getTimesheetDocument().getAssignments();
489 List<String> assignmentKeys = new ArrayList<String>();
490 for (Assignment assignment : assignments) {
491 assignmentKeys.add(assignment.getAssignmentKey());
492 }
493 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(HrContext.getTargetPrincipalId(), tdaf.getTimesheetDocument().getAsOfDate(), tdaf.getTimesheetDocument().getDocEndDate(), assignmentKeys);
494
495
496 List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
497
498
499 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(newTimeBlocks.size());
500 for (TimeBlock tb : newTimeBlocks) {
501 referenceTimeBlocks.add(tb.copy());
502 }
503 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, leaveBlocks, tdaf.getCalendarEntry(), tdaf.getTimesheetDocument(), HrContext.getPrincipalId());
504 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, HrContext.getPrincipalId());
505 generateTimesheetChangedNotification(HrContext.getPrincipalId(), HrContext.getTargetPrincipalId(), tdaf.getDocumentId());
506 }
507
508
509
510
511
512
513
514
515 private void changeTimeBlocks(TimeDetailActionForm tdaf) {
516 boolean isClockLogCreated = false;
517 String clockLogBeginId = null;
518 String clockLogEndId = null;
519 tdaf.getDocumentId();
520
521
522
523
524 if (tdaf.getTkTimeBlockId() != null) {
525 TimeBlock tb = TkServiceLocator.getTimeBlockService().getTimeBlock(tdaf.getTkTimeBlockId());
526 if (tb != null) {
527 isClockLogCreated = tb.getClockLogCreated();
528 clockLogBeginId = tb.getClockLogBeginId();
529 clockLogEndId = tb.getClockLogEndId();
530 }
531 }
532
533 Assignment currentAssignment = tdaf.getTimesheetDocument().getAssignment(AssignmentDescriptionKey.get(tdaf.getSelectedAssignment()));
534
535
536 DateTime startTime = null;
537 DateTime endTime = null;
538 if(tdaf.getStartTime() != null && tdaf.getEndTime() != null) {
539 startTime = TKUtils.convertDateStringToDateTime(tdaf.getStartDate(), tdaf.getStartTime());
540 endTime = TKUtils.convertDateStringToDateTime(tdaf.getEndDate(), tdaf.getEndTime());
541
542 if (HrContext.isAnyAdmin() || HrContext.isAnyApprover() || HrContext.isAnyPayrollProcessor()) {
543 startTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(startTime, LocalDate.fromDateFields(tdaf.getBeginCalendarEntryDate()));
544 endTime = TkServiceLocator.getGracePeriodService().processGracePeriodRule(endTime, LocalDate.fromDateFields(tdaf.getBeginCalendarEntryDate()));
545 }
546 } else {
547
548 startTime = TKUtils.formatDateTimeStringNoTimezone(tdaf.getStartDate());
549 endTime = TKUtils.formatDateTimeStringNoTimezone(tdaf.getEndDate());
550 }
551
552
553
554 List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
555
556
557
558 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(newTimeBlocks.size());
559 for (TimeBlock tb : newTimeBlocks) {
560 referenceTimeBlocks.add(tb.copy());
561 }
562
563 List<TimeBlock> timeBlocksToAdd = null;
564
565 if (StringUtils.equals(tdaf.getAcrossDays(), "y")
566 && !(endTime.getDayOfYear() - startTime.getDayOfYear() <= 1
567 && endTime.getHourOfDay() == 0)) {
568
569 timeBlocksToAdd = TkServiceLocator.getTimeBlockService().buildTimeBlocksSpanDates(currentAssignment,
570 tdaf.getSelectedEarnCode(), tdaf.getTimesheetDocument(), startTime,
571 endTime, tdaf.getHours(), tdaf.getAmount(), isClockLogCreated, Boolean.parseBoolean(tdaf.getLunchDeleted()),
572 tdaf.getSpanningWeeks(), HrContext.getPrincipalId(), clockLogBeginId, clockLogEndId);
573
574 } else {
575 timeBlocksToAdd = TkServiceLocator.getTimeBlockService().buildTimeBlocks(currentAssignment,
576 tdaf.getSelectedEarnCode(), tdaf.getTimesheetDocument(), startTime,
577 endTime, tdaf.getHours(), tdaf.getAmount(), isClockLogCreated, Boolean.parseBoolean(tdaf.getLunchDeleted()),
578 HrContext.getPrincipalId(), clockLogBeginId, clockLogEndId);
579 }
580
581 TimeBlock existingTimeBlock = null;
582 TimeBlock timeBlockToUpdate = null;
583
584
585 if (tdaf.getTkTimeBlockId() != null) {
586 timeBlockToUpdate = timeBlocksToAdd.get(0);
587 TkServiceLocator.getTimeHourDetailService().removeTimeHourDetails(tdaf.getTkTimeBlockId());
588 timeBlockToUpdate.setTkTimeBlockId(tdaf.getTkTimeBlockId());
589 }
590
591 List<TimeBlock> finalNewTimeBlocks = new ArrayList<TimeBlock>();
592
593 for (TimeBlock tb : newTimeBlocks) {
594 if(!ObjectUtils.equals(tb.getTkTimeBlockId(), tdaf.getTkTimeBlockId())) {
595 finalNewTimeBlocks.add(tb);
596 } else {
597 existingTimeBlock = tb;
598 existingTimeBlock.copy(timeBlockToUpdate);
599 finalNewTimeBlocks.add(existingTimeBlock);
600 }
601 }
602
603 for (TimeBlock tb : timeBlocksToAdd) {
604 if(tdaf.getTkTimeBlockId() != null) {
605 if(!ObjectUtils.equals(tb.getTkTimeBlockId(), tdaf.getTkTimeBlockId())) {
606 finalNewTimeBlocks.add(tb);
607 }
608 } else {
609 finalNewTimeBlocks.add(tb);
610 }
611 }
612
613
614 TkServiceLocator.getTimesheetService().resetTimeBlock(finalNewTimeBlocks, tdaf.getTimesheetDocument().getAsOfDate());
615
616
617
618
619 if(StringUtils.isNotEmpty(tdaf.getOvertimePref())) {
620 for (TimeBlock tb : finalNewTimeBlocks) {
621 if ((StringUtils.isNotEmpty(tdaf.getTkTimeBlockId()) && tdaf.getTkTimeBlockId().equals(tb.getTkTimeBlockId()))
622 || (tb.getBeginTimestamp().equals(startTime) && tb.getEndTimestamp().equals(endTime))) {
623 tb.setOvertimePref(tdaf.getOvertimePref());
624 }
625 }
626 }
627
628 List<Assignment> assignments = tdaf.getTimesheetDocument().getAssignments();
629 List<String> assignmentKeys = new ArrayList<String>();
630 for (Assignment assignment : assignments) {
631 assignmentKeys.add(assignment.getAssignmentKey());
632 }
633
634 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(HrContext.getTargetPrincipalId(), tdaf.getTimesheetDocument().getAsOfDate(), tdaf.getTimesheetDocument().getDocEndDate(), assignmentKeys);
635
636 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, finalNewTimeBlocks, leaveBlocks, tdaf.getCalendarEntry(), tdaf.getTimesheetDocument(), HrContext.getPrincipalId());
637
638 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, finalNewTimeBlocks, HrContext.getPrincipalId());
639
640 generateTimesheetChangedNotification(HrContext.getPrincipalId(), HrContext.getTargetPrincipalId(), tdaf.getDocumentId());
641
642 }
643
644
645
646
647
648
649
650
651 private void updateLeaveBlock(TimeDetailActionForm tdaf) throws Exception {
652
653 String principalId = HrContext.getPrincipalId();
654 String targetPrincipalId = HrContext.getTargetPrincipalId();
655
656 String selectedEarnCode = tdaf.getSelectedEarnCode();
657 String leaveBlockId = tdaf.getLmLeaveBlockId();
658
659 LeaveBlock updatedLeaveBlock = null;
660 updatedLeaveBlock = LmServiceLocator.getLeaveBlockService().getLeaveBlock(leaveBlockId);
661 if (updatedLeaveBlock.isEditable()) {
662 if (!updatedLeaveBlock.getLeaveAmount().equals(tdaf.getLeaveAmount())) {
663 updatedLeaveBlock.setLeaveAmount(tdaf.getLeaveAmount());
664 }
665
666 DateTime beginDate = null;
667 DateTime endDate = null;
668
669 EarnCode earnCode = HrServiceLocator.getEarnCodeService().getEarnCode(selectedEarnCode, updatedLeaveBlock.getLeaveLocalDate());
670 if(earnCode != null && earnCode.getRecordMethod().equalsIgnoreCase(HrConstants.EARN_CODE_TIME)) {
671 if(tdaf.getStartTime() != null && tdaf.getEndTime() != null) {
672 beginDate = TKUtils.convertDateStringToDateTimeWithoutZone(tdaf.getStartDate(), tdaf.getStartTime());
673 endDate = TKUtils.convertDateStringToDateTimeWithoutZone(tdaf.getEndDate(), tdaf.getEndTime());
674 } else {
675 beginDate = TKUtils.formatDateTimeStringNoTimezone(tdaf.getStartDate());
676 endDate = TKUtils.formatDateTimeStringNoTimezone(tdaf.getEndDate());
677 }
678 updatedLeaveBlock.setBeginTimestamp(new Timestamp(beginDate.getMillis()));
679 updatedLeaveBlock.setEndTimestamp(new Timestamp(endDate.getMillis()));
680 updatedLeaveBlock.setLeaveAmount(TKUtils.getHoursBetween(beginDate.getMillis(), endDate.getMillis()));
681 }
682
683 if (!updatedLeaveBlock.getEarnCode().equals(earnCode.getEarnCode())) {
684 updatedLeaveBlock.setEarnCode(earnCode.getEarnCode());
685 }
686
687 LmServiceLocator.getLeaveBlockService().updateLeaveBlock(updatedLeaveBlock, principalId);
688 }
689
690 List<Assignment> assignments = tdaf.getTimesheetDocument().getAssignments();
691 List<String> assignmentKeys = new ArrayList<String>();
692 for (Assignment assignment : assignments) {
693 assignmentKeys.add(assignment.getAssignmentKey());
694 }
695 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(targetPrincipalId, tdaf.getTimesheetDocument().getAsOfDate(), tdaf.getTimesheetDocument().getDocEndDate(), assignmentKeys);
696
697
698 List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
699
700
701 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(newTimeBlocks.size());
702 for (TimeBlock tb : newTimeBlocks) {
703 referenceTimeBlocks.add(tb.copy());
704 }
705 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, leaveBlocks, tdaf.getCalendarEntry(), tdaf.getTimesheetDocument(), principalId);
706
707 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, principalId);
708 generateTimesheetChangedNotification(principalId, targetPrincipalId, tdaf.getDocumentId());
709
710 }
711
712
713 public ActionForward updateTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
714
715 TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
716 Assignment assignment = tdaf.getTimesheetDocument().getAssignment(AssignmentDescriptionKey.get(tdaf.getSelectedAssignment()));
717
718
719 List<TimeBlock> timeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
720 TimeBlock updatedTimeBlock = null;
721 for (TimeBlock tb : timeBlocks) {
722 if (tb.getTkTimeBlockId().compareTo(tdaf.getTkTimeBlockId()) == 0) {
723 updatedTimeBlock = tb;
724 tb.setJobNumber(assignment.getJobNumber());
725 tb.setWorkArea(assignment.getWorkArea());
726 tb.setTask(assignment.getTask());
727 break;
728 }
729 }
730
731 Set<String> earnCodes = new HashSet<String>();
732 if (updatedTimeBlock != null) {
733 List<EarnCode> validEarnCodes = TkServiceLocator.getTimesheetService().getEarnCodesForTime(assignment, updatedTimeBlock.getBeginDateTime().toLocalDate(), true);
734 for (EarnCode e : validEarnCodes) {
735 earnCodes.add(e.getEarnCode());
736 }
737 }
738
739 if (updatedTimeBlock != null
740 && earnCodes.contains(updatedTimeBlock.getEarnCode())) {
741 TkServiceLocator.getTimeBlockService().updateTimeBlock(updatedTimeBlock);
742
743 TimeBlockHistory tbh = new TimeBlockHistory(updatedTimeBlock);
744 tbh.setActionHistory(TkConstants.ACTIONS.UPDATE_TIME_BLOCK);
745 TkServiceLocator.getTimeBlockHistoryService().saveTimeBlockHistory(tbh);
746 }
747
748
749 tdaf.setMethodToCall("addTimeBlock");
750
751 return mapping.findForward("basic");
752 }
753
754
755 public ActionForward actualTimeInquiry(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
756 return mapping.findForward("ati");
757 }
758
759 public ActionForward deleteLunchDeduction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
760
761 TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
762 String timeHourDetailId = tdaf.getTkTimeHourDetailId();
763
764 List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
765 TimeHourDetail thd = TkServiceLocator.getTimeHourDetailService().getTimeHourDetail(timeHourDetailId);
766 for(TimeBlock tb : newTimeBlocks) {
767 if(tb.getTkTimeBlockId().equals(thd.getTkTimeBlockId())) {
768
769 tb.setLunchDeleted(true);
770 }
771 }
772
773 TkServiceLocator.getTimeHourDetailService().removeTimeHourDetail(thd.getTkTimeHourDetailId());
774
775 List<Assignment> assignments = tdaf.getTimesheetDocument().getAssignments();
776 List<String> assignmentKeys = new ArrayList<String>();
777 for (Assignment assignment : assignments) {
778 assignmentKeys.add(assignment.getAssignmentKey());
779 }
780 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(HrContext.getTargetPrincipalId(), tdaf.getTimesheetDocument().getAsOfDate(), tdaf.getTimesheetDocument().getDocEndDate(), assignmentKeys);
781
782 TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks, tdaf.getTimesheetDocument().getAsOfDate());
783
784
785 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, leaveBlocks, tdaf.getCalendarEntry(), tdaf.getTimesheetDocument(), HrContext.getPrincipalId());
786 TkServiceLocator.getTimeBlockService().saveTimeBlocks(newTimeBlocks);
787 tdaf.getTimesheetDocument().setTimeBlocks(newTimeBlocks);
788
789 return mapping.findForward("basic");
790 }
791
792 public ActionForward deleteLeaveBlock(ActionMapping mapping,ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
793 TimeDetailActionForm tdaf = (TimeDetailActionForm) form;
794
795 String principalId = HrContext.getPrincipalId();
796 String targetPrincipalId = HrContext.getTargetPrincipalId();
797 String documentId = tdaf.getDocumentId();
798 String leaveBlockId = tdaf.getLmLeaveBlockId();
799
800 LeaveBlock blockToDelete = LmServiceLocator.getLeaveBlockService().getLeaveBlock(leaveBlockId);
801 if (blockToDelete != null && LmServiceLocator.getLMPermissionService().canDeleteLeaveBlock(HrContext.getPrincipalId(), blockToDelete)) {
802 LmServiceLocator.getLeaveBlockService().deleteLeaveBlock(leaveBlockId, HrContext.getPrincipalId());
803
804
805 List<TimeBlock> newTimeBlocks = tdaf.getTimesheetDocument().getTimeBlocks();
806
807
808 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(newTimeBlocks.size());
809 for (TimeBlock tb : newTimeBlocks) {
810 referenceTimeBlocks.add(tb.copy());
811 }
812 List<Assignment> assignments = tdaf.getTimesheetDocument().getAssignments();
813 List<String> assignmentKeys = new ArrayList<String>();
814 for (Assignment assignment : assignments) {
815 assignmentKeys.add(assignment.getAssignmentKey());
816 }
817 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(principalId, tdaf.getTimesheetDocument().getAsOfDate(), tdaf.getTimesheetDocument().getDocEndDate(), assignmentKeys);
818
819
820 TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks, tdaf.getTimesheetDocument().getAsOfDate());
821 TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.ADD_TIME_BLOCK, newTimeBlocks, leaveBlocks, tdaf.getCalendarEntry(), tdaf.getTimesheetDocument(), HrContext.getPrincipalId());
822 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, HrContext.getPrincipalId());
823 generateTimesheetChangedNotification(principalId, targetPrincipalId, documentId);
824 }
825
826
827 EarnCode ec = HrServiceLocator.getEarnCodeService().getEarnCode(blockToDelete.getEarnCode(), blockToDelete.getLeaveLocalDate());
828 if(ec != null && ec.getEligibleForAccrual().equals("N")) {
829 CalendarEntry ce = HrServiceLocator.getCalendarEntryService()
830 .getCurrentCalendarDatesForLeaveCalendar(blockToDelete.getPrincipalId(), blockToDelete.getLeaveLocalDate().toDateTimeAtStartOfDay());
831 if(ce != null) {
832 LmServiceLocator.getLeaveAccrualService().runAccrual(blockToDelete.getPrincipalId(), ce.getBeginPeriodFullDateTime().toDateTime(), ce.getEndPeriodFullDateTime().toDateTime(), false);
833 }
834 }
835
836 return mapping.findForward("basic");
837 }
838
839 private void generateTimesheetChangedNotification(String principalId, String targetPrincipalId, String documentId) {
840 if (!StringUtils.equals(principalId, targetPrincipalId)) {
841 EntityNamePrincipalName person = KimApiServiceLocator.getIdentityService().getDefaultNamesForPrincipalId(principalId);
842 if (person != null && person.getDefaultName() != null) {
843 String subject = "Timesheet Modification Notice";
844 StringBuilder message = new StringBuilder();
845 message.append("Your Timesheet was changed by ");
846 message.append(person.getDefaultName().getCompositeNameUnmasked());
847 message.append(" on your behalf.");
848 message.append(SystemUtils.LINE_SEPARATOR);
849 message.append(getTimesheetURL(documentId));
850
851 HrServiceLocator.getKPMENotificationService().sendNotification(subject, message.toString(), targetPrincipalId);
852 }
853 }
854 }
855
856 @SuppressWarnings("deprecation")
857 private String getTimesheetURL(String documentId) {
858 Properties params = new Properties();
859 params.put("documentId", documentId);
860 return UrlFactory.parameterizeUrl(getApplicationBaseUrl() + "/TimeDetail.do", params);
861 }
862
863 }