001 /* 002 * Copyright 2011 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.kfs.module.bc.document.service.impl; 017 018 import static org.kuali.kfs.module.bc.BCConstants.AppointmentFundingDurationCodes.LWPA; 019 import static org.kuali.kfs.module.bc.BCConstants.AppointmentFundingDurationCodes.LWPF; 020 import static org.kuali.kfs.module.bc.BCConstants.AppointmentFundingDurationCodes.NONE; 021 022 import java.math.BigDecimal; 023 import java.util.List; 024 025 import org.apache.commons.lang.ObjectUtils; 026 import org.apache.commons.lang.StringUtils; 027 import org.kuali.kfs.module.bc.BCConstants; 028 import org.kuali.kfs.module.bc.BCKeyConstants; 029 import org.kuali.kfs.module.bc.BCPropertyConstants; 030 import org.kuali.kfs.module.bc.BCConstants.SynchronizationCheckType; 031 import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding; 032 import org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService; 033 import org.kuali.kfs.module.bc.document.service.SalarySettingService; 034 import org.kuali.kfs.module.bc.service.HumanResourcesPayrollService; 035 import org.kuali.kfs.sys.KFSConstants; 036 import org.kuali.kfs.sys.KFSPropertyConstants; 037 import org.kuali.rice.kns.util.KualiDecimal; 038 import org.kuali.rice.kns.util.KualiInteger; 039 import org.kuali.rice.kns.util.MessageMap; 040 041 /** 042 * provide a set of rule elements for salary setting. 043 */ 044 public class SalarySettingRuleHelperServiceImpl implements SalarySettingRuleHelperService { 045 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SalarySettingRuleHelperServiceImpl.class); 046 047 private SalarySettingService salarySettingService; 048 private HumanResourcesPayrollService humanResourcesPayrollService; 049 050 /** 051 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#canBeAdjusted(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, org.kuali.rice.kns.util.ErrorMap) 052 */ 053 public boolean canBeAdjusted(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 054 if (appointmentFunding.getEffectiveCSFTracker() == null) { 055 // These error messages should not be displayed since the reported condition is obvious and benign. 056 //errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_AMOUNT, BCKeyConstants.ERROR_CANNOT_ADJUST_FUNDING_WITHOUT_EFFECTIVE_CSF_TRACKER); 057 return false; 058 } 059 060 if (appointmentFunding.isAppointmentFundingDeleteIndicator()) { 061 // These error messages should not be displayed since the reported condition is obvious and benign. 062 //errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_AMOUNT, BCKeyConstants.ERROR_CANNOT_ADJUST_FUNDING_MARKED_AS_DELETE); 063 return false; 064 } 065 066 return true; 067 } 068 069 /** 070 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasActiveJob(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 071 * org.kuali.rice.kns.util.ErrorMap) 072 */ 073 public boolean hasActiveJob(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 074 Integer fiscalYear = appointmentFunding.getUniversityFiscalYear(); 075 String emplid = appointmentFunding.getEmplid(); 076 String positionNumber = appointmentFunding.getPositionNumber(); 077 078 boolean hasActiveJob = humanResourcesPayrollService.isActiveJob(emplid, positionNumber, fiscalYear, SynchronizationCheckType.ALL); 079 if (!hasActiveJob) { 080 errorMap.putError(KFSConstants.GLOBAL_ERRORS, BCKeyConstants.ERROR_NO_ACTIVE_JOB_FOUND, appointmentFunding.getEmplid(), appointmentFunding.getPositionNumber()); 081 return false; 082 } 083 084 return true; 085 } 086 087 /** 088 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasObjectCodeMatchingDefaultOfPosition(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 089 * org.kuali.core.util.ErrorMap) 090 */ 091 public boolean hasObjectCodeMatchingDefaultOfPosition(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 092 String defaultObjectCode = appointmentFunding.getBudgetConstructionPosition().getIuDefaultObjectCode(); 093 String objectCode = appointmentFunding.getFinancialObjectCode(); 094 095 if (!StringUtils.equals(objectCode, defaultObjectCode)) { 096 errorMap.putError(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, BCKeyConstants.ERROR_NOT_DEFAULT_OBJECT_CODE, defaultObjectCode); 097 return false; 098 } 099 100 return true; 101 } 102 103 /** 104 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasRequestedAmountZeroWhenFullYearLeave(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 105 * org.kuali.core.util.ErrorMap) 106 */ 107 public boolean hasRequestedAmountZeroWhenFullYearLeave(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 108 String leaveDurationCode = appointmentFunding.getAppointmentFundingDurationCode(); 109 110 // Request Salary Amount must be zero because these leave codes are for full year leave without pay. 111 if (StringUtils.equals(leaveDurationCode, LWPA.durationCode) || StringUtils.equals(leaveDurationCode, LWPF.durationCode)) { 112 KualiInteger requestedAmount = appointmentFunding.getAppointmentRequestedAmount(); 113 114 if (!requestedAmount.isZero()) { 115 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_AMOUNT, BCKeyConstants.ERROR_REQUEST_AMOUNT_NOT_ZERO_WHEN_FULL_YEAR_LEAVE); 116 return false; 117 } 118 } 119 120 return true; 121 } 122 123 /** 124 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasRequestedFteQuantityZeroWhenFullYearLeave(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 125 * org.kuali.core.util.ErrorMap) 126 */ 127 public boolean hasRequestedFteQuantityZeroWhenFullYearLeave(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 128 String leaveDurationCode = appointmentFunding.getAppointmentFundingDurationCode(); 129 130 // Request Salary Amount must be zero because these leave codes are for full year leave without pay. 131 if (StringUtils.equals(leaveDurationCode, LWPA.durationCode) || StringUtils.equals(leaveDurationCode, LWPF.durationCode)) { 132 BigDecimal requestedFteQuantity = appointmentFunding.getAppointmentRequestedFteQuantity(); 133 134 if (requestedFteQuantity.compareTo(BigDecimal.ZERO) != 0) { 135 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_FTE_QUANTITY, BCKeyConstants.ERROR_REQUEST_FTE_NOT_ZERO_WHEN_FULL_YEAR_LEAVE); 136 return false; 137 } 138 139 return true; 140 } 141 142 return true; 143 } 144 145 /** 146 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasNoExistingLine(java.util.List, 147 * org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, org.kuali.rice.kns.util.ErrorMap) 148 */ 149 public boolean hasNoExistingLine(List<PendingBudgetConstructionAppointmentFunding> appointmentFundings, PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 150 boolean hasNoExistingLine = salarySettingService.findAppointmentFunding(appointmentFundings, appointmentFunding) == null; 151 if (!hasNoExistingLine) { 152 errorMap.putError(BCPropertyConstants.NEW_BCAF_LINE, BCKeyConstants.ERROR_DUPLICATE_FUNDING_LINE); 153 return false; 154 } 155 156 return true; 157 } 158 159 /** 160 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasValidRequestedAmount(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 161 * org.kuali.core.util.ErrorMap) 162 */ 163 public boolean hasValidRequestedAmount(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 164 KualiInteger requestedAmount = appointmentFunding.getAppointmentRequestedAmount(); 165 if (requestedAmount == null || requestedAmount.isNegative()) { 166 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_AMOUNT, BCKeyConstants.ERROR_REQUESTED_AMOUNT_NONNEGATIVE_REQUIRED); 167 return false; 168 } 169 170 return true; 171 } 172 173 public boolean hasValidRequestedAmountQuickSalarySetting(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 174 175 if (this.hasValidRequestedAmount(appointmentFunding, errorMap)){ 176 KualiInteger requestedAmount = appointmentFunding.getAppointmentRequestedAmount(); 177 BigDecimal requestedFteQuantity = appointmentFunding.getAppointmentRequestedFteQuantity(); 178 if (requestedAmount.isPositive() && (requestedFteQuantity != null && requestedFteQuantity.compareTo(BigDecimal.ZERO) == 0)) { 179 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_AMOUNT, BCKeyConstants.ERROR_REQUESTED_AMOUNT_NEEDS_FTE_FIRST); 180 return false; 181 } 182 } 183 184 return true; 185 } 186 187 /** 188 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasValidRequestedCsfAmount(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 189 * org.kuali.core.util.ErrorMap) 190 */ 191 public boolean hasValidRequestedCsfAmount(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 192 KualiInteger csfAmount = appointmentFunding.getAppointmentRequestedCsfAmount(); 193 String leaveDurationCode = appointmentFunding.getAppointmentFundingDurationCode(); 194 195 // Requested csf amount must be greater than 0 if there is a leave 196 if (!StringUtils.equals(leaveDurationCode, NONE.durationCode)) { 197 if (csfAmount == null || !csfAmount.isPositive()) { 198 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_CSF_AMOUNT, BCKeyConstants.ERROR_FTE_GREATER_THAN_ZERO_REQUIRED); 199 return false; 200 } 201 202 return true; 203 } 204 205 return true; 206 } 207 208 /** 209 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasValidRequestedCsfTimePercent(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 210 * org.kuali.core.util.ErrorMap) 211 */ 212 public boolean hasValidRequestedCsfTimePercent(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 213 BigDecimal csfTimePercent = appointmentFunding.getAppointmentRequestedCsfTimePercent(); 214 String leaveDurationCode = appointmentFunding.getAppointmentFundingDurationCode(); 215 216 // Requested csf amount must be greater than 0 if there is a leave 217 if (!StringUtils.equals(leaveDurationCode, NONE.durationCode)) { 218 if (csfTimePercent == null || csfTimePercent.compareTo(BigDecimal.ZERO) <= 0 || csfTimePercent.compareTo(BCConstants.ONE_HUNDRED) > 0 ) { 219 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_CSF_TIME_PERCENT, BCKeyConstants.ERROR_LEAVE_TIME_PERCENT_NOT_IN_RANGE, BigDecimal.ZERO.toPlainString(), BCConstants.ONE_HUNDRED.toPlainString()); 220 return false; 221 } 222 223 return true; 224 } 225 226 return true; 227 } 228 229 /** 230 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasValidRequestedFteQuantity(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 231 * org.kuali.core.util.ErrorMap) 232 */ 233 public boolean hasValidRequestedFteQuantity(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 234 BigDecimal requestedFteQuantity = appointmentFunding.getAppointmentRequestedFteQuantity(); 235 if (requestedFteQuantity == null || requestedFteQuantity.compareTo(BigDecimal.ZERO) < 0 || requestedFteQuantity.compareTo(BigDecimal.ONE) > 0) { 236 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_FTE_QUANTITY, BCKeyConstants.ERROR_FTE_QUANTITY_NOT_IN_RANGE, BigDecimal.ZERO.toPlainString(), BigDecimal.ONE.toPlainString()); 237 return false; 238 } 239 240 return true; 241 } 242 243 /** 244 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasValidRequestedFundingMonth(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 245 * org.kuali.core.util.ErrorMap) 246 */ 247 public boolean hasValidRequestedFundingMonth(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 248 Integer fundingMonths = appointmentFunding.getAppointmentFundingMonth(); 249 if (fundingMonths == null) { 250 errorMap.putError(BCPropertyConstants.APPOINTMENT_FUNDING_MONTH, BCKeyConstants.ERROR_EMPTY_FUNDIN_MONTH); 251 return false; 252 } 253 254 // Requested funding months must be between 0 and position normal work months if there is a leave 255 String leaveDurationCode = appointmentFunding.getAppointmentFundingDurationCode(); 256 Integer normalWorkMonths = appointmentFunding.getBudgetConstructionPosition().getIuNormalWorkMonths(); 257 if (!StringUtils.equals(leaveDurationCode, NONE.durationCode)) { 258 if (fundingMonths < 0 || fundingMonths > normalWorkMonths) { 259 errorMap.putError(BCPropertyConstants.APPOINTMENT_FUNDING_MONTH, BCKeyConstants.ERROR_FUNDIN_MONTH_NOT_IN_RANGE, ObjectUtils.toString(fundingMonths), "0", ObjectUtils.toString(normalWorkMonths)); 260 return false; 261 } 262 263 return true; 264 } 265 266 // Requested funding months must equal to position normal work months if no leave 267 if (!fundingMonths.equals(normalWorkMonths)) { 268 errorMap.putError(BCPropertyConstants.APPOINTMENT_FUNDING_MONTH, BCKeyConstants.ERROR_NOT_EQUAL_NORMAL_WORK_MONTHS, ObjectUtils.toString(fundingMonths), ObjectUtils.toString(normalWorkMonths)); 269 return false; 270 } 271 272 return true; 273 } 274 275 /** 276 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasValidRequestedTimePercent(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 277 * org.kuali.core.util.ErrorMap) 278 */ 279 public boolean hasValidRequestedTimePercent(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 280 KualiInteger requestedAmount = appointmentFunding.getAppointmentRequestedAmount(); 281 BigDecimal requestedTimePercent = appointmentFunding.getAppointmentRequestedTimePercent(); 282 283 if (requestedTimePercent == null) { 284 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_TIME_PERCENT, BCKeyConstants.ERROR_EMPTY_REQUESTED_TIME_PERCENT); 285 return false; 286 } 287 288 if (requestedTimePercent.compareTo(BigDecimal.ZERO) < 0 || requestedTimePercent.compareTo(BCConstants.ONE_HUNDRED) > 0 ) { 289 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_TIME_PERCENT, BCKeyConstants.ERROR_TIME_PERCENT_NOT_IN_RANGE, BigDecimal.ZERO.toPlainString(), BCConstants.ONE_HUNDRED.toPlainString()); 290 return false; 291 } 292 293 if (requestedAmount.isPositive() && requestedTimePercent.compareTo(BigDecimal.ZERO) <= 0) { 294 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_TIME_PERCENT, BCKeyConstants.ERROR_TIME_PERCENT_GREATER_THAN_ZERO_REQUIRED); 295 return false; 296 } 297 298 return true; 299 } 300 301 /** 302 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasValidAdjustmentAmount(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 303 * org.kuali.rice.kns.util.ErrorMap) 304 */ 305 public boolean hasValidAdjustmentAmount(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 306 KualiDecimal adjustmentAmount = appointmentFunding.getAdjustmentAmount(); 307 308 if (adjustmentAmount == null) { 309 errorMap.putError(BCPropertyConstants.ADJUSTMENT_AMOUNT, BCKeyConstants.ERROR_ADJUSTMENT_AMOUNT_REQUIRED); 310 return false; 311 } 312 313 return true; 314 } 315 316 /** 317 * @see org.kuali.kfs.module.bc.document.service.SalarySettingRuleHelperService#hasValidAdjustmentAmount(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding, 318 * org.kuali.rice.kns.util.ErrorMap) 319 */ 320 public boolean hasValidPayRateOrAnnualAmount(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) { 321 BigDecimal payRate = appointmentFunding.getAppointmentRequestedPayRate(); 322 KualiInteger requestedAmount = appointmentFunding.getAppointmentRequestedAmount(); 323 324 if (requestedAmount == null && payRate == null) { 325 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_PAY_RATE, BCKeyConstants.ERROR_EMPTY_PAY_RATE_ANNUAL_AMOUNT); 326 errorMap.putError(BCPropertyConstants.APPOINTMENT_REQUESTED_AMOUNT, BCKeyConstants.ERROR_EMPTY_PAY_RATE_ANNUAL_AMOUNT); 327 return false; 328 } 329 330 return true; 331 } 332 333 /** 334 * Sets the salarySettingService attribute value. 335 * 336 * @param salarySettingService The salarySettingService to set. 337 */ 338 public void setSalarySettingService(SalarySettingService salarySettingService) { 339 this.salarySettingService = salarySettingService; 340 } 341 342 /** 343 * Sets the humanResourcesPayrollService attribute value. 344 * 345 * @param humanResourcesPayrollService The humanResourcesPayrollService to set. 346 */ 347 public void setHumanResourcesPayrollService(HumanResourcesPayrollService humanResourcesPayrollService) { 348 this.humanResourcesPayrollService = humanResourcesPayrollService; 349 } 350 }