View Javadoc

1   /**
2    * Copyright 2004-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.hr.lm.request.approval.web;
17  
18  import java.sql.Date;
19  import java.text.DateFormat;
20  import java.text.SimpleDateFormat;
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.Comparator;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import javax.servlet.http.HttpServletRequest;
30  import javax.servlet.http.HttpServletResponse;
31  
32  import org.apache.commons.collections.CollectionUtils;
33  import org.apache.commons.lang.ObjectUtils;
34  import org.apache.commons.lang.StringUtils;
35  import org.apache.log4j.Logger;
36  import org.apache.struts.action.ActionForm;
37  import org.apache.struts.action.ActionForward;
38  import org.apache.struts.action.ActionMapping;
39  import org.hsqldb.lib.StringUtil;
40  import org.json.simple.JSONArray;
41  import org.json.simple.JSONValue;
42  import org.kuali.hr.lm.leaveblock.LeaveBlock;
43  import org.kuali.hr.lm.workflow.LeaveRequestDocument;
44  import org.kuali.hr.time.assignment.Assignment;
45  import org.kuali.hr.time.base.web.ApprovalAction;
46  import org.kuali.hr.time.service.base.TkServiceLocator;
47  import org.kuali.hr.time.util.TKContext;
48  import org.kuali.hr.time.util.TKUser;
49  import org.kuali.hr.time.util.TKUtils;
50  import org.kuali.hr.time.workarea.WorkArea;
51  import org.kuali.rice.kew.api.KewApiServiceLocator;
52  import org.kuali.rice.kew.api.action.ActionItem;
53  import org.kuali.rice.kim.api.identity.Person;
54  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
55  
56  public class LeaveRequestApprovalAction  extends ApprovalAction {
57  	
58      private static final Logger LOG = Logger.getLogger(LeaveRequestApprovalAction.class);
59      public static final String DOC_SEPARATOR = "----";	// separator for documents
60      public static final String ID_SEPARATOR = "____";	// separator for documentId and reason string
61      public static final String DOC_NOT_FOUND = "Leave request document not found with id ";
62      public static final String LEAVE_BLOCK_NOT_FOUND = "Leave Block not found for Leave request document ";
63      
64  	@Override
65  	public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
66          ActionForward forward = super.execute(mapping, form, request, response);
67  		LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form;
68  		
69  		Date currentDate = TKUtils.getCurrentDate();
70  		Set<Long> workAreas = TkServiceLocator.getTkRoleService().getWorkAreasForApprover(TKContext.getPrincipalId(), currentDate);
71  		List<String> principalIds = new ArrayList<String>();
72          for (Long workArea : workAreas) {
73              List<Assignment> assignments = TkServiceLocator.getAssignmentService().getActiveAssignmentsForWorkArea(workArea, currentDate);
74              for (Assignment a : assignments) {
75                  principalIds.add(a.getPrincipalId());
76              }
77          }
78  
79          // Set calendar groups
80          List<String> calGroups =  new ArrayList<String>();
81          if (CollectionUtils.isNotEmpty(principalIds)) {
82              calGroups = TkServiceLocator.getLeaveApprovalService().getUniqueLeavePayGroupsForPrincipalIds(principalIds);
83          }
84          lraaForm.setPayCalendarGroups(calGroups);		
85  		
86  		List<String> depts = new ArrayList<String>(TKContext.getUser().getReportingApprovalDepartments().keySet());
87  		Collections.sort(depts);
88  	    lraaForm.setDepartments(depts);
89  		
90  		// build employee rows to display on the page
91  	    List<ActionItem> items = filterActionsWithSeletedParameters(lraaForm.getSelectedPayCalendarGroup(),
92  				lraaForm.getSelectedDept(), this.getWorkAreaList(lraaForm));
93  		List<LeaveRequestApprovalEmployeeRow> rowList = this.getEmployeeRows(items);
94  		lraaForm.setEmployeeRows(rowList);
95  		return forward;
96  	}
97  	
98  	public ActionForward loadApprovalTab(ActionMapping mapping, ActionForm form,
99  			HttpServletRequest request, HttpServletResponse response) throws Exception {
100 		ActionForward fwd = mapping.findForward("basic");
101 		LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form;
102         Date currentDate = TKUtils.getCurrentDate();
103         
104         //reset state
105         if(StringUtils.isEmpty(lraaForm.getSelectedDept())) {
106         	resetState(form, request);
107         
108 	        Set<Long> workAreas = TkServiceLocator.getTkRoleService().getWorkAreasForApprover(TKContext.getPrincipalId(), currentDate);
109 	        List<String> principalIds = new ArrayList<String>();
110 	        for (Long workArea : workAreas) {
111 	            List<Assignment> assignments = TkServiceLocator.getAssignmentService().getActiveAssignmentsForWorkArea(workArea, currentDate);
112 	            for (Assignment a : assignments) {
113 	                principalIds.add(a.getPrincipalId());
114 	            }
115 	        }
116 	        // Set calendar groups
117 	        List<String> calGroups =  new ArrayList<String>();
118 	        if (CollectionUtils.isNotEmpty(principalIds)) {
119 	            calGroups = TkServiceLocator.getLeaveApprovalService().getUniqueLeavePayGroupsForPrincipalIds(principalIds);
120 	        }
121 	        lraaForm.setPayCalendarGroups(calGroups);
122 	        if (StringUtils.isBlank(lraaForm.getSelectedPayCalendarGroup())
123 	                && CollectionUtils.isNotEmpty(calGroups)) {
124 	        	lraaForm.setSelectedPayCalendarGroup(calGroups.get(0));
125 	        }
126 	        // set departments
127 			List<String> depts = new ArrayList<String>(TKContext.getUser().getReportingApprovalDepartments().keySet());
128 			Collections.sort(depts);
129 		    lraaForm.setDepartments(depts);
130 		    if (StringUtils.isBlank(lraaForm.getSelectedDept())
131 	                && lraaForm.getDepartments().size() == 1) {
132 	        	lraaForm.setSelectedDept(lraaForm.getDepartments().get(0));
133 	        	lraaForm.getWorkAreaDescr().clear();
134 	        	List<WorkArea> workAreaList = TkServiceLocator.getWorkAreaService().getWorkAreas(lraaForm.getSelectedDept(), currentDate);
135 	            for(WorkArea wa : workAreaList){
136 	            	if (TKContext.getUser().getApproverWorkAreas().contains(wa.getWorkArea())
137 	            			|| TKContext.getUser().getReviewerWorkAreas().contains(wa.getWorkArea())) {
138 	            		lraaForm.getWorkAreaDescr().put(wa.getWorkArea(),wa.getDescription()+"("+wa.getWorkArea()+")");
139 	            	}
140 	            }
141 	        }		    
142         }
143         
144         // build employee rows to display on the page
145         List<ActionItem> items = filterActionsWithSeletedParameters(lraaForm.getSelectedPayCalendarGroup(),
146 				lraaForm.getSelectedDept(), this.getWorkAreaList(lraaForm));
147         List<LeaveRequestApprovalEmployeeRow> rowList = this.getEmployeeRows(items);
148         lraaForm.setEmployeeRows(rowList);	     
149         
150         return fwd;
151 	}
152 	
153 	public ActionForward selectNewPayCalendar(ActionMapping mapping, ActionForm form,
154 			HttpServletRequest request, HttpServletResponse response)
155 			throws Exception {
156 		// resets the common fields for approval pages
157 		super.resetMainFields(form);
158 		LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form;
159 		lraaForm.setEmployeeRows(new ArrayList<LeaveRequestApprovalEmployeeRow>());
160 		
161 		return loadApprovalTab(mapping, form, request, response);
162 	}	
163 	
164 	public ActionForward selectNewDept(ActionMapping mapping, ActionForm form,
165 			HttpServletRequest request, HttpServletResponse response)
166 			throws Exception {
167 		LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form;
168 		
169 		Date currentDate = TKUtils.getCurrentDate();
170 		
171 		lraaForm.getWorkAreaDescr().clear();
172     	List<WorkArea> workAreas = TkServiceLocator.getWorkAreaService().getWorkAreas(lraaForm.getSelectedDept(), currentDate);
173         for(WorkArea wa : workAreas){
174         	if (TKContext.getUser().getApproverWorkAreas().contains(wa.getWorkArea())
175         			|| TKContext.getUser().getReviewerWorkAreas().contains(wa.getWorkArea())) {
176         		lraaForm.getWorkAreaDescr().put(wa.getWorkArea(),wa.getDescription()+"("+wa.getWorkArea()+")");
177         	}
178         }
179     	// filter actions with selected calendarGroup, Dept and workarea
180     	List<ActionItem> items = filterActionsWithSeletedParameters(lraaForm.getSelectedPayCalendarGroup(),
181     				lraaForm.getSelectedDept(), this.getWorkAreaList(lraaForm));
182     	List<LeaveRequestApprovalEmployeeRow> rowList = this.getEmployeeRows(items);
183 		lraaForm.setEmployeeRows(rowList);	
184  	
185 		return mapping.findForward("basic");
186 	}
187 	
188 	public ActionForward selectNewWorkArea(ActionMapping mapping, ActionForm form,
189 			HttpServletRequest request, HttpServletResponse response)
190 			throws Exception {
191 		LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form;
192 		    
193 		// filter actions with selected calendarGroup, Dept and workarea
194     	List<ActionItem> items = filterActionsWithSeletedParameters(lraaForm.getSelectedPayCalendarGroup(),
195     				lraaForm.getSelectedDept(), this.getWorkAreaList(lraaForm));
196     	List<LeaveRequestApprovalEmployeeRow> rowList = this.getEmployeeRows(items);
197 		lraaForm.setEmployeeRows(rowList);
198         
199 		return mapping.findForward("basic");
200 	}
201 	
202 	private List<ActionItem> filterActionsWithSeletedParameters(String calGroup, String dept, List<String> workAreaList) {
203 		String principalId = TKUser.getCurrentTargetPerson().getPrincipalId();
204 		List<ActionItem> actionList = KewApiServiceLocator.getActionListService().getActionItemsForPrincipal(principalId);
205 		List<ActionItem> resultsList = new ArrayList<ActionItem>();
206 
207 		Date currentDate = TKUtils.getCurrentDate();
208 		List<String> principalIds = TkServiceLocator.getLeaveApprovalService()
209  			.getLeavePrincipalIdsWithSearchCriteria(workAreaList, calGroup, currentDate, currentDate, currentDate);    
210 		
211 		if(CollectionUtils.isNotEmpty(principalIds)) {
212 			for(ActionItem anAction : actionList) {
213 				String docId = anAction.getDocumentId();
214 				if(anAction.getDocName().equals(LeaveRequestDocument.LEAVE_REQUEST_DOCUMENT_TYPE)) {
215 					LeaveRequestDocument lrd = TkServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocument(docId);
216 					if(lrd != null) {
217 						LeaveBlock lb = lrd.getLeaveBlock();
218 						if(lb != null) {
219 							if(principalIds.contains(lb.getPrincipalId())) {
220 								resultsList.add(anAction);
221 							}
222 						}
223 					}
224 				}
225 			}
226 		}
227         
228         return resultsList;
229 	}
230 	
231 	private List<String> getWorkAreaList(LeaveRequestApprovalActionForm lraaForm) {
232 		List<String> workAreaList = new ArrayList<String>();
233 	    if(StringUtil.isEmpty(lraaForm.getSelectedWorkArea())) {
234 	    	for(Long aKey : lraaForm.getWorkAreaDescr().keySet()) {
235 	    		workAreaList.add(aKey.toString());
236 	    	}
237 	    } else {
238 	    	workAreaList.add(lraaForm.getSelectedWorkArea());
239 	    }
240 	    return workAreaList;
241 	}
242 	
243 	public void resetState(ActionForm form, HttpServletRequest request) {
244 		LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form;
245     	lraaForm.getDepartments().clear();
246     	lraaForm.getWorkAreaDescr().clear();
247     	lraaForm.setEmployeeRows(new ArrayList<LeaveRequestApprovalEmployeeRow>());
248     	lraaForm.setSelectedDept(null);
249     	lraaForm.setSearchField(null);
250     	lraaForm.setSearchTerm(null);
251 	}
252 	
253 	public ActionForward takeActionOnEmployee(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
254 		LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form;
255 		
256 		if(StringUtils.isNotEmpty(lraaForm.getApproveList())) {
257 			String[] approveList = lraaForm.getApproveList().split(DOC_SEPARATOR);
258 			for(String eachAction : approveList){
259 				String[] fields = eachAction.split(ID_SEPARATOR);
260 				String docId = fields[0];	// leave request document id
261 				String reasonString = fields.length > 1 ? fields[1] : ""; 	// approve reason text, could be empty
262 				TkServiceLocator.getLeaveRequestDocumentService().approveLeave(docId, TKContext.getPrincipalId(), reasonString);
263 				// leave block's status is changed to "approved" in postProcessor of LeaveRequestDocument
264 			}
265 		}
266 		if(StringUtils.isNotEmpty(lraaForm.getDisapproveList())) {
267 			String[] disapproveList = lraaForm.getDisapproveList().split(DOC_SEPARATOR);
268 			for(String eachAction : disapproveList){
269 				String[] fields = eachAction.split(ID_SEPARATOR);
270 				String docId = fields[0];	// leave request document id
271 				String reasonString = fields.length > 1 ? fields[1] : ""; 	// disapprove reason
272 				TkServiceLocator.getLeaveRequestDocumentService().disapproveLeave(docId, TKContext.getPrincipalId(), reasonString);
273 				// leave block's status is changed to "disapproved" in postProcessor of LeaveRequestDocument	
274 			}
275 		}
276 		if(StringUtils.isNotEmpty(lraaForm.getDeferList())) {
277 			String[] deferList = lraaForm.getDeferList().split(DOC_SEPARATOR);
278 			for(String eachAction : deferList){
279 				String[] fields = eachAction.split(ID_SEPARATOR);
280 				String docId = fields[0];	// leave request document id
281 				String reasonString =  fields.length > 1 ? fields[1] : ""; 	// defer reason
282 				TkServiceLocator.getLeaveRequestDocumentService().deferLeave(docId, TKContext.getPrincipalId(), reasonString);
283 				// leave block's status is changed to "deferred" in postProcessor of LeaveRequestDocument	
284 			}
285 		}
286 		return mapping.findForward("basic");
287 	}
288 
289 	private List<LeaveRequestApprovalEmployeeRow> getEmployeeRows(List<ActionItem> actionList) {
290 		List<LeaveRequestApprovalEmployeeRow> empRowList = new ArrayList<LeaveRequestApprovalEmployeeRow>();
291 		Map<String, List<LeaveRequestDocument>> docMap = new HashMap<String, List<LeaveRequestDocument>>();
292 		for(ActionItem action : actionList) {
293 			if(action.getDocName().equals(LeaveRequestDocument.LEAVE_REQUEST_DOCUMENT_TYPE)) {
294 				String docId = action.getDocumentId();
295 				LeaveRequestDocument lrd = TkServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocument(docId);
296 				if(lrd != null) {
297 					LeaveBlock lb = lrd.getLeaveBlock();
298 					if(lb != null) {
299 						String lbPrincipalId = lb.getPrincipalId();
300 						List<LeaveRequestDocument> docList = docMap.get(lbPrincipalId) == null ? new ArrayList<LeaveRequestDocument>() : docMap.get(lbPrincipalId);
301 						docList.add(lrd);
302 						docMap.put(lbPrincipalId, docList);
303 					}
304 				}
305 				
306 			}
307 		}
308 		for (Map.Entry<String, List<LeaveRequestDocument>> entry : docMap.entrySet()) {
309 			LeaveRequestApprovalEmployeeRow aRow = this.getAnEmployeeRow(entry.getKey(), entry.getValue());
310 			if(aRow != null) {
311 				empRowList.add(aRow);
312 			}
313 		}
314 		// sort list by employee name
315 		Collections.sort(empRowList, new Comparator<LeaveRequestApprovalEmployeeRow>() {
316 			@Override
317 			public int compare(LeaveRequestApprovalEmployeeRow row1, LeaveRequestApprovalEmployeeRow row2) {
318 				return ObjectUtils.compare(row1.getEmployeeName(), row2.getEmployeeName());
319 			}
320     	});		
321 		
322 		return empRowList;
323 	}
324 	
325 	private LeaveRequestApprovalEmployeeRow getAnEmployeeRow(String principalId, List<LeaveRequestDocument> docList) {
326 		if(CollectionUtils.isEmpty(docList) || StringUtils.isEmpty(principalId)) {
327 			return null;
328 		}
329 		Person principal = KimApiServiceLocator.getPersonService().getPerson(principalId);
330 		if(principal == null) {
331 			return null;
332 		}
333 		LeaveRequestApprovalEmployeeRow empRow = new LeaveRequestApprovalEmployeeRow();
334 		empRow.setPrincipalId(principalId);
335 		empRow.setEmployeeName(principal.getName());
336 		List<LeaveRequestApprovalRow> rowList = new ArrayList<LeaveRequestApprovalRow>();
337 		for(LeaveRequestDocument lrd : docList) {
338 			if(lrd == null) {
339 				return null;
340 			}
341 			LeaveBlock lb = lrd.getLeaveBlock();
342 			if(lb == null) {
343 				return null;
344 			}
345 			LeaveRequestApprovalRow aRow = new LeaveRequestApprovalRow();
346 			aRow.setLeaveRequestDocId(lrd.getDocumentNumber());
347 			aRow.setLeaveCode(lb.getEarnCode());
348 			aRow.setRequestedDate(TKUtils.formatDate(lb.getLeaveDate()));
349 			aRow.setRequestedHours(lb.getLeaveAmount().toString());
350 			aRow.setDescription(lrd.getDescription());
351 			DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
352 			aRow.setSubmittedTime(df.format( new Date(lrd.getDocumentHeader().getWorkflowDocument().getDateCreated().getMillis())));
353 			rowList.add(aRow);
354 		}
355 		// sort list by date
356 		if(CollectionUtils.isNotEmpty(rowList)) {
357 			Collections.sort(rowList, new Comparator<LeaveRequestApprovalRow>() {
358 				@Override
359 				public int compare(LeaveRequestApprovalRow row1, LeaveRequestApprovalRow row2) {
360 					return ObjectUtils.compare(row1.getRequestedDate(), row2.getRequestedDate());
361 				}
362 	    	});
363 			empRow.setLeaveRequestList(rowList);
364 		}
365 		return empRow;
366 	}
367 
368 	@SuppressWarnings("unchecked")
369 	public ActionForward validateActions(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
370 		LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form;
371 		JSONArray errorMsgList = new JSONArray();
372         List<String> errors = new ArrayList<String>();
373         if(StringUtils.isEmpty(lraaForm.getApproveList()) 
374 	        	&& StringUtils.isEmpty(lraaForm.getDisapproveList())
375 	        	&& StringUtils.isEmpty(lraaForm.getDeferList())) {
376         	errors.add("No Actions selected. Please try again.");
377         } else {
378 			if(StringUtils.isNotEmpty(lraaForm.getApproveList())) {
379 				String[] approveList = lraaForm.getApproveList().split(DOC_SEPARATOR);
380 				for(String eachAction : approveList){
381 					String[] fields = eachAction.split(ID_SEPARATOR);
382 					String docId = fields[0];	// leave request document id
383 					LeaveRequestDocument lrd = TkServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocument(docId);
384 					if(lrd == null) {
385 						errors.add(DOC_NOT_FOUND + docId);
386 						break;
387 					} else {
388 						LeaveBlock lb = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lrd.getLmLeaveBlockId());
389 						if(lb == null) {
390 							errors.add(LEAVE_BLOCK_NOT_FOUND + docId);
391 							break;
392 						}
393 					}
394 				}
395 			}
396 			if(StringUtils.isNotEmpty(lraaForm.getDisapproveList())) {
397 				String[] disapproveList = lraaForm.getDisapproveList().split(DOC_SEPARATOR);
398 				for(String eachAction : disapproveList){
399 					String[] fields = eachAction.split(ID_SEPARATOR);
400 					String docId = fields[0];	// leave request document id
401 					String reasonString = fields.length > 1 ? fields[1] : ""; 	// disapprove reason
402 					if(StringUtils.isEmpty(reasonString)) {
403 						errors.add("Reason is required for Disapprove action");
404 						break;
405 					} else {
406 						LeaveRequestDocument lrd = TkServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocument(docId);
407 						if(lrd == null) {
408 							errors.add(DOC_NOT_FOUND + docId);
409 							break;
410 						}else {
411 							LeaveBlock lb = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lrd.getLmLeaveBlockId());
412 							if(lb == null) {
413 								errors.add(LEAVE_BLOCK_NOT_FOUND + docId);
414 								break;
415 							}
416 						}
417 					}
418 				}
419 			}
420 			if(StringUtils.isNotEmpty(lraaForm.getDeferList())) {
421 				String[] deferList = lraaForm.getDeferList().split(DOC_SEPARATOR);
422 				for(String eachAction : deferList){
423 					String[] fields = eachAction.split(ID_SEPARATOR);
424 					String docId = fields[0];	// leave request document id
425 					String reasonString =  fields.length > 1 ? fields[1] : ""; 	// defer reason
426 					if(StringUtils.isEmpty(reasonString)) {
427 						errors.add("Reason is required for Defer action");
428 						break;
429 					} else {
430 						LeaveRequestDocument lrd = TkServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocument(docId);
431 						if(lrd == null) {
432 							errors.add(DOC_NOT_FOUND + docId);
433 							break;
434 						}else {
435 							LeaveBlock lb = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lrd.getLmLeaveBlockId());
436 							if(lb == null) {
437 								errors.add(LEAVE_BLOCK_NOT_FOUND + docId);
438 								break;
439 							}
440 						}
441 					}
442 				}
443 			}
444         }
445         errorMsgList.addAll(errors);
446         lraaForm.setOutputString(JSONValue.toJSONString(errorMsgList));
447         return mapping.findForward("ws");
448     }	
449 }