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