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.kuali.hr.lm.LMConstants;
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.lm.employeeoverride.EmployeeOverride;
028 import org.kuali.hr.time.principal.PrincipalHRAttributes;
029 import org.kuali.hr.time.service.base.TkServiceLocator;
030 import org.kuali.hr.time.util.TKUtils;
031 import org.kuali.hr.time.util.TkConstants;
032 import org.kuali.rice.krad.util.GlobalVariables;
033 import org.kuali.rice.krad.util.ObjectUtils;
034
035 public class LeavePayoutValidationUtils {
036
037 public static boolean validatePayout(LeavePayout leavePayout) {
038 boolean isValid = true;
039 String principalId = leavePayout.getPrincipalId();
040 Date effectiveDate = leavePayout.getEffectiveDate();
041 String fromAccrualCategory = leavePayout.getFromAccrualCategory();
042 String payoutEarnCode = leavePayout.getEarnCode();
043 AccrualCategory fromCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(fromAccrualCategory, effectiveDate);
044 AccrualCategory toCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(payoutEarnCode, effectiveDate);
045 PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,effectiveDate);
046
047 if(ObjectUtils.isNotNull(pha)) {
048 if(ObjectUtils.isNotNull(pha.getLeavePlan())) {
049 AccrualCategoryRule acr = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(fromCat, effectiveDate, pha.getServiceDate());
050 if(ObjectUtils.isNotNull(acr)) {
051 if(ObjectUtils.isNotNull(acr.getMaxBalFlag())
052 && StringUtils.isNotBlank(acr.getMaxBalFlag())
053 && StringUtils.isNotEmpty(acr.getMaxBalFlag())
054 && StringUtils.equals(acr.getMaxBalFlag(), "Y")) {
055 if(ObjectUtils.isNotNull(acr.getMaxPayoutEarnCode()) || StringUtils.equals(LMConstants.ACTION_AT_MAX_BAL.LOSE, acr.getActionAtMaxBalance())) {
056 /* isValid &= validatePrincipal(pha,principalId);
057 isValid &= validateEffectiveDate(effectiveDate);
058 isValid &= validateAgainstLeavePlan(pha,fromCat,toCat,effectiveDate);
059 isValid &= validateTransferFromAccrualCategory(fromCat,principalId,effectiveDate,acr);
060 isValid &= validateTransferToAccrualCategory(toCat,principalId,effectiveDate,acr);
061 */
062 isValid &= validatePayoutAmount(leavePayout.getPayoutAmount(),fromCat,toCat, principalId, effectiveDate, acr);
063 }
064 else {
065 //should never be the case if accrual category rules are validated correctly.
066 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
067 "leavePayout.fromAccrualCategory.rules.payoutToEarnCode",
068 fromAccrualCategory);
069 isValid &= false;
070 }
071 }
072 else {
073 //max bal flag null, blank, empty, or "N"
074 GlobalVariables.getMessageMap().putError("document.newMaintinableObject.fromAccrualCategory",
075 "leavePayout.fromAccrualCategory.rules.maxBalFlag", fromAccrualCategory);
076 isValid &= false;
077 }
078 }
079 else {
080 //department admins must validate amount to transfer does not exceed current balance.
081 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.fromAccrualCategory",
082 "leavePayout.fromAccrualCategory.rules.exist",fromCat.getAccrualCategory());
083 isValid &= false;
084 }
085 }
086 else {
087 //if the principal doesn't have a leave plan, there aren't any accrual categories that can be debited/credited.
088 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","leavePayout.principal.noLeavePlan");
089 isValid &=false;
090 }
091 }
092 else {
093 //if the principal has no principal hr attributes, they're not a principal.
094 GlobalVariables.getMessageMap().putError("document.newMaintainableObject.principalId","leavePayout.principal.noAttributes");
095 isValid &= false;
096 }
097 /* }*/
098 return isValid;
099
100 }
101
102 private static boolean validatePayoutAmount(BigDecimal payoutAmount,
103 AccrualCategory fromCat, AccrualCategory toCat, String principalId,
104 Date effectiveDate, AccrualCategoryRule accrualRule) {
105
106 BigDecimal balance = TkServiceLocator.getAccrualCategoryService().getAccruedBalanceForPrincipal(principalId, fromCat, effectiveDate);
107 //transfer amount must be less than the max transfer amount defined in the accrual category rule.
108 //it cannot be negative.
109 boolean isValid = true;
110
111 BigDecimal maxPayoutAmount = null;
112 BigDecimal adjustedMaxPayoutAmount = null;
113 if(ObjectUtils.isNotNull(accrualRule.getMaxPayoutAmount())) {
114 maxPayoutAmount = new BigDecimal(accrualRule.getMaxPayoutAmount());
115 BigDecimal fullTimeEngagement = TkServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate);
116 adjustedMaxPayoutAmount = maxPayoutAmount.multiply(fullTimeEngagement);
117 }
118
119 //use override if one exists.
120 EmployeeOverride maxPayoutAmountOverride = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, fromCat.getLeavePlan(), fromCat.getAccrualCategory(), "MPA", effectiveDate);
121 if(ObjectUtils.isNotNull(maxPayoutAmountOverride))
122 adjustedMaxPayoutAmount = new BigDecimal(maxPayoutAmountOverride.getOverrideValue());
123
124
125 if(ObjectUtils.isNotNull(adjustedMaxPayoutAmount)) {
126 if(payoutAmount.compareTo(adjustedMaxPayoutAmount) > 0) {
127 isValid &= false;
128 String fromUnitOfTime = TkConstants.UNIT_OF_TIME.get(fromCat.getUnitOfTime());
129 GlobalVariables.getMessageMap().putError("leavePayout.payoutAmount","leavePayout.payoutAmount.maxPayoutAmount",adjustedMaxPayoutAmount.toString(),fromUnitOfTime);
130 }
131 }
132 // check for a positive amount.
133 if(payoutAmount.compareTo(BigDecimal.ZERO) < 0 ) {
134 isValid &= false;
135 GlobalVariables.getMessageMap().putError("leavePayout.payoutAmount","leavePayout.payoutAmount.negative");
136 }
137
138 if(balance.subtract(payoutAmount).compareTo(BigDecimal.ZERO) < 0 ) {
139 if(StringUtils.equals(fromCat.getEarnCodeObj().getAllowNegativeAccrualBalance(),"Y"))
140 isValid &= true;
141 else {
142 isValid &= false;
143 GlobalVariables.getMessageMap().putError("leavePayout.payoutAmount", "maxBalance.amount.exceedsBalance");
144 }
145 }
146 return isValid;
147 }
148
149 private boolean validateMaxBalance() {
150 //This validation could assert that the payout amount, together with forfeiture
151 //brings the balance for the given accrual category back to, or under, the balance limit
152 //without exceeding the total accrued balance.
153 return true;
154 }
155
156 private boolean validateMaxCarryOver() {
157 //This validation could assert that the payout amount, together with forfeiture
158 //brings the balance for the given accrual category back to, or under, the max carry over limit
159 //without exceeding the total accrued balance.
160 return true;
161 }
162
163 }