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.leavepayout.validation;
17  
18  import java.math.BigDecimal;
19  import java.sql.Date;
20  import java.util.List;
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.commons.lang.time.DateUtils;
24  import org.kuali.hr.lm.accrual.AccrualCategory;
25  import org.kuali.hr.lm.accrual.AccrualCategoryRule;
26  import org.kuali.hr.lm.leavepayout.LeavePayout;
27  import org.kuali.hr.time.earncode.EarnCode;
28  import org.kuali.hr.time.principal.PrincipalHRAttributes;
29  import org.kuali.hr.time.service.base.TkServiceLocator;
30  import org.kuali.hr.time.util.TKContext;
31  import org.kuali.hr.time.util.TKUtils;
32  import org.kuali.rice.kns.document.MaintenanceDocument;
33  import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
34  import org.kuali.rice.krad.bo.PersistableBusinessObject;
35  import org.kuali.rice.krad.util.GlobalVariables;
36  import org.kuali.rice.krad.util.ObjectUtils;
37  
38  public class LeavePayoutValidation extends MaintenanceDocumentRuleBase {
39  
40  	private boolean validateAgainstLeavePlan(PrincipalHRAttributes pha, AccrualCategory fromAccrualCategory, Date effectiveDate) {
41  		boolean isValid = true;
42  
43  		List<AccrualCategory> accrualCategories = TkServiceLocator.getAccrualCategoryService().getActiveAccrualCategoriesForLeavePlan(pha.getLeavePlan(), effectiveDate);
44  		if(accrualCategories.size() > 0) {
45  			boolean isFromInLeavePlan = false;
46  			for(AccrualCategory activeAccrualCategory : accrualCategories) {
47  				if(StringUtils.equals(activeAccrualCategory.getLmAccrualCategoryId(),fromAccrualCategory.getLmAccrualCategoryId())) {
48  					isFromInLeavePlan = true;
49  				}
50  			}
51  			if(!isFromInLeavePlan) {
52  				GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "leavePayout.accrualCategory.notInLeavePlan", fromAccrualCategory.getAccrualCategory());
53  				isValid &= false;
54  			}
55  		}
56  		else {
57  			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "leavePayout.principal.noACinLeavePlan");
58  			isValid &=false;
59  		}
60  		
61  		return isValid;
62  	}
63  	
64  	//Employee Overrides???
65  	/**
66  	 * Transfer amount must be validated against several variables, including max transfer amount,
67  	 * max carry over ( for the converted amount deposited into the "to" accrual category, max usage
68  	 * ( if transfers count as usage ).
69  	 * @param transferAmount
70  	 * @param debitedAccrualCategory
71  	 * @param creditedAccrualCategory
72  	 * @param principalId TODO
73  	 * @param effectiveDate TODO
74  	 * @return true if transfer amount is valid
75  	 */
76  	private boolean validatePayoutAmount(BigDecimal transferAmount,
77  			AccrualCategory debitedAccrualCategory,
78  			EarnCode payoutEarnCode, String principalId, Date effectiveDate) {
79  		
80  		if(transferAmount.compareTo(BigDecimal.ZERO) < 0 ) {
81  			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.transferAmount", "leavePayout.amount.negative");
82  			return false;
83  		}
84  		//TkServiceLocator.getAccrualCategoryService().getCurrentBalanceForPrincipal(principalId, debitedAccrualCategory, effectiveDate);
85  
86  		return true;
87  	}
88  
89  	/**
90  	 * Are there any rules in place for effective date? i.e. not more than one year in advance...
91  	 * @param date
92  	 * @return
93  	 */
94  	private boolean validateEffectiveDate(Date date) {
95  		//Limit on future dates?
96  		if(date.getTime() > DateUtils.addYears(TKUtils.getCurrentDate(), 1).getTime()) {
97  			GlobalVariables.getMessageMap().putError("document.newMaintainableObject.effectiveDate", "leavePayout.effectiveDate.overOneYear");
98  			return false;
99  		}
100 		return true;
101 	}
102 	
103 	/**
104 	 * Is the "From" accrual category required to be over its maximum balance before a transfer can take place?
105 	 * The "From" accrual category must be defined in an accrual category rule as having a max bal rule.
106 	 * @param accrualCategory
107 	 * @param effectiveDate 
108 	 * @param principalId 
109 	 * @param acr 
110 	 * @return
111 	 */
112 	private boolean validateTransferFromAccrualCategory(AccrualCategory accrualCategory, String principalId,
113 			Date effectiveDate, AccrualCategoryRule acr) {
114 		//accrualCategory has rules
115 		PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, effectiveDate);
116 		
117 		return true;
118 	}
119 	
120 	private boolean validatePrincipal(PrincipalHRAttributes pha, String principalId) {
121 		// TODO Auto-generated method stub
122 		// Principal has to have an associated leave plan.
123 		// leave plan should contain the transfer "from" accrual category.
124 		
125 		return true;
126 	}
127 	
128 	/**
129 	 * Is not called when saving a document, but is called on submit.
130 	 * 
131 	 * The branched logic in this method contains references to accrual category rule properties
132 	 * that, when balance transfer is triggered through system interaction, would naturally have
133 	 * been checked in the process of triggering the balance transfer. i.e. existence of accrual
134 	 * category rule, maxBalFlag = Y, leave plan for principal id existence and accrual category
135 	 * existence under that leave plan. The context in which the balance transfers are triggered
136 	 * would themselves validate these checks.
137 	 * 
138 	 */
139 	@Override
140 	public boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
141 		boolean isValid = true;
142 		LOG.debug("entering custom validation for Balance Transfer");
143 
144 		PersistableBusinessObject pbo = (PersistableBusinessObject) this.getNewBo();
145 
146 		if(pbo instanceof LeavePayout) {
147 
148 			LeavePayout leavePayout = (LeavePayout) pbo;
149 
150 			/**
151 			 * Validation is basically governed by accrual category rules. Get accrual category
152 			 * rules for both the "To" and "From" accrual categories, pass to validators along with the
153 			 * values needing to be validated.
154 			 * 
155 			 * Balance transfers initiated from the leave calendar display should already have all values
156 			 * populated, thus validated, including the accrual category rule for the "From" accrual category.
157 			 * 
158 			 * Balance transfers initiated via the Maintenance tab will have no values populated.
159 			 */
160 			String principalId = leavePayout.getPrincipalId();
161 			Date effectiveDate = leavePayout.getEffectiveDate();
162 			String fromAccrualCategory = leavePayout.getFromAccrualCategory();
163 			EarnCode payoutEarnCode = leavePayout.getEarnCodeObj();
164 			AccrualCategory fromCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate);
165 			PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate);
166 			
167 			boolean isDeptAdmin = TKContext.getUser().isDepartmentAdmin();
168 			boolean isSysAdmin = TKContext.getUser().isSystemAdmin();
169 			if(isDeptAdmin || isSysAdmin) {
170 				isValid &= validatePayoutAmount(leavePayout.getPayoutAmount(),fromCat,payoutEarnCode, principalId, effectiveDate);
171 			}
172 			else {
173 				if(ObjectUtils.isNotNull(pha)) {
174 					if(ObjectUtils.isNotNull(pha.getLeavePlan())) {
175 						AccrualCategoryRule acr = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat, effectiveDate, pha.getServiceDate());
176 						if(ObjectUtils.isNotNull(acr)) {
177 							if(ObjectUtils.isNotNull(acr.getMaxBalFlag())
178 									&& StringUtils.isNotBlank(acr.getMaxBalFlag())
179 									&& StringUtils.isNotEmpty(acr.getMaxBalFlag())
180 									&& StringUtils.equals(acr.getMaxBalFlag(), "Y")) {
181 								if(ObjectUtils.isNotNull(payoutEarnCode)) {
182 									isValid &= validatePrincipal(pha,principalId);
183 									isValid &= validateEffectiveDate(effectiveDate);
184 									isValid &= validateAgainstLeavePlan(pha,fromCat,effectiveDate);
185 									isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr);
186 									isValid &= validatePayoutAmount(leavePayout.getPayoutAmount(),fromCat,payoutEarnCode, null, null);
187 								}
188 								else {
189 									//should never be the case if accrual category rules are validated correctly.
190 									GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
191 											"leavePayout.fromAccrualCategory.rules.payoutToEarnCode",
192 											fromAccrualCategory);
193 									isValid &= false;
194 								}
195 							}
196 							else {
197 								//max bal flag null, blank, empty, or "N"
198 								GlobalVariables.getMessageMap().putError("document.newMaintinableObject.fromAccrualCategory",
199 										"leavePayout.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory);
200 								isValid &= false;
201 							}
202 						}
203 						else {
204 							//department admins must validate amount to transfer does not exceed current balance.
205 							GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
206 									"leavePayout.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory());
207 							isValid &= false;
208 						}
209 					}
210 					else {
211 						//if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited.
212 						GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","leavePayout.principal.noLeavePlan");
213 						isValid &=false;
214 					}
215 				}
216 				else  {
217 					//if the principal has no principal hr attributes, they're not a principal.
218 					GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","leavePayout.principal.noAttributes");
219 					isValid &= false;
220 				}
221 			}
222 		}
223 		return isValid; 
224 	}
225 	
226 	@Override
227 	protected boolean processCustomApproveDocumentBusinessRules(
228 			MaintenanceDocument document) {
229 /*		System.out.println("");*/
230 		return super.processCustomApproveDocumentBusinessRules(document);
231 	}
232 
233 }