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