View Javadoc
1   /**
2    * Copyright 2004-2015 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.kpme.tklm.leave.service.permission;
17  
18  import java.math.BigDecimal;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.collections.CollectionUtils;
24  import org.apache.commons.lang.StringUtils;
25  import org.joda.time.DateTime;
26  import org.joda.time.LocalDate;
27  import org.kuali.kpme.core.KPMENamespace;
28  import org.kuali.kpme.core.block.CalendarBlockPermissions;
29  import org.kuali.kpme.core.calendar.entry.CalendarEntry;
30  import org.kuali.kpme.core.department.Department;
31  import org.kuali.kpme.core.job.Job;
32  import org.kuali.kpme.core.role.KPMERole;
33  import org.kuali.kpme.core.service.HrServiceLocator;
34  import org.kuali.kpme.core.service.permission.HrPermissionServiceBase;
35  import org.kuali.kpme.core.util.HrConstants;
36  import org.kuali.kpme.core.util.HrContext;
37  import org.kuali.kpme.tklm.common.LMConstants;
38  import org.kuali.kpme.tklm.leave.block.LeaveBlock;
39  import org.kuali.kpme.tklm.leave.calendar.service.LeaveCalendarService;
40  import org.kuali.kpme.tklm.leave.request.service.LeaveRequestDocumentService;
41  import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
42  import org.kuali.kpme.tklm.leave.timeoff.SystemScheduledTimeOff;
43  import org.kuali.kpme.tklm.leave.workflow.LeaveRequestDocument;
44  import org.kuali.kpme.tklm.time.service.TkServiceLocator;
45  import org.kuali.kpme.tklm.time.util.TkContext;
46  import org.kuali.kpme.tklm.time.workflow.TimesheetDocumentHeader;
47  import org.kuali.rice.kew.api.KewApiServiceLocator;
48  import org.kuali.rice.kew.api.action.ActionType;
49  import org.kuali.rice.kew.api.action.ValidActions;
50  import org.kuali.rice.kew.api.document.DocumentStatus;
51  import org.kuali.rice.kim.api.KimConstants;
52  import org.kuali.rice.krad.util.KRADConstants;
53  
54  public class LMPermissionServiceImpl extends HrPermissionServiceBase implements LMPermissionService {
55  	
56  	private LeaveCalendarService leaveCalendarService;
57  	private LeaveRequestDocumentService leaveRequestDocumentService;
58  	
59  	@Override
60  	public boolean isAuthorized(String principalId, String permissionName, DateTime asOfDate) {
61  		Map<String, String> qualification = new HashMap<String, String>();
62  		
63  		return getPermissionService().isAuthorized(principalId, KPMENamespace.KPME_LM.getNamespaceCode(), permissionName, qualification);
64  	}
65  	
66  	@Override
67  	public boolean isAuthorized(String principalId, String permissionName, Map<String, String> qualification, DateTime asOfDate) {
68  		return getPermissionService().isAuthorized(principalId, KPMENamespace.KPME_LM.getNamespaceCode(), permissionName, qualification);
69  	}
70      
71      @Override
72      public boolean canViewLeaveRequest(String principalId, String documentId) {
73      	return canSuperUserAdministerLeaveRequest(principalId, documentId) 
74      			|| isAuthorizedByTemplate(principalId, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, documentId);
75      }
76      
77      @Override
78      public boolean canEditLeaveRequest(String principalId, String documentId) {
79      	return canSuperUserAdministerLeaveRequest(principalId, documentId) 
80      			|| isAuthorizedByTemplate(principalId, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, documentId);
81      }
82      
83      @Override
84      public boolean canSubmitLeaveRequest(String principalId, String documentId) {
85          return canSuperUserAdministerLeaveRequest(principalId, documentId) 
86          		|| isAuthorizedByTemplate(principalId, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE, KimConstants.PermissionTemplateNames.ROUTE_DOCUMENT, documentId);
87      }
88      
89      @Override
90      public boolean canApproveLeaveRequest(String principalId, String documentId) {
91      	boolean canApproveLeaveRequest = false;
92      	
93      	ValidActions validActions = KewApiServiceLocator.getWorkflowDocumentActionsService().determineValidActions(documentId, principalId);
94      	
95      	if (validActions.getValidActions() != null) {
96      		canApproveLeaveRequest = validActions.getValidActions().contains(ActionType.APPROVE);
97      	}
98      	
99      	return canApproveLeaveRequest;
100     }
101     
102     @Override
103     public boolean canSuperUserAdministerLeaveRequest(String principalId, String documentId) {
104         return isAuthorizedByTemplate(principalId, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE, "Administer Routing for Document", documentId);
105     }
106     
107     private boolean isAuthorizedByTemplate(String principalId, String namespaceCode, String permissionTemplateName, String documentId) {
108     	boolean isAuthorizedByTemplate = false;
109 
110 /*    	LeaveRequestDocument lrd = LmServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocument(documentId);
111     	
112     	if (lrd != null) {
113     		String documentTypeName = LeaveRequestDocument.LEAVE_REQUEST_DOCUMENT_TYPE;
114         	DocumentStatus documentStatus = DocumentStatus.fromCode(lrd.getActionCode());
115         	
116         	isAuthorizedByTemplate = isAuthorizedByTemplate(principalId, namespaceCode, permissionTemplateName, documentTypeName, documentId, documentStatus);
117     	}*/
118     	
119     	return isAuthorizedByTemplate;
120     }
121     
122     @Override
123 	public boolean isAuthorizedByTemplate(String principalId, String namespaceCode, String permissionTemplateName, Map<String, String> permissionDetails, DateTime asOfDate) {
124 		Map<String, String> qualification = new HashMap<String, String>();
125 		
126 		return isAuthorizedByTemplate(principalId, namespaceCode, permissionTemplateName, permissionDetails, qualification, asOfDate);
127 	}
128 	
129     @Override
130 	public boolean isAuthorizedByTemplate(String principalId, String namespaceCode, String permissionTemplateName, Map<String, String> permissionDetails, Map<String, String> qualification, DateTime asOfDate) {
131 		return getPermissionService().isAuthorizedByTemplate(principalId, namespaceCode, permissionTemplateName, permissionDetails, qualification);
132 	}
133 
134     private boolean updateCanEditLeavePerm(String principalId, CalendarBlockPermissions perms, boolean canEditAll) {
135         perms.putCanEdit(principalId, canEditAll);
136         HrServiceLocator.getHRPermissionService().updateLeaveBlockPermissions(perms);
137         return canEditAll;
138     }
139 
140     @Override
141     public boolean canEditLeaveBlock(String principalId, LeaveBlock leaveBlock) {
142         if (principalId != null) {
143             CalendarBlockPermissions perms = HrServiceLocator.getHRPermissionService().getLeaveBlockPermissions(leaveBlock.getLmLeaveBlockId());
144             Boolean canEdit = perms.isPrincipalCanEdit(principalId);
145 
146             if (canEdit != null) {
147                 return canEdit;
148             }
149         	String documentId = leaveBlock.getDocumentId();
150         	if (StringUtils.isBlank(documentId)) {
151         		TimesheetDocumentHeader timesheetDocumentHeader = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeaderForDate(principalId, leaveBlock.getLeaveLocalDate().toDateTimeAtStartOfDay());
152         		if (timesheetDocumentHeader != null) {
153         			documentId = timesheetDocumentHeader.getDocumentId();
154         		}
155         	}
156         	if (StringUtils.isNotBlank(documentId)) {
157         		DocumentStatus documentStatus = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(documentId);
158         		if (DocumentStatus.CANCELED.equals(documentStatus) || DocumentStatus.DISAPPROVED.equals(documentStatus)) {
159                     return updateCanEditLeavePerm(principalId, perms, false);
160         		}
161         	}
162 	 	 	 	
163             String blockType = leaveBlock.getLeaveBlockType();
164             String requestStatus = leaveBlock.getRequestStatus();
165             if (StringUtils.equals(HrConstants.REQUEST_STATUS.DISAPPROVED, requestStatus)) {
166                 return updateCanEditLeavePerm(principalId, perms, false);
167             }
168             if (StringUtils.equals(HrConstants.REQUEST_STATUS.APPROVED, requestStatus)) {
169             	List<LeaveRequestDocument> docList= LmServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocumentsByLeaveBlockId(leaveBlock.getLmLeaveBlockId());
170             	if(CollectionUtils.isEmpty(docList)) {
171             		// not a leave request. if this is a leave request, do further checking on it
172                     return updateCanEditLeavePerm(principalId, perms, false);
173             	}            	
174             }
175             if (StringUtils.isBlank(blockType)
176                     || StringUtils.equals(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR, blockType)
177                     || StringUtils.equals(LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR, blockType)) {
178 
179 //            	if (!TkContext.isDepartmentAdmin()
180 //                        || HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER.getRoleName(), leaveBlock.getWorkArea(), new DateTime())) {
181             	if(this.userHasRolesToEditLeaveBlock(principalId, leaveBlock)) {
182                     return updateCanEditLeavePerm(principalId, perms, true);
183             	}
184             } else if (LMConstants.LEAVE_BLOCK_TYPE.LEAVE_PAYOUT.equals(blockType)
185                     || LMConstants.LEAVE_BLOCK_TYPE.DONATION_MAINT.equals(blockType)
186                     || LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER.equals(blockType)
187                     || LMConstants.LEAVE_BLOCK_TYPE.LEAVE_ADJUSTMENT_MAINT.equals(blockType)) {
188                 if (HrContext.isSystemAdmin()) {
189                     return updateCanEditLeavePerm(principalId, perms, true);
190                 }
191             }
192             // kpme-1689
193             if(StringUtils.equals(LMConstants.LEAVE_BLOCK_TYPE.ACCRUAL_SERVICE, blockType)
194             		&& StringUtils.isNotEmpty(leaveBlock.getScheduleTimeOffId())
195             		&& leaveBlock.getLeaveAmount().compareTo(BigDecimal.ZERO) == -1) {
196             	if(HrContext.isSystemAdmin()) {
197                     return updateCanEditLeavePerm(principalId, perms, true);
198             	}
199             	SystemScheduledTimeOff ssto = LmServiceLocator.getSysSchTimeOffService().getSystemScheduledTimeOff(leaveBlock.getScheduleTimeOffId());
200             	if(ssto != null && !StringUtils.equals(LMConstants.UNUSED_TIME.NO_UNUSED, ssto.getUnusedTime())) {
201                     return updateCanEditLeavePerm(principalId, perms, true);
202             	}
203             }
204         }
205 
206         return false;
207     }
208     
209     @Override
210     public boolean userHasRolesToEditLeaveBlock(String principalId, LeaveBlock aLeaveBlock) {
211     	// Location and sys admins along with approver,reviewer, payroll processors should have access to edit calendar
212     	// department admins and view only should not have access to edit timesheets. view only roles are location view only and global view only
213     	// location and sys admin roles should have priority unless it is their own calendar.
214 
215         if (StringUtils.equals(TkContext.getTargetPrincipalId(), principalId)) {
216             return true;
217         }
218 	    // use if blocks to check the roles in priority order and returns true so we don't need to check all possible roles for performance purpose 
219     	// system admin
220 	    if(HrServiceLocator.getKPMEGroupService().isMemberOfSystemAdministratorGroup(principalId, LocalDate.now().toDateTimeAtStartOfDay())) {
221 	    	return true;
222         }
223 	   // LeaveSysAdmin
224 	    if(HrServiceLocator.getKPMERoleService().principalHasRole(principalId, KPMENamespace.KPME_LM.getNamespaceCode(), KPMERole.LEAVE_SYSTEM_ADMINISTRATOR.getRoleName(), LocalDate.now().toDateTimeAtStartOfDay())) {
225 	    	return true;
226         }
227 	    
228 	    // use job to find the department, then use the location from Department to get the location roles 
229 	    Job aJob = HrServiceLocator.getJobService().getJob(aLeaveBlock.getPrincipalId(), aLeaveBlock.getJobNumber(), aLeaveBlock.getLeaveLocalDate());
230 	    if(aJob != null) {
231 	    	Department aDept = HrServiceLocator.getDepartmentService().getDepartmentWithoutRoles(aJob.getDept(), aJob.getEffectiveLocalDate());
232 	    	if(aDept != null) {
233 	    		// LeaveLocationAdmin
234 			    if(HrServiceLocator.getKPMERoleService().principalHasRoleInLocation(principalId, KPMENamespace.KPME_LM.getNamespaceCode(), KPMERole.LEAVE_LOCATION_ADMINISTRATOR.getRoleName(), aDept.getLocation(), LocalDate.now().toDateTimeAtStartOfDay()))
235 			    	return true;
236 			    // Payroll Processor
237 			    if(HrServiceLocator.getKPMERoleService().principalHasRoleInDepartment(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR.getRoleName(), aDept.getDept(), LocalDate.now().toDateTimeAtStartOfDay())) {
238 			    	return true;
239 		        }
240 			    // Payroll Processor Delegate
241 			    if(HrServiceLocator.getKPMERoleService().principalHasRoleInDepartment(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR_DELEGATE.getRoleName(), aDept.getDept(), LocalDate.now().toDateTimeAtStartOfDay())) {
242 			    	return true;
243 		        }
244 	    	}
245 	    }	    
246     	Long aWorkArea = aLeaveBlock.getWorkArea();
247 	    // Reviewer
248 	    if(HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.REVIEWER.getRoleName(), aWorkArea, LocalDate.now().toDateTimeAtStartOfDay())) {
249 	    	return true;
250         }
251 	    // Approver
252 	    if(HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER.getRoleName(), aWorkArea, LocalDate.now().toDateTimeAtStartOfDay())) {
253 	    	return true;
254         }
255 	    // Approver Delegate
256 	    if(HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(principalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER_DELEGATE.getRoleName(), aWorkArea, LocalDate.now().toDateTimeAtStartOfDay())) {
257 	    	return true;
258         }
259 	    
260 	  
261 	    
262 	    
263 	    // no eligible roles found
264 	    return false;
265 	 
266     }
267 
268     private boolean updateCanDeleteLeaveblockPerm(String principalId, CalendarBlockPermissions perms, boolean canDelete) {
269         perms.putCanDelete(principalId, canDelete);
270         HrServiceLocator.getHRPermissionService().updateLeaveBlockPermissions(perms);
271         return canDelete;
272     }
273 
274     @Override
275     public boolean canDeleteLeaveBlock(String principalId, LeaveBlock leaveBlock) {
276         if (principalId != null) {
277             CalendarBlockPermissions perms = HrServiceLocator.getHRPermissionService().getLeaveBlockPermissions(leaveBlock.getLmLeaveBlockId());
278             Boolean canDelete = perms.isPrincipalCanDelete(principalId);
279 
280             if (canDelete != null) {
281                 return canDelete;
282             }
283         	String documentId = leaveBlock.getDocumentId();
284         	if (StringUtils.isBlank(documentId)) {
285                     String targetPrincipalId = HrContext.isTargetInUse() ? HrContext.getTargetPrincipalId() : principalId;
286                     TimesheetDocumentHeader timesheetDocumentHeader = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeaderForDate(targetPrincipalId, leaveBlock.getLeaveLocalDate().toDateTimeAtStartOfDay());
287 
288                     if (timesheetDocumentHeader != null) {
289                         documentId = timesheetDocumentHeader.getDocumentId();
290                     }
291         	}
292         	if (StringUtils.isNotBlank(documentId)) {
293         		DocumentStatus documentStatus = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(documentId);
294         		if (DocumentStatus.CANCELED.equals(documentStatus) || DocumentStatus.DISAPPROVED.equals(documentStatus) || DocumentStatus.FINAL.equals(documentStatus)) {
295                     return updateCanDeleteLeaveblockPerm(principalId, perms, false);
296         		}
297         	}
298         }
299     	
300     	if(StringUtils.equals(HrConstants.REQUEST_STATUS.DISAPPROVED, leaveBlock.getRequestStatus()))  {
301             return false;
302         }
303     	if(canBankOrTransferSSTOUsage(leaveBlock)) {
304             return true;
305     	}
306         if (StringUtils.equals(HrConstants.REQUEST_STATUS.APPROVED, leaveBlock.getRequestStatus())) {
307         	List<LeaveRequestDocument> docList= LmServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocumentsByLeaveBlockId(leaveBlock.getLmLeaveBlockId());
308         	if(CollectionUtils.isEmpty(docList)) {
309         		return false;	// not a leave request
310         	}
311         }
312        
313         return canEditLeaveBlock(principalId, leaveBlock);
314     }
315     
316     @Override
317 	public boolean canBankOrTransferSSTOUsage(LeaveBlock lb) {
318 		// if it's an accrual generated ssto usage leave block which can be banked or transferred, and on a current leave calendar,
319 	    // it can be deleted so the accrualed amount can be banked
320 	    return canBankSSTOUsage(lb) || canTransferSSTOUsage(lb);
321 	}
322     
323     @Override
324 	public boolean canBankSSTOUsage(LeaveBlock lb) {
325  	   if(lb.getAccrualGenerated() 
326 			   && StringUtils.isNotEmpty(lb.getScheduleTimeOffId()) 
327 			   && lb.getLeaveAmount().compareTo(BigDecimal.ZERO) < 0) {
328 		   SystemScheduledTimeOff ssto = LmServiceLocator.getSysSchTimeOffService().getSystemScheduledTimeOff(lb.getScheduleTimeOffId());
329 		   if(ssto != null && StringUtils.equals(ssto.getUnusedTime(), LMConstants.UNUSED_TIME.BANK)) {
330 			   String viewPrincipal = HrContext.getTargetPrincipalId();
331 			   CalendarEntry ce = HrServiceLocator.getCalendarEntryService()
332 						.getCurrentCalendarDatesForLeaveCalendar(viewPrincipal, new LocalDate().toDateTimeAtStartOfDay());
333 			   if(ce != null) {
334 				   if(!lb.getLeaveDate().before(ce.getBeginPeriodDate()) && !lb.getLeaveDate().after(ce.getEndPeriodDate())) {
335 					   return true;
336 				   }
337 			   }
338 			  
339 		   }
340 	   }
341 	   return false;
342 	}
343     
344     @Override
345 	public boolean canTransferSSTOUsage(LeaveBlock lb) {
346 	   if(lb.getAccrualGenerated() 
347 			   && StringUtils.isNotEmpty(lb.getScheduleTimeOffId()) 
348 			   && lb.getLeaveAmount().compareTo(BigDecimal.ZERO) < 0) {
349 		   SystemScheduledTimeOff ssto = LmServiceLocator.getSysSchTimeOffService().getSystemScheduledTimeOff(lb.getScheduleTimeOffId());
350 		   if(ssto != null && LMConstants.UNUSED_TIME.TRANSFER.equals(ssto.getUnusedTime())) {
351 			   String viewPrincipal = HrContext.getTargetPrincipalId();
352 			   CalendarEntry ce = HrServiceLocator.getCalendarEntryService()
353 						.getCurrentCalendarDatesForLeaveCalendar(viewPrincipal, new LocalDate().toDateTimeAtStartOfDay());
354 			   if(ce != null) {
355 				   if(!lb.getLeaveDate().before(ce.getBeginPeriodDate()) && !lb.getLeaveDate().after(ce.getEndPeriodDate())) {
356 					   return true;
357 				   }
358 			   }
359 			  
360 		   }
361 	   }
362 	   return false;
363 	}
364 	
365 	
366 
367 	public LeaveCalendarService getLeaveCalendarService() {
368 		return leaveCalendarService;
369 	}
370 
371 	public void setLeaveCalendarService(LeaveCalendarService leaveCalendarService) {
372 		this.leaveCalendarService = leaveCalendarService;
373 	}
374 	
375 	public LeaveRequestDocumentService getLeaveRequestDocumentService() {
376 		return leaveRequestDocumentService;
377 	}
378 
379 	public void setLeaveRequestDocumentService(LeaveRequestDocumentService leaveRequestDocumentService) {
380 		this.leaveRequestDocumentService = leaveRequestDocumentService;
381 	}
382 	
383 }