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.balancetransfer.validation;
017
018 import java.math.BigDecimal;
019 import java.sql.Date;
020 import org.apache.commons.lang.StringUtils;
021 import org.kuali.hr.lm.LMConstants;
022 import org.kuali.hr.lm.accrual.AccrualCategory;
023 import org.kuali.hr.lm.accrual.AccrualCategoryRule;
024 import org.kuali.hr.lm.balancetransfer.BalanceTransfer;
025 import org.kuali.hr.lm.employeeoverride.EmployeeOverride;
026 import org.kuali.hr.lm.timeoff.SystemScheduledTimeOff;
027 import org.kuali.hr.time.principal.PrincipalHRAttributes;
028 import org.kuali.hr.time.service.base.TkServiceLocator;
029 import org.kuali.hr.time.util.TkConstants;
030 import org.kuali.rice.krad.util.GlobalVariables;
031 import org.kuali.rice.krad.util.ObjectUtils;
032
033 public class BalanceTransferValidationUtils {
034
035 public static boolean validateTransfer(BalanceTransfer balanceTransfer) {
036 boolean isValid = true;
037 if(StringUtils.isNotEmpty(balanceTransfer.getSstoId())) {
038 return isValid && validateSstoTranser(balanceTransfer) ;
039 }
040 String principalId = balanceTransfer.getPrincipalId();
041 Date effectiveDate = balanceTransfer.getEffectiveDate();
042 String fromAccrualCategory = balanceTransfer.getFromAccrualCategory();
043 String toAccrualCategory = balanceTransfer.getToAccrualCategory();
044 AccrualCategory fromCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate);
045 AccrualCategory toCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(toAccrualCategory, effectiveDate);
046 PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate);
047
048 if(ObjectUtils.isNotNull(pha)) {
049 if(ObjectUtils.isNotNull(pha.getLeavePlan())) {
050 AccrualCategoryRule acr = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat,
051 effectiveDate, pha.getServiceDate());
052 if(ObjectUtils.isNotNull(acr)) {
053 if(ObjectUtils.isNotNull(acr.getMaxBalFlag())
054 && StringUtils.isNotBlank(acr.getMaxBalFlag())
055 && StringUtils.isNotEmpty(acr.getMaxBalFlag())
056 && StringUtils.equals(acr.getMaxBalFlag(), "Y")) {
057 if(ObjectUtils.isNotNull(acr.getMaxBalanceTransferToAccrualCategory()) || StringUtils.equals(LMConstants.ACTION_AT_MAX_BAL.LOSE, acr.getActionAtMaxBalance())) {
058 /* isValid &= validatePrincipal(pha,principalId);
059 isValid &= validateEffectiveDate(effectiveDate);
060 isValid &= validateAgainstLeavePlan(pha,fromCat,toCat,effectiveDate);
061 isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr);
062 isValid &= validateTransferToAccrualCategory(toCat,principalId,effectiveDate,acr);*/
063 isValid &= validateMaxCarryOver(balanceTransfer.getAmountTransferred(),toCat,principalId,effectiveDate,acr, pha);
064 isValid &= validateTransferAmount(balanceTransfer.getTransferAmount(),fromCat,toCat, principalId, effectiveDate, acr);
065 isValid &= validateForfeitedAmount(balanceTransfer.getForfeitedAmount());
066 }
067 else {
068 //should never be the case if accrual category rules are validated correctly.
069 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
070 "balanceTransfer.fromAccrualCategory.rules.transferToAccrualCategory",
071 fromAccrualCategory);
072 isValid &= false;
073 }
074 }
075 else {
076 //max bal flag null, blank, empty, or "N"
077 GlobalVariables.getMessageMap().putError("document.newMaintinableObject.fromAccrualCategory",
078 "balanceTransfer.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory);
079 isValid &= false;
080 }
081 }
082 else {
083 //department admins must validate amount to transfer does not exceed current balance.
084 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
085 "balanceTransfer.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory());
086 isValid &= false;
087 }
088 }
089 else {
090 //if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited.
091 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noLeavePlan");
092 isValid &=false;
093 }
094 }
095 else {
096 //if the principal has no principal hr attributes, they're not a principal.
097 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","balanceTransfer.principal.noAttributes");
098 isValid &= false;
099 }
100 /* }*/
101 return isValid;
102
103 }
104
105 private static boolean validateForfeitedAmount(BigDecimal forfeitedAmount) {
106 return forfeitedAmount.compareTo(BigDecimal.ZERO) >= 0 ? true: false;
107 }
108
109 private boolean validateMaxBalance() {
110 //This validation could assert that the payout amount, together with forfeiture
111 //brings the balance for the given accrual category back to, or under, the balance limit
112 //without exceeding the total accrued balance.
113 return true;
114 }
115
116 private boolean validateMaxCarryOver() {
117 //This validation could assert that the payout amount, together with forfeiture
118 //brings the balance for the given accrual category back to, or under, the max carry over limit
119 //without exceeding the total accrued balance.
120 return true;
121 }
122
123 private static boolean validateMaxCarryOver(BigDecimal amountTransferred,
124 AccrualCategory toCat, String principalId, Date effectiveDate,
125 AccrualCategoryRule acr, PrincipalHRAttributes pha) {
126 /* List<AccrualCategoryRule> rules = toCat.getAccrualCategoryRules();
127 Date serviceDate = pha.getServiceDate();
128 Interval interval = new Interval(serviceDate.getTime(), effectiveDate.getTime());
129 for(AccrualCategoryRule rule : rules) {
130 String unitOfTime = rule.getServiceUnitOfTime();
131 if(StringUtils.equals(unitOfTime, LMConstants.SERVICE_TIME_MONTHS))
132 }*/
133 return true;
134 }
135
136 private static boolean validateTransferAmount(BigDecimal transferAmount,
137 AccrualCategory fromCat, AccrualCategory toCat, String principalId,
138 Date effectiveDate, AccrualCategoryRule accrualRule) {
139
140 //transfer amount must be less than the max transfer amount defined in the accrual category rule.
141 //it cannot be negative.
142 boolean isValid = true;
143
144 BigDecimal balance = TkServiceLocator.getAccrualCategoryService().getAccruedBalanceForPrincipal(principalId, fromCat, effectiveDate);
145
146 BigDecimal maxTransferAmount = null;
147 BigDecimal adjustedMaxTransferAmount = null;
148 if(ObjectUtils.isNotNull(accrualRule.getMaxTransferAmount())) {
149 maxTransferAmount = new BigDecimal(accrualRule.getMaxTransferAmount());
150 BigDecimal fullTimeEngagement = TkServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate);
151 adjustedMaxTransferAmount = maxTransferAmount.multiply(fullTimeEngagement);
152 }
153
154 //use override if one exists.
155 EmployeeOverride maxTransferAmountOverride = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, fromCat.getLeavePlan(), fromCat.getAccrualCategory(), "MTA", effectiveDate);
156 if(ObjectUtils.isNotNull(maxTransferAmountOverride))
157 adjustedMaxTransferAmount = new BigDecimal(maxTransferAmountOverride.getOverrideValue());
158
159 if(ObjectUtils.isNotNull(adjustedMaxTransferAmount)) {
160 if(transferAmount.compareTo(adjustedMaxTransferAmount) > 0) {
161 isValid &= false;
162 String fromUnitOfTime = TkConstants.UNIT_OF_TIME.get(fromCat.getUnitOfTime());
163 GlobalVariables.getMessageMap().putError("balanceTransfer.transferAmount","balanceTransfer.transferAmount.maxTransferAmount",adjustedMaxTransferAmount.toString(),fromUnitOfTime);
164 }
165 }
166 // check for a positive amount.
167 if(transferAmount.compareTo(BigDecimal.ZERO) < 0 ) {
168 isValid &= false;
169 GlobalVariables.getMessageMap().putError("balanceTransfer.transferAmount","balanceTransfer.transferAmount.negative");
170 }
171
172 if(balance.subtract(transferAmount).compareTo(BigDecimal.ZERO) < 0 ) {
173 if(StringUtils.equals(fromCat.getEarnCodeObj().getAllowNegativeAccrualBalance(),"Y"))
174 isValid &= true;
175 else {
176 isValid &= false;
177 GlobalVariables.getMessageMap().putError("balanceTransfer.transferAmount", "maxBalance.amount.exceedsBalance");
178 }
179 }
180
181 return isValid;
182 }
183
184 public static boolean validateSstoTranser(BalanceTransfer bt) {
185 // make sure from accrual category is consistent with the ssto's
186 SystemScheduledTimeOff ssto = TkServiceLocator.getSysSchTimeOffService().getSystemScheduledTimeOff(bt.getSstoId());
187 if(ssto == null) {
188 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.sstoDoesNotExis", bt.getSstoId());
189 return false;
190 }
191 if(!ssto.getAccrualCategory().equals(bt.getFromAccrualCategory())) {
192 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.fromACWrong", bt.getFromAccrualCategory(), ssto.getAccrualCategory());
193 return false;
194 }
195
196 if(bt.getFromAccrualCategory().equals(bt.getToAccrualCategory())) {
197 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.fromAndToACTheSame");
198 return false;
199 }
200
201 AccrualCategory fromAC = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(bt.getFromAccrualCategory(), bt.getEffectiveDate());
202 if(fromAC == null) {
203 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.acDoesNotExist", bt.getFromAccrualCategory());
204 return false;
205 }
206 AccrualCategory toAC = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(bt.getToAccrualCategory(), bt.getEffectiveDate());
207 if(toAC == null) {
208 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.toAccrualCategory", "balanceTransfer.transferSSTO.acDoesNotExist", bt.getToAccrualCategory());
209 return false;
210 }
211 // make sure the leave plan of from/to accrual categories are consistent with the employee's leave plan
212 PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(bt.getPrincipalId(),bt.getEffectiveDate());
213 if(StringUtils.isNotEmpty(fromAC.getLeavePlan())){
214 if(!fromAC.getLeavePlan().equals(pha.getLeavePlan())) {
215 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory", "balanceTransfer.transferSSTO.wrongACLeavePlan", fromAC.getLeavePlan(), pha.getLeavePlan());
216 return false;
217 }
218 }
219 if(StringUtils.isNotEmpty(toAC.getLeavePlan())){
220 if(!fromAC.getLeavePlan().equals(pha.getLeavePlan())) {
221 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.toAccrualCategory", "balanceTransfer.transferSSTO.wrongACLeavePlan", toAC.getLeavePlan(), pha.getLeavePlan());
222 return false;
223 }
224 }
225
226 return true;
227 }
228
229 }