1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.hr.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.Date;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.log4j.Logger;
32 import org.apache.struts.action.ActionForm;
33 import org.apache.struts.action.ActionForward;
34 import org.apache.struts.action.ActionMapping;
35 import org.joda.time.DateTime;
36 import org.joda.time.DateTimeZone;
37 import org.joda.time.Interval;
38 import org.json.simple.JSONArray;
39 import org.json.simple.JSONValue;
40 import org.kuali.hr.time.assignment.Assignment;
41 import org.kuali.hr.time.assignment.AssignmentDescriptionKey;
42 import org.kuali.hr.time.clocklog.ClockLog;
43 import org.kuali.hr.time.collection.rule.TimeCollectionRule;
44 import org.kuali.hr.time.roles.TkUserRoles;
45 import org.kuali.hr.time.roles.UserRoles;
46 import org.kuali.hr.time.service.base.TkServiceLocator;
47 import org.kuali.hr.time.timeblock.TimeBlock;
48 import org.kuali.hr.time.timesheet.TimesheetDocument;
49 import org.kuali.hr.time.timesheet.web.TimesheetAction;
50 import org.kuali.hr.time.util.TKContext;
51 import org.kuali.hr.time.util.TKUser;
52 import org.kuali.hr.time.util.TKUtils;
53 import org.kuali.hr.time.util.TkConstants;
54 import org.kuali.rice.krad.exception.AuthorizationException;
55 import org.kuali.rice.krad.util.GlobalVariables;
56
57 public class ClockAction extends TimesheetAction {
58
59 private static final Logger LOG = Logger.getLogger(ClockAction.class);
60 public static final SimpleDateFormat SDF = new SimpleDateFormat("EEE, MMMM d yyyy HH:mm:ss, zzzz");
61 public static final String SEPERATOR = "[****]+";
62
63 @Override
64 protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
65 super.checkTKAuthorization(form, methodToCall);
66
67 UserRoles roles = TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId());
68 TimesheetDocument doc = TKContext.getCurrentTimesheetDocument();
69
70
71 if (StringUtils.equals(methodToCall, "clockAction") ||
72 StringUtils.equals(methodToCall, "addTimeBlock") ||
73 StringUtils.equals(methodToCall, "editTimeBlock") ||
74 StringUtils.equals(methodToCall, "distributeTimeBlocks") ||
75 StringUtils.equals(methodToCall, "saveNewTimeBlocks") ||
76 StringUtils.equals(methodToCall, "deleteTimeBlock")) {
77 if (!roles.isDocumentWritable(doc)) {
78 throw new AuthorizationException(roles.getPrincipalId(), "ClockAction", "");
79 }
80 }
81 }
82
83
84 @Override
85 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
86 ActionForward forward = super.execute(mapping, form, request, response);
87 ClockActionForm caf = (ClockActionForm) form;
88 caf.setCurrentServerTime(String.valueOf(new Date().getTime()));
89 caf.getUserSystemOffsetServerTime();
90 caf.setShowLunchButton(TkServiceLocator.getSystemLunchRuleService().isShowLunchButton());
91 caf.setAssignmentDescriptions(TkServiceLocator.getAssignmentService().getAssignmentDescriptions(caf.getTimesheetDocument(), true));
92 if (caf.isShowLunchButton()) {
93
94
95
96
97 Map<String, Boolean> assignmentDeptLunchRuleMap = new HashMap<String, Boolean>();
98 if (caf.getTimesheetDocument() != null) {
99 for (Assignment a : caf.getTimesheetDocument().getAssignments()) {
100 String key = AssignmentDescriptionKey.getAssignmentKeyString(a);
101 assignmentDeptLunchRuleMap.put(key, a.getDeptLunchRule() != null);
102 }
103 }
104 caf.setAssignmentLunchMap(assignmentDeptLunchRuleMap);
105 }
106 String principalId = TKUser.getCurrentTargetPersonId();
107 if (principalId != null) {
108 caf.setPrincipalId(principalId);
109 }
110
111
112 if(caf.getTimesheetDocument() == null) {
113
114 if (!GlobalVariables.getMessageMap().hasErrors()) {
115 caf.setErrorMessage("You do not currently have a timesheet. Clock action is not allowed.");
116 }
117 return mapping.findForward("basic");
118 }
119
120 if(caf.getTimesheetDocument().getDocumentHeader().getDocumentStatus().equals(TkConstants.ROUTE_STATUS.ENROUTE)
121 || caf.getTimesheetDocument().getDocumentHeader().getDocumentStatus().equals(TkConstants.ROUTE_STATUS.FINAL)) {
122 caf.setErrorMessage("Your current timesheet is already submitted for Approval. Clock action is not allowed on this timesheet.");
123 return mapping.findForward("basic");
124 }
125
126
127 this.assignShowDistributeButton(caf);
128
129 if(caf.getTimesheetDocument().getDocumentHeader().getDocumentStatus().equals(TkConstants.ROUTE_STATUS.ENROUTE)
130 || caf.getTimesheetDocument().getDocumentHeader().getDocumentStatus().equals(TkConstants.ROUTE_STATUS.FINAL)) {
131 caf.setShowMissedPunchButton(false);
132 } else {
133 caf.setShowMissedPunchButton(true);
134 }
135
136 String tbIdString = caf.getEditTimeBlockId();
137 if (tbIdString != null) {
138 caf.setCurrentTimeBlock(TkServiceLocator.getTimeBlockService().getTimeBlock(caf.getEditTimeBlockId()));
139 }
140
141 ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog(principalId);
142 if (lastClockLog != null) {
143 Timestamp lastClockTimestamp = lastClockLog.getClockTimestamp();
144 String lastClockZone = lastClockLog.getClockTimestampTimezone();
145 if (StringUtils.isEmpty(lastClockZone)) {
146 lastClockZone = TKUtils.getSystemTimeZone();
147 }
148
149
150
151 DateTimeZone zone = DateTimeZone.forID(lastClockZone);
152 DateTime clockWithZone = new DateTime(lastClockTimestamp, zone);
153 caf.setLastClockTimeWithZone(clockWithZone.toDate());
154 caf.setLastClockTimestamp(lastClockTimestamp);
155 caf.setLastClockAction(lastClockLog.getClockAction());
156 }
157
158 if (lastClockLog == null || StringUtils.equals(lastClockLog.getClockAction(), TkConstants.CLOCK_OUT)) {
159 caf.setCurrentClockAction(TkConstants.CLOCK_IN);
160 } else {
161
162 if (StringUtils.equals(lastClockLog.getClockAction(), TkConstants.LUNCH_OUT) && TkServiceLocator.getSystemLunchRuleService().isShowLunchButton()) {
163 caf.setCurrentClockAction(TkConstants.LUNCH_IN);
164 }
165
166
167
168 else {
169 caf.setCurrentClockAction(TkConstants.CLOCK_OUT);
170 }
171
172 String selectedAssignment = new AssignmentDescriptionKey(lastClockLog.getJobNumber(), lastClockLog.getWorkArea(), lastClockLog.getTask()).toAssignmentKeyString();
173 caf.setSelectedAssignment(selectedAssignment);
174 Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(caf.getTimesheetDocument(), selectedAssignment);
175 Map<String, String> assignmentDesc = TkServiceLocator.getAssignmentService().getAssignmentDescriptions(assignment);
176 caf.setAssignmentDescriptions(assignmentDesc);
177
178 }
179
180
181
182 if (StringUtils.equals(GlobalVariables.getUserSession().getPrincipalId(), TKUser.getCurrentTargetPersonId())) {
183 caf.setClockButtonEnabled(true);
184 } else {
185 boolean isApproverOrReviewerForCurrentAssignment = false;
186 String selectedAssignment = StringUtils.EMPTY;
187 if (caf.getAssignmentDescriptions() != null) {
188 if (caf.getAssignmentDescriptions().size() == 1) {
189 for (String assignment : caf.getAssignmentDescriptions().keySet()) {
190 selectedAssignment = assignment;
191 }
192 } else {
193 selectedAssignment = caf.getSelectedAssignment();
194 }
195 }
196 if (StringUtils.isNotBlank(selectedAssignment)) {
197 Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(new AssignmentDescriptionKey(selectedAssignment), TKUtils.getCurrentDate());
198 if (assignment != null) {
199 UserRoles roles = TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId());
200 Long workArea = assignment.getWorkArea();
201 isApproverOrReviewerForCurrentAssignment = roles.getApproverWorkAreas().contains(workArea) || roles.getReviewerWorkAreas().contains(workArea);
202 }
203 }
204 caf.setClockButtonEnabled(isApproverOrReviewerForCurrentAssignment);
205 }
206
207 return forward;
208 }
209
210 public void assignShowDistributeButton(ClockActionForm caf) {
211 caf.setShowDistrubuteButton(false);
212
213 TimesheetDocument timesheetDocument = caf.getTimesheetDocument();
214 if (timesheetDocument != null) {
215 int eligibleAssignmentCount = 0;
216 for (Assignment assignment : timesheetDocument.getAssignments()) {
217 String department = assignment.getJob() != null ? assignment.getJob().getDept() : null;
218 Long workArea = assignment.getWorkArea();
219 String payType = assignment.getJob() != null ? assignment.getJob().getHrPayType() : null;
220 TimeCollectionRule rule = TkServiceLocator.getTimeCollectionRuleService().getTimeCollectionRule(department, workArea, payType, timesheetDocument.getDocEndDate());
221 if (rule != null && rule.isHrsDistributionF()) {
222 eligibleAssignmentCount++;
223 }
224
225
226 if (eligibleAssignmentCount > 1) {
227 caf.setShowDistrubuteButton(true);
228 break;
229 }
230 }
231 }
232 }
233
234
235 public ActionForward clockAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
236 ClockActionForm caf = (ClockActionForm) form;
237
238
239
240 if (StringUtils.isBlank(caf.getSelectedAssignment())) {
241 caf.setErrorMessage("No assignment selected.");
242 return mapping.findForward("basic");
243 }
244 ClockLog previousClockLog = TkServiceLocator.getClockLogService().getLastClockLog(TKUser.getCurrentTargetPersonId());
245 if(previousClockLog != null && StringUtils.equals(caf.getCurrentClockAction(), previousClockLog.getClockAction())){
246 caf.setErrorMessage("The operation is already performed.");
247 return mapping.findForward("basic");
248 }
249 String ip = TKUtils.getIPAddressFromRequest(request);
250 Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(caf.getTimesheetDocument(), caf.getSelectedAssignment());
251
252 List<Assignment> lstAssingmentAsOfToday = TkServiceLocator.getAssignmentService().getAssignments(TKContext.getTargetPrincipalId(), TKUtils.getCurrentDate());
253 boolean foundValidAssignment = false;
254 for(Assignment assign : lstAssingmentAsOfToday){
255 if((assign.getJobNumber().compareTo(assignment.getJobNumber()) ==0) &&
256 (assign.getWorkArea().compareTo(assignment.getWorkArea()) == 0) &&
257 (assign.getTask().compareTo(assignment.getTask()) == 0)){
258 foundValidAssignment = true;
259 break;
260 }
261 }
262
263 if(!foundValidAssignment){
264 caf.setErrorMessage("Assignment is not effective as of today");
265 return mapping.findForward("basic");
266 }
267
268
269 ClockLog clockLog = TkServiceLocator.getClockLogService().processClockLog(new Timestamp(System.currentTimeMillis()), assignment, caf.getPayCalendarDates(), ip,
270 TKUtils.getCurrentDate(), caf.getTimesheetDocument(), caf.getCurrentClockAction(), true, TKUser.getCurrentTargetPersonId());
271
272 caf.setClockLog(clockLog);
273
274 return mapping.findForward("basic");
275 }
276
277 public ActionForward distributeTimeBlocks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
278 ClockActionForm caf = (ClockActionForm) form;
279 caf.findTimeBlocksToDistribute();
280 return mapping.findForward("tb");
281 }
282
283
284 public ActionForward editTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
285 ClockActionForm caf = (ClockActionForm) form;
286 TimeBlock tb = caf.getCurrentTimeBlock();
287 caf.setCurrentAssignmentKey(tb.getAssignmentKey());
288
289 ActionForward forward = mapping.findForward("et");
290
291 return new ActionForward(forward.getPath() + "?editTimeBlockId=" + tb.getTkTimeBlockId().toString());
292
293 }
294 public ActionForward addTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
295 ClockActionForm caf = (ClockActionForm) form;
296 TimeBlock currentTb = caf.getCurrentTimeBlock();
297 List<TimeBlock> newTimeBlocks = caf.getTimesheetDocument().getTimeBlocks();
298 List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(caf.getTimesheetDocument().getTimeBlocks().size());
299 for (TimeBlock tb : caf.getTimesheetDocument().getTimeBlocks()) {
300 referenceTimeBlocks.add(tb.copy());
301 }
302
303 TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, TKContext.getPrincipalId());
304
305 ActionForward forward = mapping.findForward("et");
306
307 return new ActionForward(forward.getPath() + "?editTimeBlockId=" + currentTb.getTkTimeBlockId().toString());
308 }
309
310 public ActionForward saveNewTimeBlocks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
311 ClockActionForm caf = (ClockActionForm)form;
312 String tbId = caf.getTbId();
313 String timesheetDocId = caf.getTsDocId();
314
315 String[] assignments = caf.getNewAssignDesCol().split(SEPERATOR);
316 String[] beginDates = caf.getNewBDCol().split(SEPERATOR);
317 String[] beginTimes = caf.getNewBTCol().split(SEPERATOR);
318 String[] endDates = caf.getNewEDCol().split(SEPERATOR);
319 String[] endTimes = caf.getNewETCol().split(SEPERATOR);
320 String[] hrs = caf.getNewHrsCol().split(SEPERATOR);
321 String earnCode = TkServiceLocator.getTimeBlockService().getTimeBlock(tbId).getEarnCode();
322
323 List<TimeBlock> newTbList = new ArrayList<TimeBlock>();
324 for(int i = 0; i < hrs.length; i++) {
325 BigDecimal hours = new BigDecimal(hrs[i]);
326 Timestamp beginTS = TKUtils.convertDateStringToTimestamp(beginDates[i], beginTimes[i]);
327 Timestamp endTS = TKUtils.convertDateStringToTimestamp(endDates[i], endTimes[i]);
328 String assignString = assignments[i];
329 Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(assignString);
330
331 TimesheetDocument tsDoc = TkServiceLocator.getTimesheetService().getTimesheetDocument(timesheetDocId);
332
333 TimeBlock tb = TkServiceLocator.getTimeBlockService().createTimeBlock(tsDoc, beginTS, endTS, assignment, earnCode, hours,BigDecimal.ZERO, false, false, TKContext.getPrincipalId());
334 newTbList.add(tb);
335 }
336 TkServiceLocator.getTimeBlockService().resetTimeHourDetail(newTbList);
337 TkServiceLocator.getTimeBlockService().saveTimeBlocks(newTbList);
338 TimeBlock oldTB = TkServiceLocator.getTimeBlockService().getTimeBlock(tbId);
339 TkServiceLocator.getTimeBlockService().deleteTimeBlock(oldTB);
340 return mapping.findForward("basic");
341 }
342
343 public ActionForward validateNewTimeBlock(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
344 ClockActionForm caf = (ClockActionForm)form;
345 String tbId = caf.getTbId();
346 String[] assignments = caf.getNewAssignDesCol().split(SEPERATOR);
347 String[] beginDates = caf.getNewBDCol().split(SEPERATOR);
348 String[] beginTimes = caf.getNewBTCol().split(SEPERATOR);
349 String[] endDates = caf.getNewEDCol().split(SEPERATOR);
350 String[] endTimes = caf.getNewETCol().split(SEPERATOR);
351 String[] hrs = caf.getNewHrsCol().split(SEPERATOR);
352
353 List<Interval> newIntervals = new ArrayList<Interval>();
354 JSONArray errorMsgList = new JSONArray();
355
356
357 if(assignments.length != beginDates.length ||
358 assignments.length!= beginTimes.length ||
359 assignments.length != endDates.length ||
360 assignments.length != endTimes.length ||
361 assignments.length != hrs.length) {
362 errorMsgList.add("All fields are required");
363 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
364 return mapping.findForward("ws");
365 }
366
367 for(int i = 0; i < hrs.length; i++) {
368 String index = String.valueOf(i+1);
369
370
371 BigDecimal dc = new BigDecimal(hrs[i]);
372 if (dc.compareTo(new BigDecimal("0")) == 0) {
373 errorMsgList.add("The entered hours for entry " + index + " is not valid.");
374 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
375 return mapping.findForward("ws");
376 }
377
378
379
380 Timestamp beginTS = TKUtils.convertDateStringToTimestampWithoutZone(beginDates[i], beginTimes[i]);
381 Timestamp endTS = TKUtils.convertDateStringToTimestampWithoutZone(endDates[i], endTimes[i]);
382 if ((beginTS.compareTo(endTS) > 0 || endTS.compareTo(beginTS) < 0)) {
383 errorMsgList.add("The time or date for entry " + index + " is not valid.");
384 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
385 return mapping.findForward("ws");
386 }
387
388
389 DateTime start = new DateTime(beginTS);
390 DateTime end = new DateTime(endTS);
391 Interval addedTimeblockInterval = new Interval(start, end);
392 newIntervals.add(addedTimeblockInterval);
393 for (TimeBlock timeBlock : caf.getTimesheetDocument().getTimeBlocks()) {
394 if(timeBlock.getTkTimeBlockId().equals(tbId)) {
395 continue;
396 }
397 if(timeBlock.getHours().compareTo(BigDecimal.ZERO) == 0) {
398 continue;
399 }
400
401 DateTimeZone dateTimeZone = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
402 DateTime timeBlockBeginTimestamp = new DateTime(timeBlock.getBeginTimestamp().getTime(), dateTimeZone).withZoneRetainFields(TKUtils.getSystemDateTimeZone());
403 DateTime timeBlockEndTimestamp = new DateTime(timeBlock.getEndTimestamp().getTime(), dateTimeZone).withZoneRetainFields(TKUtils.getSystemDateTimeZone());
404 Interval timeBlockInterval = new Interval(timeBlockBeginTimestamp, timeBlockEndTimestamp);
405 if (timeBlockInterval.overlaps(addedTimeblockInterval)) {
406 errorMsgList.add("The time block you are trying to add for entry " + index + " overlaps with an existing time block.");
407 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
408 return mapping.findForward("ws");
409 }
410 }
411 }
412
413 if(newIntervals.size() > 1 ) {
414 for(Interval intv1 : newIntervals) {
415 for(Interval intv2 : newIntervals) {
416 if(intv1.equals(intv2)) {
417 continue;
418 }
419 if (intv1.overlaps(intv2)) {
420 errorMsgList.add("There is time overlap between the entries.");
421 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
422 return mapping.findForward("ws");
423 }
424 }
425 }
426 }
427
428 caf.setOutputString(JSONValue.toJSONString(errorMsgList));
429 return mapping.findForward("ws");
430 }
431
432 public ActionForward closeMissedPunchDoc(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
433 return mapping.findForward("closeMissedPunchDoc");
434 }
435
436 }