001 /** 002 * Copyright 2004-2013 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.hr.lm.request.approval.web; 017 018 import java.sql.Date; 019 import java.text.DateFormat; 020 import java.text.SimpleDateFormat; 021 import java.util.ArrayList; 022 import java.util.Collections; 023 import java.util.Comparator; 024 import java.util.HashMap; 025 import java.util.List; 026 import java.util.Map; 027 import java.util.Set; 028 029 import javax.servlet.http.HttpServletRequest; 030 import javax.servlet.http.HttpServletResponse; 031 032 import org.apache.commons.collections.CollectionUtils; 033 import org.apache.commons.lang.ObjectUtils; 034 import org.apache.commons.lang.StringUtils; 035 import org.apache.log4j.Logger; 036 import org.apache.struts.action.ActionForm; 037 import org.apache.struts.action.ActionForward; 038 import org.apache.struts.action.ActionMapping; 039 import org.hsqldb.lib.StringUtil; 040 import org.json.simple.JSONArray; 041 import org.json.simple.JSONValue; 042 import org.kuali.hr.lm.leaveblock.LeaveBlock; 043 import org.kuali.hr.lm.workflow.LeaveRequestDocument; 044 import org.kuali.hr.time.assignment.Assignment; 045 import org.kuali.hr.time.base.web.ApprovalAction; 046 import org.kuali.hr.time.service.base.TkServiceLocator; 047 import org.kuali.hr.time.util.TKContext; 048 import org.kuali.hr.time.util.TKUser; 049 import org.kuali.hr.time.util.TKUtils; 050 import org.kuali.hr.time.workarea.WorkArea; 051 import org.kuali.rice.kew.api.KewApiServiceLocator; 052 import org.kuali.rice.kew.api.action.ActionItem; 053 import org.kuali.rice.kim.api.identity.Person; 054 import org.kuali.rice.kim.api.services.KimApiServiceLocator; 055 056 public class LeaveRequestApprovalAction extends ApprovalAction { 057 058 private static final Logger LOG = Logger.getLogger(LeaveRequestApprovalAction.class); 059 public static final String DOC_SEPARATOR = "----"; // separator for documents 060 public static final String ID_SEPARATOR = "____"; // separator for documentId and reason string 061 public static final String DOC_NOT_FOUND = "Leave request document not found with id "; 062 public static final String LEAVE_BLOCK_NOT_FOUND = "Leave Block not found for Leave request document "; 063 064 @Override 065 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 066 ActionForward forward = super.execute(mapping, form, request, response); 067 LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form; 068 069 Date currentDate = TKUtils.getCurrentDate(); 070 Set<Long> workAreas = TkServiceLocator.getTkRoleService().getWorkAreasForApprover(TKContext.getPrincipalId(), currentDate); 071 List<String> principalIds = new ArrayList<String>(); 072 for (Long workArea : workAreas) { 073 List<Assignment> assignments = TkServiceLocator.getAssignmentService().getActiveAssignmentsForWorkArea(workArea, currentDate); 074 for (Assignment a : assignments) { 075 principalIds.add(a.getPrincipalId()); 076 } 077 } 078 079 // Set calendar groups 080 List<String> calGroups = new ArrayList<String>(); 081 if (CollectionUtils.isNotEmpty(principalIds)) { 082 calGroups = TkServiceLocator.getLeaveApprovalService().getUniqueLeavePayGroupsForPrincipalIds(principalIds); 083 } 084 lraaForm.setPayCalendarGroups(calGroups); 085 086 List<String> depts = new ArrayList<String>(TKContext.getUser().getReportingApprovalDepartments().keySet()); 087 Collections.sort(depts); 088 lraaForm.setDepartments(depts); 089 090 // build employee rows to display on the page 091 List<ActionItem> items = filterActionsWithSeletedParameters(lraaForm.getSelectedPayCalendarGroup(), 092 lraaForm.getSelectedDept(), this.getWorkAreaList(lraaForm)); 093 List<LeaveRequestApprovalEmployeeRow> rowList = this.getEmployeeRows(items); 094 lraaForm.setEmployeeRows(rowList); 095 return forward; 096 } 097 098 public ActionForward loadApprovalTab(ActionMapping mapping, ActionForm form, 099 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 }