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