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.leavepayout.validation;
017
018 import java.math.BigDecimal;
019 import java.sql.Date;
020 import java.util.List;
021
022 import org.apache.commons.lang.StringUtils;
023 import org.apache.commons.lang.time.DateUtils;
024 import org.kuali.hr.lm.accrual.AccrualCategory;
025 import org.kuali.hr.lm.accrual.AccrualCategoryRule;
026 import org.kuali.hr.lm.leavepayout.LeavePayout;
027 import org.kuali.hr.time.earncode.EarnCode;
028 import org.kuali.hr.time.principal.PrincipalHRAttributes;
029 import org.kuali.hr.time.service.base.TkServiceLocator;
030 import org.kuali.hr.time.util.TKContext;
031 import org.kuali.hr.time.util.TKUtils;
032 import org.kuali.rice.kns.document.MaintenanceDocument;
033 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
034 import org.kuali.rice.krad.bo.PersistableBusinessObject;
035 import org.kuali.rice.krad.util.GlobalVariables;
036 import org.kuali.rice.krad.util.ObjectUtils;
037
038 public class LeavePayoutValidation extends MaintenanceDocumentRuleBase {
039
040 private boolean validateAgainstLeavePlan(PrincipalHRAttributes pha, AccrualCategory fromAccrualCategory, Date effectiveDate) {
041 boolean isValid = true;
042
043 List<AccrualCategory> accrualCategories = TkServiceLocator.getAccrualCategoryService().getActiveAccrualCategoriesForLeavePlan(pha.getLeavePlan(), effectiveDate);
044 if(accrualCategories.size() > 0) {
045 boolean isFromInLeavePlan = false;
046 for(AccrualCategory activeAccrualCategory : accrualCategories) {
047 if(StringUtils.equals(activeAccrualCategory.getLmAccrualCategoryId(),fromAccrualCategory.getLmAccrualCategoryId())) {
048 isFromInLeavePlan = true;
049 }
050 }
051 if(!isFromInLeavePlan) {
052 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "leavePayout.accrualCategory.notInLeavePlan", fromAccrualCategory.getAccrualCategory());
053 isValid &= false;
054 }
055 }
056 else {
057 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId", "leavePayout.principal.noACinLeavePlan");
058 isValid &=false;
059 }
060
061 return isValid;
062 }
063
064 //Employee Overrides???
065 /**
066 * Transfer amount must be validated against several variables, including max transfer amount,
067 * max carry over ( for the converted amount deposited into the "to" accrual category, max usage
068 * ( if transfers count as usage ).
069 * @param transferAmount
070 * @param debitedAccrualCategory
071 * @param creditedAccrualCategory
072 * @param principalId TODO
073 * @param effectiveDate TODO
074 * @return true if transfer amount is valid
075 */
076 private boolean validatePayoutAmount(BigDecimal transferAmount,
077 AccrualCategory debitedAccrualCategory,
078 EarnCode payoutEarnCode, String principalId, Date effectiveDate) {
079
080 if(transferAmount.compareTo(BigDecimal.ZERO) < 0 ) {
081 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.transferAmount", "leavePayout.amount.negative");
082 return false;
083 }
084 //TkServiceLocator.getAccrualCategoryService().getCurrentBalanceForPrincipal(principalId, debitedAccrualCategory, effectiveDate);
085
086 return true;
087 }
088
089 /**
090 * Are there any rules in place for effective date? i.e. not more than one year in advance...
091 * @param date
092 * @return
093 */
094 private boolean validateEffectiveDate(Date date) {
095 //Limit on future dates?
096 if(date.getTime() > DateUtils.addYears(TKUtils.getCurrentDate(), 1).getTime()) {
097 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.effectiveDate", "leavePayout.effectiveDate.overOneYear");
098 return false;
099 }
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 }