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.balancetransfer.validation;
17  
18  import java.math.BigDecimal;
19  import java.sql.Date;
20  import java.util.Calendar;
21  import java.util.List;
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.commons.lang.time.DateUtils;
25  import org.kuali.hr.lm.accrual.AccrualCategory;
26  import org.kuali.hr.lm.accrual.AccrualCategoryRule;
27  import org.kuali.hr.lm.balancetransfer.BalanceTransfer;
28  import org.kuali.hr.lm.employeeoverride.EmployeeOverride;
29  import org.kuali.hr.time.principal.PrincipalHRAttributes;
30  import org.kuali.hr.time.service.base.TkServiceLocator;
31  import org.kuali.hr.time.util.TKContext;
32  import org.kuali.hr.time.util.TKUtils;
33  import org.kuali.hr.time.util.TkConstants;
34  import org.kuali.rice.kns.document.MaintenanceDocument;
35  import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
36  import org.kuali.rice.krad.bo.PersistableBusinessObject;
37  import org.kuali.rice.krad.util.GlobalVariables;
38  import org.kuali.rice.krad.util.ObjectUtils;
39  
40  public class BalanceTransferValidation extends MaintenanceDocumentRuleBase {
41  
42  	//the "to" and "from" accrual categories should be in the supplied principal's leave plan as of the effective date.
43  	private boolean validateLeavePlan(PrincipalHRAttributes pha,
44  			AccrualCategory fromAccrualCategory, AccrualCategory toAccrualCategory, Date effectiveDate) {
45  		boolean isValid = true;
46  		
47  		List<AccrualCategory> accrualCategories = TkServiceLocator.getAccrualCategoryService().getActiveAccrualCategoriesForLeavePlan(pha.getLeavePlan(), effectiveDate);
48  		if(accrualCategories.size() > 0) {
49  			boolean isFromInLeavePlan = false;
50  			boolean isToInLeavePlan = false;
51  			for(AccrualCategory activeAccrualCategory : accrualCategories) {
52  				if(StringUtils.equals(activeAccrualCategory.getLmAccrualCategoryId(),fromAccrualCategory.getLmAccrualCategoryId())) {
53  					isFromInLeavePlan = true;
54  				}
55  				if(StringUtils.equals(activeAccrualCategory.getLmAccrualCategoryId(), toAccrualCategory.getLmAccrualCategoryId())) {
56  					isToInLeavePlan = true;
57  				}
58  			}
59  			if(!isFromInLeavePlan) {
60  				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.accrualCategory.notInLeavePlan", fromAccrualCategory.getAccrualCategory());
61  				isValid &= false;
62  			}
63  			if(!isToInLeavePlan) {
64  				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.toAccrualCategory", "balanceTransfer.accrualCategory.notInLeavePlan", toAccrualCategory.getAccrualCategory());
65  				isValid &= false;			
66  			}
67  		}
68  		else {
69  			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "balanceTransfer.principal.noACinLeavePlan");
70  			isValid &=false;
71  		}
72  		return isValid;
73  	}
74  	
75  	//See isTransferAmountUnderMaxLimit for futher validation
76  	private boolean validateTransferAmount(BigDecimal transferAmount,
77  			AccrualCategory debitedAccrualCategory,
78  			AccrualCategory creditedAccrualCategory, String principalId, Date effectiveDate) {
79  		
80  		if(transferAmount.compareTo(BigDecimal.ZERO) < 0 ) {
81  			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.transferAmount", "balanceTransfer.amount.negative");
82  			return false;
83  		}
84  
85  		return true;
86  	}
87  
88  	//Effective date not more than one year in advance
89  	private boolean validateEffectiveDate(Date date) {
90  		if(DateUtils.addYears(TKUtils.getCurrentDate(), 1).compareTo(date) > 0)
91  			return true;
92  		else
93  			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.effectiveDate", "balanceTransfer.effectiveDate.error");
94  		return false;
95  	}
96  	
97  	private boolean validateTransferFromAccrualCategory(AccrualCategory accrualCategory, String principalId,
98  			Date effectiveDate, AccrualCategoryRule acr) {
99  		//accrualCategory has rules
100 		PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, effectiveDate);
101 		
102 		return true;
103 	}
104 	
105 	//Transfer to accrual category should match the value defined in the accrual category rule
106 	private boolean validateTransferToAccrualCategory(AccrualCategory accrualCategory, String principalId, Date effectiveDate, AccrualCategoryRule acr) {
107 		AccrualCategory maxBalTranToAccCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(acr.getMaxBalanceTransferToAccrualCategory(),effectiveDate);
108 		if(!StringUtils.equals(maxBalTranToAccCat.getLmAccrualCategoryId(),accrualCategory.getLmAccrualCategoryId())) {
109 			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.toAccrualCategory", "balanceTransfer.toAccrualCategory.noMatch",accrualCategory.getAccrualCategory());
110 			return false;
111 		}
112 		return true;
113 	}
114 
115 	//no validation
116 	private boolean validatePrincipal(PrincipalHRAttributes pha, String principalId) {
117 		return true;
118 	}
119 	
120 	//transfer amount must be under max limit when submitted via max balance triggered action or by a work area approver.
121 	private boolean isTransferAmountUnderMaxLimit(String principalId, Date effectiveDate, String accrualCategory,
122 			BigDecimal transferAmount, AccrualCategoryRule accrualRule, String leavePlan) {
123 	
124 		if(ObjectUtils.isNotNull(accrualRule)) {
125 
126 			BigDecimal maxTransferAmount = null;
127 			if(ObjectUtils.isNotNull(accrualRule.getMaxTransferAmount())) {
128 				maxTransferAmount = new BigDecimal(accrualRule.getMaxTransferAmount());
129 			}
130 			if(ObjectUtils.isNotNull(maxTransferAmount)) {
131 				EmployeeOverride eo = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, leavePlan, accrualCategory, TkConstants.EMPLOYEE_OVERRIDE_TYPE.get("MTA"), effectiveDate);
132 				if(ObjectUtils.isNotNull(eo))
133 					maxTransferAmount = new BigDecimal(eo.getOverrideValue());
134 				else {
135 					BigDecimal fteSum = TkServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate);
136 					maxTransferAmount = maxTransferAmount.multiply(fteSum);
137 				}
138 				if(transferAmount.compareTo(maxTransferAmount) > 0) {
139 					GlobalVariables.getMessageMap().putError("document.newMaintainableObject.transferAmount","balanceTransfer.exceeds.transferLimit");
140 					return false;
141 				}
142 			}
143 		}
144 		return true;
145 	}
146 	
147 	@Override
148 	public boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
149 		boolean isValid = super.processCustomRouteDocumentBusinessRules(document);
150 		LOG.debug("entering custom validation for Balance Transfer");
151 
152 		PersistableBusinessObject pbo = (PersistableBusinessObject) this.getNewBo();
153 
154 		if(pbo instanceof BalanceTransfer) {
155 
156 			BalanceTransfer balanceTransfer = (BalanceTransfer) pbo;
157 			
158 			// if this balance transfer is on a system scheduled time off, then don't do further validation
159 			if(StringUtils.isNotEmpty(balanceTransfer.getSstoId())) {
160 				isValid &= BalanceTransferValidationUtils.validateSstoTranser(balanceTransfer);
161 				return isValid;
162 			}
163 			if(isValid) {
164 
165 				/**
166 				 * Validation is basically governed by accrual category rules. Get accrual category
167 				 * rules for both the "To" and "From" accrual categories, pass to validators along with the
168 				 * values needing to be validated.
169 				 * 
170 				 * Balance transfers initiated from the leave calendar display should already have all values
171 				 * populated, thus validated, including the accrual category rule for the "From" accrual category.
172 				 * 
173 				 * Balance transfers initiated via the Maintenance tab will have no values populated.
174 				 */
175 				String principalId = balanceTransfer.getPrincipalId();
176 				Date effectiveDate = balanceTransfer.getEffectiveDate();
177 				String fromAccrualCategory = balanceTransfer.getFromAccrualCategory();
178 				String toAccrualCategory = balanceTransfer.getToAccrualCategory();
179 				AccrualCategory fromCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate);
180 				AccrualCategory toCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(toAccrualCategory, effectiveDate);
181 				PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate);
182 				
183 				boolean isDeptAdmin = TKContext.getUser().isDepartmentAdmin();
184 				boolean isSysAdmin = TKContext.getUser().isSystemAdmin();
185 				if(isDeptAdmin || isSysAdmin) {
186 					isValid &= validateTransferAmount(balanceTransfer.getTransferAmount(),fromCat,toCat, principalId, effectiveDate);
187 				}
188 				else {
189 					if(ObjectUtils.isNotNull(pha)) {
190 						if(ObjectUtils.isNotNull(pha.getLeavePlan())) {
191 							AccrualCategoryRule acr = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat,
192 									effectiveDate, pha.getServiceDate());
193 							if(ObjectUtils.isNotNull(acr)) {
194 								if(StringUtils.isNotBlank(acr.getMaxBalFlag())
195 										&& StringUtils.equals(acr.getMaxBalFlag(), "Y")) {
196 									if(ObjectUtils.isNotNull(toCat)) {
197 										
198 										isValid &= validatePrincipal(pha,principalId);
199 										isValid &= validateEffectiveDate(effectiveDate);
200 										isValid &= validateLeavePlan(pha,fromCat,toCat,effectiveDate);
201 										isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr);
202 										isValid &= validateTransferToAccrualCategory(toCat,principalId,effectiveDate,acr);
203 										isValid &= validateTransferAmount(balanceTransfer.getTransferAmount(),fromCat,toCat, null, null);
204 										isValid &= isTransferAmountUnderMaxLimit(principalId,effectiveDate,fromAccrualCategory,balanceTransfer.getTransferAmount(),acr,pha.getLeavePlan());
205 									}
206 									else {
207 										//should never be the case if accrual category rules are validated correctly.
208 										GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
209 												"balanceTransfer.fromAccrualCategory.rules.transferToAccrualCategory",
210 												fromAccrualCategory);
211 										isValid &= false;
212 									}
213 								}
214 								else {
215 									//max bal flag null, blank, empty, or "N"
216 									GlobalVariables.getMessageMap().putError("document.newMaintinableObject.fromAccrualCategory",
217 											"balanceTransfer.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory);
218 									isValid &= false;
219 								}
220 							}
221 							else {
222 								//department admins must validate amount to transfer does not exceed current balance.
223 								GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
224 										"balanceTransfer.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory());
225 								isValid &= false;
226 							}
227 						}
228 						else {
229 							//if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited.
230 							GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noLeavePlan");
231 							isValid &=false;
232 						}
233 					}
234 					else  {
235 						//if the principal has no principal hr attributes, they're not a principal.
236 						GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noAttributes");
237 						isValid &= false;
238 					}
239 				}
240 			}
241 		}
242 		return isValid; 
243 	}
244 	
245 	@Override
246 	protected boolean processCustomApproveDocumentBusinessRules(
247 			MaintenanceDocument document) {
248 /*		System.out.println("");*/
249 		return super.processCustomApproveDocumentBusinessRules(document);
250 	}
251 
252 }