View Javadoc
1   /**
2    * Copyright 2004-2014 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.payout.validation;
17  
18  import java.math.BigDecimal;
19  import java.util.Date;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
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.accrualcategory.AccrualCategory;
29  import org.kuali.kpme.core.accrualcategory.rule.AccrualCategoryRule;
30  import org.kuali.kpme.core.assignment.Assignment;
31  import org.kuali.kpme.core.department.Department;
32  import org.kuali.kpme.core.earncode.EarnCode;
33  import org.kuali.kpme.core.job.Job;
34  import org.kuali.kpme.core.leaveplan.LeavePlan;
35  import org.kuali.kpme.core.permission.KPMEPermissionTemplate;
36  import org.kuali.kpme.core.principal.PrincipalHRAttributes;
37  import org.kuali.kpme.core.role.KPMERole;
38  import org.kuali.kpme.core.role.KPMERoleMemberAttribute;
39  import org.kuali.kpme.core.service.HrServiceLocator;
40  import org.kuali.kpme.core.util.HrContext;
41  import org.kuali.kpme.core.util.ValidationUtils;
42  import org.kuali.kpme.tklm.common.TkConstants;
43  import org.kuali.kpme.tklm.leave.override.EmployeeOverride;
44  import org.kuali.kpme.tklm.leave.payout.LeavePayout;
45  import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
46  import org.kuali.kpme.tklm.leave.summary.LeaveSummary;
47  import org.kuali.kpme.tklm.leave.summary.LeaveSummaryRow;
48  import org.kuali.kpme.tklm.time.util.TkContext;
49  import org.kuali.rice.kew.api.WorkflowDocument;
50  import org.kuali.rice.kew.api.action.RequestedActions;
51  import org.kuali.rice.kew.api.document.DocumentContent;
52  import org.kuali.rice.kew.api.document.node.RouteNodeInstance;
53  import org.kuali.rice.kim.api.KimConstants;
54  import org.kuali.rice.kim.api.identity.Person;
55  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
56  import org.kuali.rice.kns.document.MaintenanceDocument;
57  import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
58  import org.kuali.rice.krad.bo.PersistableBusinessObject;
59  import org.kuali.rice.krad.util.GlobalVariables;
60  import org.kuali.rice.krad.util.ObjectUtils;
61  
62  public class LeavePayoutValidation extends MaintenanceDocumentRuleBase {
63  
64  /*	private boolean validateAgainstLeavePlan(PrincipalHRAttributes pha, AccrualCategory fromAccrualCategory, LocalDate effectiveDate) {
65  		boolean isValid = true;
66  		if(pha==null) {
67  			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "leavePayout.principal.noLeavePlan");
68  			isValid &= false;
69  		}
70  		else {
71  			List<AccrualCategory> accrualCategories = HrServiceLocator.getAccrualCategoryService().getActiveAccrualCategoriesForLeavePlan(pha.getLeavePlan(), effectiveDate);
72  			if(accrualCategories.size() > 0) {
73  				if(fromAccrualCategory != null) {
74  					boolean isFromInLeavePlan = false;
75  					for(AccrualCategory activeAccrualCategory : accrualCategories) {
76  						if(StringUtils.equals(activeAccrualCategory.getLmAccrualCategoryId(),fromAccrualCategory.getLmAccrualCategoryId())) {
77  							isFromInLeavePlan = true;
78  						}
79  					}
80  					if(!isFromInLeavePlan) {
81  						GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "leavePayout.accrualCategory.notInLeavePlan", fromAccrualCategory.getAccrualCategory());
82  						isValid &= false;
83  					}
84  				}
85  			}
86  			else {
87  				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "leavePayout.principal.noACinLeavePlan");
88  				isValid &=false;
89  			}
90  		}
91  		return isValid;
92  	}
93  	
94  	//Employee Overrides???
95  	*//**
96  	 * Transfer amount could be validated against several variables, including max transfer amount,
97  	 * max carry over.
98  	 * ( if transfers count as usage ).
99  	 * @param transferAmount
100 	 * @param debitedAccrualCategory
101 	 * @param creditedAccrualCategory
102 	 * @param principalId TODO
103 	 * @param effectiveDate TODO
104 	 * @param isSomeAdmin 
105 	 * @return true if transfer amount is valid
106 	 *//*
107 	private boolean validatePayoutAmount(BigDecimal transferAmount,
108 			AccrualCategory debitedAccrualCategory,
109 			EarnCode payoutEarnCode, String principalId, LocalDate effectiveDate, boolean isSomeAdmin) {
110 		if(transferAmount != null) {
111 			if(transferAmount.compareTo(BigDecimal.ZERO) <= 0 ) {
112 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.payoutAmount", "leavePayout.payoutAmount.negative");
113 				return false;
114 			}
115 			if(debitedAccrualCategory != null) {
116 				BigDecimal balance = LmServiceLocator.getLeaveSummaryService().getLeaveBalanceForAccrCatUpToDate(principalId, effectiveDate, effectiveDate, debitedAccrualCategory.getAccrualCategory(), effectiveDate);
117 				if(balance != null) {
118 					if(transferAmount.compareTo(balance) > 0 && !isSomeAdmin) {
119 						GlobalVariables.getMessageMap().putError("document.newMaintainableObject.payoutAmount", "leavePayout.payoutAmount.exceeds.balance");
120 						return false;
121 					}
122 				}
123 			}
124 		}
125 		else {
126 			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.payoutAmount", "leavePayout.payoutAmount.required");
127 		}
128 
129 		return true;
130 	}
131 	
132 	*//**
133 	 * Is the "From" accrual category required to be over its maximum balance before a transfer can take place?
134 	 * The "From" accrual category must be defined in an accrual category rule as having a max bal rule.
135 	 * @param accrualCategory
136 	 * @param effectiveDate 
137 	 * @param principalId 
138 	 * @param fromAccrualCategory 
139 	 * @return
140 	 *//*
141 	private boolean validateTransferFromAccrualCategory(AccrualCategory accrualCategory, String principalId,
142 			LocalDate effectiveDate, String fromAccrualCategory) {
143 		boolean isValid = ValidationUtils.validateAccCategory(fromAccrualCategory, principalId, effectiveDate);
144 		if(!isValid) {
145 			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory","balanceTransfer.accrualcategory.exists",fromAccrualCategory);
146 		}
147 		return isValid;
148 	}
149 	
150 	private boolean validateTransferToEarnCode(EarnCode transferToEarnCode, AccrualCategoryRule acr, String principalId, PrincipalHRAttributes pha, LocalDate effectiveDate, boolean isSomeAdmin) {
151 		boolean isValid = true;
152         //commenting out for KPME-2847
153 		if(transferToEarnCode != null && !isSomeAdmin) {
154 			LeavePlan earnCodeLeavePlan = HrServiceLocator.getLeavePlanService().getLeavePlan(transferToEarnCode.getLeavePlan(),effectiveDate);
155 			if(earnCodeLeavePlan != null) {
156 				LeavePlan phaLeavePlan = HrServiceLocator.getLeavePlanService().getLeavePlan(pha.getLeavePlan(), effectiveDate);
157 				if(phaLeavePlan != null) {
158 					//transfer to earn code should be in the employee's leave plan.
159 					if(!StringUtils.equals(earnCodeLeavePlan.getLmLeavePlanId(),phaLeavePlan.getLmLeavePlanId()) && !isSomeAdmin) {
160 						GlobalVariables.getMessageMap().putError("document.newMaintainableObject.earnCode", "leavePayout.earncode.leaveplan.inconsistent");
161 						isValid &= false;
162 					}
163 				}
164 			}
165 			else {
166 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.earnCode", "leavePayout.earncode.leaveplan.exists");
167 				isValid &= false;
168 			}
169 		}
170 		if (transferToEarnCode == null) {
171 			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.earnCode", "leavePayout.earncode.exists");
172 			isValid &= false;
173 		}
174 		return isValid;
175 	}
176 	
177 	//transfer amount must be under max limit when submitted via max balance triggered action or by a work area approver.
178 	private boolean isPayoutAmountUnderMaxLimit(String principalId, LocalDate effectiveDate, String accrualCategory,
179 				BigDecimal payoutAmount, AccrualCategoryRule accrualRule, String leavePlan) {
180 	
181 		if(ObjectUtils.isNotNull(accrualRule)) {
182 
183 			BigDecimal maxPayoutAmount = null;
184 			if(ObjectUtils.isNotNull(accrualRule.getMaxTransferAmount())) {
185 				maxPayoutAmount = new BigDecimal(accrualRule.getMaxTransferAmount());
186 			}
187 			if(ObjectUtils.isNotNull(maxPayoutAmount)) {
188 				EmployeeOverride eo = LmServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, leavePlan, accrualCategory, TkConstants.EMPLOYEE_OVERRIDE_TYPE.get("MPA"), effectiveDate);
189 				if(ObjectUtils.isNotNull(eo))
190 					if(ObjectUtils.isNull(eo.getOverrideValue()))
191 						maxPayoutAmount = new BigDecimal(Long.MAX_VALUE);
192 					else
193 						maxPayoutAmount = new BigDecimal(eo.getOverrideValue());
194 				else {
195 					BigDecimal fteSum = HrServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate);
196 					maxPayoutAmount = maxPayoutAmount.multiply(fteSum);
197 				}
198 				if(payoutAmount.compareTo(maxPayoutAmount) > 0) {
199 					GlobalVariables.getMessageMap().putError("document.newMaintainableObject.payoutAmount","leavePayout.exceeds.payoutLimit");
200 					return false;
201 				}
202 			}
203 		}
204 		return true;
205 	}
206 	
207 	private boolean validateAccrualCategoryRule(AccrualCategoryRule acr,
208 			EarnCode payoutEarnCode, AccrualCategory fromCat, LocalDate effectiveDate) {
209 		if(acr != null) {
210 			EarnCode earnCode = HrServiceLocator.getEarnCodeService().getEarnCode(acr.getMaxPayoutEarnCode(),effectiveDate);
211 			if(earnCode == null) {
212 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "leavePayout.earncode.exists");
213 				return false;
214 			}
215 			else {
216 				if(!StringUtils.equals(earnCode.getHrEarnCodeId(), payoutEarnCode.getHrEarnCodeId())) {
217 					GlobalVariables.getMessageMap().putError("document.newMaintainableObject.earnCode", "leavePayout.payoutEarnCode.noMatch",payoutEarnCode.getEarnCode());
218 					return false;
219 				}
220 			}
221 		}
222 		else {
223 			if(!(TkContext.isDepartmentAdmin() || HrContext.isSystemAdmin() || TkContext.isLocationAdmin())) {
224 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "leavePayout.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory());
225 				return false;
226 			}
227 		}
228 		return true;
229 	}
230 	
231 	@Override
232 	public boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
233 		boolean isValid = true;
234 		LOG.debug("entering custom validation for Balance Transfer");
235 
236 		PersistableBusinessObject pbo = (PersistableBusinessObject) this.getNewBo();
237 
238 		if(pbo instanceof LeavePayout) {
239 
240 			LeavePayout leavePayout = (LeavePayout) pbo;
241 
242 			*//**
243 			 * Validation is basically governed by accrual category rules. Get accrual category
244 			 * rules for both the "To" and "From" accrual categories, pass to validators along with the
245 			 * values needing to be validated.
246 			 * 
247 			 * Balance transfers initiated from the leave calendar display should already have all values
248 			 * populated, thus validated, including the accrual category rule for the "From" accrual category.
249 			 * 
250 			 * Balance transfers initiated via the Maintenance tab will have no values populated.
251 			 *//*
252 			String principalId = leavePayout.getPrincipalId();
253 			LocalDate effectiveDate = leavePayout.getEffectiveLocalDate();
254 			String fromAccrualCategory = leavePayout.getFromAccrualCategory();
255 			EarnCode payoutEarnCode = leavePayout.getEarnCodeObj();
256 			AccrualCategory fromCat = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate);
257 			PrincipalHRAttributes pha = HrServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate);
258 			
259 			boolean isDeptAdmin = TkContext.isDepartmentAdmin();
260 			boolean isSysAdmin = HrContext.isSystemAdmin();
261 			boolean isLocAdmin = TkContext.isLocationAdmin();
262 			
263 			if(ObjectUtils.isNotNull(pha)) {
264 				if(ObjectUtils.isNotNull(pha.getLeavePlan())) {
265 					if(isDeptAdmin || isSysAdmin || isLocAdmin) {
266 						isValid &= validatePayoutAmount(leavePayout.getPayoutAmount(),fromCat,payoutEarnCode, principalId, effectiveDate,true);
267 						isValid &= validateAgainstLeavePlan(pha,fromCat,effectiveDate);
268 						isValid &= validatePrincipal(pha,principalId,true);
269 						isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,fromAccrualCategory);
270 						isValid &= validateTransferToEarnCode(payoutEarnCode,null,principalId,pha,effectiveDate,true);
271 					} else {
272 						AccrualCategoryRule acr = HrServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat, effectiveDate, pha.getServiceLocalDate());
273 						if(ObjectUtils.isNotNull(acr)) {
274 							if(ObjectUtils.isNotNull(acr.getMaxBalFlag())
275 									&& StringUtils.isNotBlank(acr.getMaxBalFlag())
276 									&& StringUtils.isNotEmpty(acr.getMaxBalFlag())
277 									&& StringUtils.equals(acr.getMaxBalFlag(), "Y")) {
278 								if(ObjectUtils.isNotNull(payoutEarnCode)) {
279 									isValid &= validatePrincipal(pha,principalId,false);
280 									isValid &= validateEffectiveDate(effectiveDate);
281 									isValid &= validateAccrualCategoryRule(acr,payoutEarnCode,fromCat,effectiveDate);
282 									isValid &= validateTransferToEarnCode(payoutEarnCode,acr,principalId,pha,effectiveDate,false);
283 									isValid &= validateAgainstLeavePlan(pha,fromCat,effectiveDate);
284 									isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,fromAccrualCategory);
285 									isValid &= validatePayoutAmount(leavePayout.getPayoutAmount(),fromCat,payoutEarnCode, null, null,false);
286 									isValid &= isPayoutAmountUnderMaxLimit(principalId, effectiveDate, fromAccrualCategory, leavePayout.getPayoutAmount(), acr, pha.getLeavePlan());
287 								}
288 								else {
289 									//should never be the case if accrual category rules are validated correctly.
290 									GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
291 											"leavePayout.fromAccrualCategory.rules.payoutToEarnCode",
292 											fromAccrualCategory);
293 									isValid &= false;
294 								}
295 							}
296 							else {
297 								//max bal flag null, blank, empty, or "N"
298 								GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
299 										"leavePayout.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory);
300 								isValid &= false;
301 							}
302 						}
303 						else {
304 							//department admins must validate amount to transfer does not exceed current balance.
305 							GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
306 									"leavePayout.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory());
307 							isValid &= false;
308 						}
309 					}
310 				}
311 				else {
312 					//if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited.
313 					GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","leavePayout.principal.noLeavePlan");
314 					isValid &=false;
315 				}
316 			}
317 			else  {
318 				//if the principal has no principal hr attributes, they're not a principal.
319 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","leavePayout.principal.noAttributes");
320 				isValid &= false;
321 			}
322 		}
323 		return isValid;
324 	}*/
325 	
326 	@Override
327 	protected boolean processCustomRouteDocumentBusinessRules(
328 			MaintenanceDocument document) {
329 		boolean isValid = true;
330 
331 		LOG.debug("entering custom validation for Balance Transfer");
332 
333 		PersistableBusinessObject pbo = (PersistableBusinessObject) this.getNewBo();
334 
335 		if(pbo instanceof LeavePayout) {
336 
337 			LeavePayout leavePayout = (LeavePayout) pbo;
338 			String fromAccrualCat = leavePayout.getFromAccrualCategory();
339 			String toEarnCode = leavePayout.getEarnCode();
340 			String principalId = leavePayout.getPrincipalId();
341 			BigDecimal payoutAmount = leavePayout.getPayoutAmount();
342 			
343 			isValid &= validateEffectiveDate(leavePayout.getEffectiveLocalDate());
344 			isValid &= validateAccrualCateogry(fromAccrualCat,leavePayout.getEffectiveLocalDate());
345 			isValid &= validateEarnCode(toEarnCode,leavePayout.getEffectiveLocalDate());
346 			isValid &= validatePayoutAmount(principalId,payoutAmount,fromAccrualCat,leavePayout.getEffectiveLocalDate());
347 			if(validatePrincipalId(principalId,leavePayout.getEffectiveLocalDate())) {
348 				isValid &= validatePrincipal(principalId,leavePayout.getEffectiveDate(),GlobalVariables.getUserSession().getPrincipalId(),document.getDocumentHeader().getWorkflowDocument());
349 			}
350 			else {
351 				isValid &= false;
352 			}
353 
354 		}
355 		return isValid;
356 	}
357 
358 	private boolean validateEffectiveDate(LocalDate date) {
359 		//Limit on future dates?
360 		if(date.isAfter(LocalDate.now().plusYears(1))) {
361 			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.effectiveDate", "leavePayout.effectiveDate.overOneYear");
362 			return false;
363 		}
364 		return true;
365 	}
366 
367 	private boolean validateAccrualCateogry(String fromAccrualCat,
368 			LocalDate effectiveLocalDate) {
369 		boolean valid = true;
370 		if(StringUtils.isNotEmpty(fromAccrualCat)) {
371 			valid &= ValidationUtils.validateAccCategory(fromAccrualCat, effectiveLocalDate);
372 			if(!valid) {
373 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "leavePayout.fromAccrualCategory.exists");
374 			}
375 		}
376 		return valid;
377 	}
378 	
379 	private boolean validatePayoutAmount(String principalId, BigDecimal payoutAmount,
380 			String fromAccrualCat, LocalDate effectiveLocalDate) {
381 		boolean isValid = true;
382 		if(payoutAmount != null) {
383 			LeaveSummary leaveSummary = LmServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDateForAccrualCategory(principalId, effectiveLocalDate, fromAccrualCat);
384 			if(leaveSummary != null) {
385 				LeaveSummaryRow leaveSummaryRow = leaveSummary.getLeaveSummaryRowForAccrualCtgy(fromAccrualCat);
386 				if(leaveSummaryRow != null) {
387 					BigDecimal accruedBalance = leaveSummaryRow.getAccruedBalance();
388 					if(payoutAmount.compareTo(accruedBalance) > 0) {
389 						isValid &= false;
390 						GlobalVariables.getMessageMap().putError("document.newMaintainableObject.payoutAmount", "leavePayout.payoutAmount.exceeds.balance");
391 					}
392 				}
393 			}
394 			if(payoutAmount.compareTo(BigDecimal.ZERO) < 0 ) {
395 				isValid  &= false;
396 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.payoutAmount", "leavePayout.payoutAmount.negative");
397 			}
398 		}
399 		return isValid;
400 	}
401 
402 	private boolean validatePrincipalId(String principalId,
403 			LocalDate effectiveLocalDate) {
404 		boolean isValid = true;
405 		if(StringUtils.isNotEmpty(principalId)) {
406 			isValid &= ValidationUtils.validatePrincipalId(principalId);
407 			if(!isValid) {
408 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "leavePayout.principal.exists");
409 			}
410 		}
411 		return isValid;
412 	}
413 
414 	private boolean validateEarnCode(String toEarnCode,
415 			LocalDate effectiveLocalDate) {
416 		boolean isValid = true;
417 		if(StringUtils.isNotEmpty(toEarnCode)) {
418 			isValid &= ValidationUtils.validateEarnCode(toEarnCode, effectiveLocalDate);
419 			if(!isValid) {
420 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.earnCode", "leavePayout.earncode.exists");	
421 			}
422 		}
423 		return isValid;
424 	}
425 	
426 	private boolean validatePrincipal(String principalId, Date effectiveDate, String userPrincipalId, WorkflowDocument workflowDocument) {
427 		boolean isValid = true;
428 		PrincipalHRAttributes pha = HrServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, LocalDate.fromDateFields(effectiveDate));
429 
430 		if(pha == null) {
431 			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "balanceTransfer.principal.noAttributes");
432 			isValid &= false;
433 		}
434 		else {
435 			boolean canCreate = false;
436 			if(!StringUtils.equals(principalId,userPrincipalId)) {
437 				List<Job> principalsJobs = HrServiceLocator.getJobService().getActiveLeaveJobs(principalId, LocalDate.fromDateFields(effectiveDate));
438 				//TODO - performance get job/dept map in 1 query?
439                 for(Job job : principalsJobs) {
440 					
441 					
442 					if(job.isEligibleForLeave()) {
443 						
444 						String department = job != null ? job.getDept() : null;
445 						Department departmentObj = job != null ? HrServiceLocator.getDepartmentService().getDepartmentWithoutRoles(department, LocalDate.fromDateFields(effectiveDate)) : null;
446 						String location = departmentObj != null ? departmentObj.getLocation() : null;
447 
448 						//logged in user may ONLY submit documents for principals in authorized departments / location.
449 			        	if (LmServiceLocator.getLMPermissionService().isAuthorizedInDepartment(userPrincipalId, "Create Leave Payout", department, new DateTime(effectiveDate.getTime()))
450 							|| LmServiceLocator.getLMPermissionService().isAuthorizedInLocation(userPrincipalId, "Create Leave Payout", location, new DateTime(effectiveDate.getTime()))) {
451 								canCreate = true;
452 								break;
453 						}
454 			        	else {
455 			        		//do NOT block approvers, processors, delegates from approving the document.
456 							List<Assignment> assignments = HrServiceLocator.getAssignmentService().getActiveAssignmentsForJob(principalId, job.getJobNumber(), LocalDate.fromDateFields(effectiveDate));
457 							for(Assignment assignment : assignments) {
458 								if(HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(userPrincipalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER.getRoleName(), assignment.getWorkArea(), new DateTime(effectiveDate))
459 										|| HrServiceLocator.getKPMERoleService().principalHasRoleInWorkArea(userPrincipalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.APPROVER_DELEGATE.getRoleName(), assignment.getWorkArea(), new DateTime(effectiveDate))
460 										|| HrServiceLocator.getKPMERoleService().principalHasRoleInDepartment(userPrincipalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR.getRoleName(), assignment.getDept(), new DateTime(effectiveDate))
461 										|| HrServiceLocator.getKPMERoleService().principalHasRoleInDepartment(userPrincipalId, KPMENamespace.KPME_HR.getNamespaceCode(), KPMERole.PAYROLL_PROCESSOR_DELEGATE.getRoleName(), assignment.getDept(), new DateTime(effectiveDate))) {
462 									canCreate = true;
463 									break;
464 								}
465 							}
466 			        	}
467 					}
468 				}
469 			}
470 			else {
471 				//should be able to submit their own transaction documents...
472 				//max balance triggered transactions go through this validation. Set a userPrincipal to system and deny LEAVE DEPT/LOC Admins ability to submit their own
473 				//transactions these simplified rules??
474 				canCreate = false;
475 			}
476 			
477 			if(!canCreate) {
478 				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "balanceTransfer.userNotAuthorized");
479 				isValid &= false;
480 			}
481 		}
482 		return isValid;
483 	}
484 }