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.external.kc.document.validation.impl; 017 018 import java.util.Calendar; 019 import java.util.Collection; 020 import java.util.Date; 021 import java.util.HashMap; 022 import java.util.Map; 023 024 import org.apache.commons.lang.StringUtils; 025 import org.apache.commons.lang.time.DateUtils; 026 import org.kuali.kfs.coa.businessobject.Account; 027 import org.kuali.kfs.coa.businessobject.FundGroup; 028 import org.kuali.kfs.coa.businessobject.IndirectCostRecoveryRateDetail; 029 import org.kuali.kfs.coa.businessobject.SubFundGroup; 030 import org.kuali.kfs.coa.service.AccountService; 031 import org.kuali.kfs.integration.cg.ContractsAndGrantsConstants; 032 import org.kuali.kfs.integration.cg.ContractsAndGrantsModuleService; 033 import org.kuali.kfs.integration.cg.ContractsAndGrantsUnit; 034 import org.kuali.kfs.integration.cg.dto.AccountCreationStatusDTO; 035 import org.kuali.kfs.integration.cg.dto.AccountParametersDTO; 036 import org.kuali.kfs.module.external.kc.KcConstants; 037 import org.kuali.kfs.module.external.kc.businessobject.AccountAutoCreateDefaults; 038 import org.kuali.kfs.module.external.kc.service.impl.AccountCreationServiceImpl; 039 import org.kuali.kfs.sys.KFSConstants; 040 import org.kuali.kfs.sys.KFSKeyConstants; 041 import org.kuali.kfs.sys.KFSPropertyConstants; 042 import org.kuali.kfs.sys.context.SpringContext; 043 import org.kuali.kfs.sys.document.validation.impl.KfsMaintenanceDocumentRuleBase; 044 import org.kuali.kfs.sys.service.UniversityDateService; 045 import org.kuali.rice.kim.bo.Person; 046 import org.kuali.rice.kns.document.MaintenanceDocument; 047 import org.kuali.rice.kns.service.DataDictionaryService; 048 import org.kuali.rice.kns.service.DictionaryValidationService; 049 import org.kuali.rice.kns.service.KualiModuleService; 050 import org.kuali.rice.kns.service.ParameterService; 051 import org.kuali.rice.kns.util.GlobalVariables; 052 import org.kuali.rice.kns.util.KNSConstants; 053 import org.kuali.rice.kns.util.ObjectUtils; 054 055 /** 056 * Business rule(s) applicable to AccountMaintenance documents. 057 */ 058 public class AccountAutoCreateDefaultsRule extends org.kuali.kfs.coa.document.validation.impl.AccountRule { 059 060 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccountAutoCreateDefaultsRule.class); 061 protected static ParameterService parameterService; 062 063 protected AccountService accountService; 064 protected ContractsAndGrantsModuleService contractsAndGrantsModuleService; 065 066 protected AccountAutoCreateDefaults oldAccountAutoCreateDefaults; 067 protected AccountAutoCreateDefaults newAccountAutoCreateDefaults; 068 069 public AccountAutoCreateDefaultsRule() { 070 071 // Pseudo-inject some services. 072 // 073 // This approach is being used to make it simpler to convert the Rule classes 074 // to spring-managed with these services injected by Spring at some later date. 075 // When this happens, just remove these calls to the setters with 076 // SpringContext, and configure the bean defs for spring. 077 this.setContractsAndGrantsModuleService(SpringContext.getBean(ContractsAndGrantsModuleService.class)); 078 accountService = SpringContext.getBean(AccountService.class); 079 } 080 081 /** 082 * This method sets the convenience objects like newAccountAutoCreateDefaults and oldAccountAutoCreateDefaults, so you have 083 * short and easy handles to the new and old objects contained in the maintenance document. It also calls the 084 * BusinessObjectBase.refresh(), which will attempt to load all sub-objects from the DB by their primary keys, if available. 085 */ 086 public void setupConvenienceObjects() { 087 088 // setup oldAccountAutoCreateDefaults convenience objects, make sure all possible sub-objects are populated 089 oldAccountAutoCreateDefaults = (AccountAutoCreateDefaults) super.getOldBo(); 090 091 // setup newAccountAutoCreateDefaults convenience objects, make sure all possible sub-objects are populated 092 newAccountAutoCreateDefaults = (AccountAutoCreateDefaults) super.getNewBo(); 093 } 094 095 /** 096 * This method calls the route rules but does not fail if any of them fail (this only happens on routing) 097 * 098 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument) 099 */ 100 protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) { 101 102 LOG.info("processCustomSaveDocumentBusinessRules called"); 103 // call the route rules to report all of the messages, but ignore the result 104 processCustomRouteDocumentBusinessRules(document); 105 106 // Save always succeeds, even if there are business rule failures 107 return true; 108 } 109 110 /** 111 * This method calls the following rules: checkAccountGuidelinesValidation checkEmptyValues checkGeneralRules checkCloseAccount 112 * checkContractsAndGrants checkExpirationDate checkFundGroup checkSubFundGroup checkFiscalOfficerIsValidKualiUser this rule 113 * will fail on routing 114 * 115 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument) 116 */ 117 protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) { 118 // default to success 119 boolean success = true; 120 121 LOG.info("processCustomRouteDocumentBusinessRules called"); 122 setupConvenienceObjects(); 123 124 success &= checkEmptyValues(document); 125 success &= checkGeneralRules(document); 126 success &= checkContractsAndGrants(document); 127 success &= checkIncomeStreamAccountRule(); 128 success &= checkRequiredKcUnit(newAccountAutoCreateDefaults, document.isNew()); 129 130 return success; 131 } 132 133 protected boolean checkEmptyValues(MaintenanceDocument maintenanceDocument) { 134 135 LOG.info("checkEmptyValues called"); 136 137 boolean success = true; 138 139 // this set confirms that all fields which are grouped (ie, foreign keys of a reference 140 // object), must either be none filled out, or all filled out. 141 success &= checkForPartiallyFilledOutReferenceForeignKeys("continuationAccount"); 142 success &= checkForPartiallyFilledOutReferenceForeignKeys("incomeStreamAccount"); 143 144 success &= checkForPartiallyFilledOutReferenceForeignKeys("reportsToAccount"); 145 success &= checkForPartiallyFilledOutReferenceForeignKeys("indirectCostRecoveryAcct"); 146 147 return success; 148 } 149 150 protected boolean checkGeneralRules(MaintenanceDocument maintenanceDocument) { 151 152 LOG.info("checkGeneralRules called"); 153 Person fiscalOfficer = newAccountAutoCreateDefaults.getAccountFiscalOfficerUser(); 154 Person accountManager = newAccountAutoCreateDefaults.getAccountManagerUser(); 155 Person accountSupervisor = newAccountAutoCreateDefaults.getAccountSupervisoryUser(); 156 157 boolean success = true; 158 159 // check FringeBenefit account rules 160 success &= checkFringeBenefitAccountRule(); 161 162 if (ObjectUtils.isNotNull(fiscalOfficer) && !getDocumentHelperService().getDocumentAuthorizer(maintenanceDocument).isAuthorized(maintenanceDocument, KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_FISCAL_OFFICER, fiscalOfficer.getPrincipalId())) { 163 super.putFieldError("accountFiscalOfficerUser.principalName", KFSKeyConstants.ERROR_USER_MISSING_PERMISSION, new String[] {fiscalOfficer.getName(), KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_FISCAL_OFFICER}); 164 success = false; 165 } 166 if (ObjectUtils.isNotNull(accountSupervisor) && !getDocumentHelperService().getDocumentAuthorizer(maintenanceDocument).isAuthorized(maintenanceDocument, KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_ACCOUNT_SUPERVISOR, accountSupervisor.getPrincipalId())) { 167 super.putFieldError("accountSupervisoryUser.principalName", KFSKeyConstants.ERROR_USER_MISSING_PERMISSION, new String[] {accountSupervisor.getName(), KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_ACCOUNT_SUPERVISOR}); 168 success = false; 169 } 170 if (ObjectUtils.isNotNull(accountManager) && !getDocumentHelperService().getDocumentAuthorizer(maintenanceDocument).isAuthorized(maintenanceDocument, KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_ACCOUNT_MANAGER, accountManager.getPrincipalId())) { 171 super.putFieldError("accountManagerUser.principalName", KFSKeyConstants.ERROR_USER_MISSING_PERMISSION, new String[] {accountManager.getName(), KFSConstants.ParameterNamespaces.CHART, KFSConstants.PermissionNames.SERVE_AS_ACCOUNT_MANAGER}); 172 success = false; 173 } 174 175 // the supervisor cannot be the same as the fiscal officer or account manager. 176 if (isSupervisorSameAsFiscalOfficer()) { 177 success &= false; 178 putFieldError("accountsSupervisorySystemsIdentifier", KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_SUPER_CANNOT_BE_FISCAL_OFFICER); 179 } 180 if (isSupervisorSameAsManager()) { 181 success &= false; 182 putFieldError("accountManagerSystemIdentifier", KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_SUPER_CANNOT_BE_ACCT_MGR); 183 } 184 185 // disallow continuation account being expired 186 if (isContinuationAccountExpired()) { 187 success &= false; 188 putFieldError("continuationAccountNumber", KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCOUNT_EXPIRED_CONTINUATION); 189 } 190 191 return success; 192 } 193 194 protected boolean checkFringeBenefitAccountRule() { 195 196 boolean result = true; 197 198 // if this account is selected as a Fringe Benefit Account, then we have nothing 199 // to test, so exit 200 if (newAccountAutoCreateDefaults.isAccountsFringesBnftIndicator()) { 201 return true; 202 } 203 204 // if fringe benefit is not selected ... continue processing 205 206 // fringe benefit account number is required 207 if (StringUtils.isBlank(newAccountAutoCreateDefaults.getReportsToAccountNumber())) { 208 putFieldError("reportsToAccountNumber", KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_RPTS_TO_ACCT_REQUIRED_IF_FRINGEBENEFIT_FALSE); 209 result &= false; 210 } 211 212 // fringe benefit chart of accounts code is required 213 if (StringUtils.isBlank(newAccountAutoCreateDefaults.getReportsToChartOfAccountsCode())) { 214 putFieldError("reportsToChartOfAccountsCode", KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_RPTS_TO_ACCT_REQUIRED_IF_FRINGEBENEFIT_FALSE); 215 result &= false; 216 } 217 218 // if either of the fringe benefit account fields are not present, then we're done 219 if (result == false) { 220 return result; 221 } 222 223 // attempt to load the fringe benefit account 224 Account fringeBenefitAccount = accountService.getByPrimaryId(newAccountAutoCreateDefaults.getReportsToChartOfAccountsCode(), newAccountAutoCreateDefaults.getReportsToAccountNumber()); 225 226 // fringe benefit account must exist 227 if (fringeBenefitAccount == null) { 228 putFieldError("reportsToAccountNumber", KFSKeyConstants.ERROR_EXISTENCE, getFieldLabel(Account.class, "reportsToAccountNumber")); 229 return false; 230 } 231 232 // fringe benefit account must be active 233 if (!fringeBenefitAccount.isActive()) { 234 putFieldError("reportsToAccountNumber", KFSKeyConstants.ERROR_INACTIVE, getFieldLabel(Account.class, "reportsToAccountNumber")); 235 result &= false; 236 } 237 238 // make sure the fringe benefit account specified is set to fringe benefits = Y 239 if (!fringeBenefitAccount.isAccountsFringesBnftIndicator()) { 240 putFieldError("reportsToAccountNumber", KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_RPTS_TO_ACCT_MUST_BE_FLAGGED_FRINGEBENEFIT, fringeBenefitAccount.getChartOfAccountsCode() + "-" + fringeBenefitAccount.getAccountNumber()); 241 result &= false; 242 } 243 244 return result; 245 } 246 247 protected boolean isSupervisorSameAsFiscalOfficer() { 248 return areTwoUsersTheSame(newAccountAutoCreateDefaults.getAccountSupervisoryUser(), newAccountAutoCreateDefaults.getAccountFiscalOfficerUser()); 249 } 250 251 protected boolean isSupervisorSameAsManager() { 252 return areTwoUsersTheSame(newAccountAutoCreateDefaults.getAccountSupervisoryUser(), newAccountAutoCreateDefaults.getAccountManagerUser()); 253 } 254 255 protected boolean isContinuationAccountExpired() { 256 257 boolean result = false; 258 259 String chartCode = newAccountAutoCreateDefaults.getContinuationFinChrtOfAcctCd(); 260 String accountNumber = newAccountAutoCreateDefaults.getContinuationAccountNumber(); 261 262 // if either chartCode or accountNumber is not entered, then we 263 // can't continue, so exit 264 if (StringUtils.isBlank(chartCode) || StringUtils.isBlank(accountNumber)) { 265 return result; 266 } 267 268 // attempt to retrieve the continuation account from the DB 269 Account continuation = accountService.getByPrimaryId(chartCode, accountNumber); 270 271 // if the object doesn't exist, then we can't continue, so exit 272 if (ObjectUtils.isNull(continuation)) { 273 return result; 274 } 275 276 // at this point, we have a valid continuation account, so we just need to 277 // know whether its expired or not 278 result = continuation.isExpired(); 279 280 return result; 281 } 282 283 protected boolean checkContractsAndGrants(MaintenanceDocument maintenanceDocument) { 284 285 LOG.info("checkContractsAndGrants called"); 286 287 boolean success = true; 288 289 // Certain C&G fields are required if the Account belongs to the CG Fund Group 290 success &= checkCgRequiredFields(); 291 292 // Income Stream account is required if this account is CG fund group, 293 // or GF (general fund) fund group (with some exceptions) 294 success &= checkIncomeStreamValid(); 295 296 // check if the new account has a valid responsibility id 297 if (!ObjectUtils.isNull(newAccountAutoCreateDefaults)) { 298 Account account = new Account(); 299 account.setContractsAndGrantsAccountResponsibilityId(newAccountAutoCreateDefaults.getContractsAndGrantsAccountResponsibilityId()); 300 final boolean hasValidAccountResponsibility = contractsAndGrantsModuleService.hasValidAccountReponsiblityIdIfNotNull(account); 301 if (!hasValidAccountResponsibility) { 302 success &= hasValidAccountResponsibility; 303 putFieldError("contractsAndGrantsAccountResponsibilityId", KFSKeyConstants.ERROR_DOCUMENT_ACCTMAINT_INVALID_CG_RESPONSIBILITY , new String[] { newAccountAutoCreateDefaults.getContractsAndGrantsAccountResponsibilityId().toString(), newAccountAutoCreateDefaults.getChartOfAccountsCode(), "" }); 304 } 305 } 306 307 return success; 308 } 309 310 protected boolean checkCgRequiredFields() { 311 312 boolean result = true; 313 314 // Certain C&G fields are required if the Account belongs to the CG Fund Group 315 if (ObjectUtils.isNotNull(newAccountAutoCreateDefaults.getSubFundGroup())) { 316 if (getSubFundGroupService().isForContractsAndGrants(newAccountAutoCreateDefaults.getSubFundGroup())) { 317 318 result &= checkEmptyBOField("indirectCostRcvyFinCoaCode", newAccountAutoCreateDefaults.getIndirectCostRcvyFinCoaCode(), replaceTokens(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_CHART_CODE_CANNOT_BE_EMPTY)); 319 result &= checkEmptyBOField("indirectCostRecoveryAcctNbr", newAccountAutoCreateDefaults.getIndirectCostRecoveryAcctNbr(), replaceTokens(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_ACCOUNT_CANNOT_BE_EMPTY)); 320 } 321 else { 322 // this is not a C&G fund group. So users should not fill in any fields in the C&G tab. 323 result &= checkCGFieldNotFilledIn("indirectCostRcvyFinCoaCode"); 324 result &= checkCGFieldNotFilledIn("indirectCostRecoveryAcctNbr"); 325 } 326 } 327 return result; 328 } 329 330 protected boolean checkIncomeStreamValid() { 331 // if the subFundGroup object is null, we can't test, so exit 332 if (ObjectUtils.isNull(newAccountAutoCreateDefaults.getSubFundGroup())) { 333 return true; 334 } 335 String subFundGroupCode = newAccountAutoCreateDefaults.getSubFundGroupCode().trim(); 336 String fundGroupCode = newAccountAutoCreateDefaults.getSubFundGroup().getFundGroupCode().trim(); 337 boolean valid = true; 338 if (getParameterService().getParameterEvaluator(Account.class, KFSConstants.ChartApcParms.INCOME_STREAM_ACCOUNT_REQUIRING_FUND_GROUPS, fundGroupCode).evaluationSucceeds()) { 339 if (getParameterService().getParameterEvaluator(Account.class, KFSConstants.ChartApcParms.INCOME_STREAM_ACCOUNT_REQUIRING_SUB_FUND_GROUPS, subFundGroupCode).evaluationSucceeds()) { 340 if (StringUtils.isBlank(newAccountAutoCreateDefaults.getIncomeStreamFinancialCoaCode())) { 341 putFieldError(KFSPropertyConstants.INCOME_STREAM_CHART_OF_ACCOUNTS_CODE, KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_INCOME_STREAM_ACCT_COA_CANNOT_BE_EMPTY, new String[] { getDdService().getAttributeLabel(FundGroup.class, KFSConstants.FUND_GROUP_CODE_PROPERTY_NAME), fundGroupCode, getDdService().getAttributeLabel(SubFundGroup.class, KFSConstants.SUB_FUND_GROUP_CODE_PROPERTY_NAME), subFundGroupCode }); 342 valid = false; 343 } 344 if (StringUtils.isBlank(newAccountAutoCreateDefaults.getIncomeStreamAccountNumber())) { 345 putFieldError(KFSPropertyConstants.INCOME_STREAM_ACCOUNT_NUMBER, KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_INCOME_STREAM_ACCT_NBR_CANNOT_BE_EMPTY, new String[] { getDdService().getAttributeLabel(FundGroup.class, KFSConstants.FUND_GROUP_CODE_PROPERTY_NAME), fundGroupCode, getDdService().getAttributeLabel(SubFundGroup.class, KFSConstants.SUB_FUND_GROUP_CODE_PROPERTY_NAME), subFundGroupCode}); 346 valid = false; 347 } 348 } 349 } 350 return valid; 351 } 352 353 protected boolean checkCGFieldNotFilledIn(String propertyName) { 354 boolean success = true; 355 Object value = ObjectUtils.getPropertyValue(newAccountAutoCreateDefaults, propertyName); 356 if ((value instanceof String && !StringUtils.isBlank(value.toString())) || (value != null)) { 357 success = false; 358 putFieldError(propertyName, KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_CG_FIELDS_FILLED_FOR_NON_CG_ACCOUNT, new String[] { newAccountAutoCreateDefaults.getSubFundGroupCode() }); 359 } 360 361 return success; 362 } 363 364 protected boolean checkIncomeStreamAccountRule() { 365 // KFSMI-4877: if fund group is in system parameter values then income stream account number must exist. 366 if ( ObjectUtils.isNotNull(newAccountAutoCreateDefaults.getSubFundGroup()) && StringUtils.isNotBlank(newAccountAutoCreateDefaults.getSubFundGroup().getFundGroupCode())) { 367 if (ObjectUtils.isNull(newAccountAutoCreateDefaults.getIncomeStreamAccount())) { 368 String incomeStreamRequiringFundGroupCode = SpringContext.getBean(ParameterService.class).getParameterValue(Account.class, KFSConstants.ChartApcParms.INCOME_STREAM_ACCOUNT_REQUIRING_FUND_GROUPS); 369 if (StringUtils.containsIgnoreCase(newAccountAutoCreateDefaults.getSubFundGroup().getFundGroupCode(), incomeStreamRequiringFundGroupCode)) { 370 GlobalVariables.getMessageMap().putError(KFSPropertyConstants.ACCOUNT_NUMBER, KFSKeyConstants.ERROR_DOCUMENT_BA_NO_INCOME_STREAM_ACCOUNT, ""); 371 return false; 372 } 373 } 374 } 375 return true; 376 } 377 378 /** 379 * This method checks to make sure that the kcUnit field exists and is entered correctly 380 * 381 * @param newAccountAutoCreateDefaults 382 * @return true/false 383 */ 384 protected boolean checkRequiredKcUnit(AccountAutoCreateDefaults newAccountAutoCreateDefaults, boolean isNew) { 385 386 boolean result = true; 387 try { 388 ContractsAndGrantsUnit unitDTO = newAccountAutoCreateDefaults.getUnitDTO(); 389 unitDTO = (ContractsAndGrantsUnit) SpringContext.getBean(KualiModuleService.class).getResponsibleModuleService(ContractsAndGrantsUnit.class).retrieveExternalizableBusinessObjectIfNecessary(newAccountAutoCreateDefaults, unitDTO, "unitDTO"); 390 if (unitDTO == null) { 391 putFieldError(KcConstants.AccountCreationDefaults.KcUnit, ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_ACCOUNT_PARAMS_UNIT_NOTFOUND, newAccountAutoCreateDefaults.getKcUnit()); 392 result &= false; 393 } 394 // in the case of new accounts check if KcUnit exists already in accountAutoCreateDefaults table - if so reject 395 if (isNew) { 396 // check for new copy and new conditions 397 String kcUnit = newAccountAutoCreateDefaults.getKcUnit(); 398 if ((kcUnit != null)) { 399 HashMap<String, String> map = new HashMap<String,String>(); 400 401 map.put(KcConstants.AccountCreationDefaults.KcUnit, kcUnit); 402 Collection <AccountAutoCreateDefaults> accountAutoCreateDefaultList = boService.findMatching(AccountAutoCreateDefaults.class, map); 403 if (accountAutoCreateDefaultList == null || (! accountAutoCreateDefaultList.isEmpty())) { 404 putFieldError(KcConstants.AccountCreationDefaults.KcUnit, ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_ACCOUNT_ALREADY_DEFINED, newAccountAutoCreateDefaults.getKcUnit()); 405 result &= false; 406 } 407 } 408 } 409 return result; 410 } 411 catch (Exception ex) { 412 putFieldError(KcConstants.AccountCreationDefaults.KcUnit, ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_ACCOUNT_PARAMS_UNIT_NOTFOUND, newAccountAutoCreateDefaults.getKcUnit()); 413 return false; 414 } 415 } 416 417 418 /** 419 * Sets the contractsAndGrantsModuleService attribute value. 420 * 421 * @param contractsAndGrantsModuleService The contractsAndGrantsModuleService to set. 422 */ 423 public void setContractsAndGrantsModuleService(ContractsAndGrantsModuleService contractsAndGrantsModuleService) { 424 this.contractsAndGrantsModuleService = contractsAndGrantsModuleService; 425 } 426 427 428 public ParameterService getParameterService() { 429 if (parameterService == null) { 430 parameterService = SpringContext.getBean(ParameterService.class); 431 } 432 return parameterService; 433 } 434 435 }