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 org.apache.commons.collections.CollectionUtils; 019 import org.apache.commons.lang.ObjectUtils; 020 import org.apache.commons.lang.StringUtils; 021 import org.apache.log4j.Logger; 022 import org.apache.struts.action.ActionForm; 023 import org.apache.struts.action.ActionForward; 024 import org.apache.struts.action.ActionMapping; 025 import org.hsqldb.lib.StringUtil; 026 import org.json.simple.JSONArray; 027 import org.json.simple.JSONValue; 028 import org.kuali.hr.lm.leaveblock.LeaveBlock; 029 import org.kuali.hr.lm.workflow.LeaveRequestDocument; 030 import org.kuali.hr.time.assignment.Assignment; 031 import org.kuali.hr.time.base.web.ApprovalAction; 032 import org.kuali.hr.time.service.base.TkServiceLocator; 033 import org.kuali.hr.time.util.TKContext; 034 import org.kuali.hr.time.util.TKUser; 035 import org.kuali.hr.time.util.TKUtils; 036 import org.kuali.hr.time.workarea.WorkArea; 037 import org.kuali.rice.kew.api.KewApiServiceLocator; 038 import org.kuali.rice.kew.api.action.ActionItem; 039 import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName; 040 import org.kuali.rice.kim.api.services.KimApiServiceLocator; 041 042 import javax.servlet.http.HttpServletRequest; 043 import javax.servlet.http.HttpServletResponse; 044 import java.sql.Date; 045 import java.text.DateFormat; 046 import java.text.SimpleDateFormat; 047 import java.util.*; 048 049 public class LeaveRequestApprovalAction extends ApprovalAction { 050 051 private static final Logger LOG = Logger.getLogger(LeaveRequestApprovalAction.class); 052 public static final String DOC_SEPARATOR = "----"; // separator for documents 053 public static final String ID_SEPARATOR = "____"; // separator for documentId and reason string 054 public static final String DOC_NOT_FOUND = "Leave request document not found with id "; 055 public static final String LEAVE_BLOCK_NOT_FOUND = "Leave Block not found for Leave request document "; 056 057 @Override 058 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 059 ActionForward forward = super.execute(mapping, form, request, response); 060 LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form; 061 062 Date currentDate = TKUtils.getCurrentDate(); 063 Set<Long> workAreas = TkServiceLocator.getTkRoleService().getWorkAreasForApprover(TKContext.getPrincipalId(), currentDate); 064 List<String> principalIds = new ArrayList<String>(); 065 for (Long workArea : workAreas) { 066 List<Assignment> assignments = TkServiceLocator.getAssignmentService().getActiveAssignmentsForWorkArea(workArea, currentDate); 067 for (Assignment a : assignments) { 068 principalIds.add(a.getPrincipalId()); 069 } 070 } 071 072 // Set calendar groups 073 List<String> calGroups = new ArrayList<String>(); 074 if (CollectionUtils.isNotEmpty(principalIds)) { 075 calGroups = TkServiceLocator.getLeaveApprovalService().getUniqueLeavePayGroupsForPrincipalIds(principalIds); 076 } 077 lraaForm.setPayCalendarGroups(calGroups); 078 079 List<String> depts = new ArrayList<String>(TKUser.getReportingApprovalDepartments().keySet()); 080 Collections.sort(depts); 081 lraaForm.setDepartments(depts); 082 083 // build employee rows to display on the page 084 List<ActionItem> items = filterActionsWithSeletedParameters(lraaForm.getSelectedPayCalendarGroup(), 085 lraaForm.getSelectedDept(), this.getWorkAreaList(lraaForm)); 086 List<LeaveRequestApprovalEmployeeRow> rowList = this.getEmployeeRows(items); 087 lraaForm.setEmployeeRows(rowList); 088 return forward; 089 } 090 091 public ActionForward loadApprovalTab(ActionMapping mapping, ActionForm form, 092 HttpServletRequest request, HttpServletResponse response) throws Exception { 093 ActionForward fwd = mapping.findForward("basic"); 094 LeaveRequestApprovalActionForm lraaForm = (LeaveRequestApprovalActionForm) form; 095 Date currentDate = TKUtils.getCurrentDate(); 096 097 //reset state 098 if(StringUtils.isEmpty(lraaForm.getSelectedDept())) { 099 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 }