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.service.impl; 017 018 import java.util.ArrayList; 019 import java.util.Collection; 020 import java.util.HashMap; 021 import java.util.List; 022 import java.util.Map; 023 024 import org.apache.commons.lang.StringUtils; 025 import org.kuali.kfs.coa.businessobject.Account; 026 import org.kuali.kfs.coa.businessobject.AccountGuideline; 027 import org.kuali.kfs.coa.businessobject.Chart; 028 import org.kuali.kfs.coa.service.AccountService; 029 import org.kuali.kfs.coa.service.ChartService; 030 import org.kuali.kfs.integration.cg.ContractsAndGrantsConstants; 031 import org.kuali.kfs.integration.cg.ContractsAndGrantsModuleService; 032 import org.kuali.kfs.integration.cg.dto.AccountCreationStatusDTO; 033 import org.kuali.kfs.integration.cg.dto.AccountParametersDTO; 034 import org.kuali.kfs.integration.cg.service.AccountCreationService; 035 import org.kuali.kfs.module.external.kc.businessobject.AccountAutoCreateDefaults; 036 import org.kuali.kfs.module.external.kc.util.GlobalVariablesExtractHelper; 037 import org.kuali.kfs.module.external.kc.util.KcUtils; 038 import org.kuali.kfs.sys.KFSConstants; 039 import org.kuali.kfs.sys.KFSKeyConstants; 040 import org.kuali.kfs.sys.KFSPropertyConstants; 041 import org.kuali.kfs.sys.context.SpringContext; 042 import org.kuali.rice.kew.exception.WorkflowException; 043 import org.kuali.rice.kim.bo.Person; 044 import org.kuali.rice.kim.service.KIMServiceLocator; 045 import org.kuali.rice.kim.service.PersonService; 046 import org.kuali.rice.kns.UserSession; 047 import org.kuali.rice.kns.datadictionary.AttributeDefinition; 048 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry; 049 import org.kuali.rice.kns.datadictionary.validation.ValidationPattern; 050 import org.kuali.rice.kns.datadictionary.validation.charlevel.AlphaNumericValidationPattern; 051 import org.kuali.rice.kns.document.Document; 052 import org.kuali.rice.kns.document.MaintenanceDocument; 053 import org.kuali.rice.kns.document.authorization.DocumentAuthorizer; 054 import org.kuali.rice.kns.document.authorization.MaintenanceDocumentAuthorizerBase; 055 import org.kuali.rice.kns.exception.ValidationException; 056 import org.kuali.rice.kns.rule.event.BlanketApproveDocumentEvent; 057 import org.kuali.rice.kns.rule.event.RouteDocumentEvent; 058 import org.kuali.rice.kns.rule.event.SaveDocumentEvent; 059 import org.kuali.rice.kns.service.BusinessObjectService; 060 import org.kuali.rice.kns.service.DataDictionaryService; 061 import org.kuali.rice.kns.service.DocumentService; 062 import org.kuali.rice.kns.service.KualiRuleService; 063 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService; 064 import org.kuali.rice.kns.service.ParameterService; 065 import org.kuali.rice.kns.util.GlobalVariables; 066 import org.kuali.rice.kns.util.KNSConstants; 067 import org.kuali.rice.kns.util.ObjectUtils; 068 069 public class AccountCreationServiceImpl implements AccountCreationService { 070 071 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccountCreationServiceImpl.class); 072 073 protected static final String ACCT_PREFIX_RESTRICTION = "PREFIXES"; 074 075 private DocumentService documentService; 076 private ParameterService parameterService; 077 private DataDictionaryService dataDictionaryService; 078 private BusinessObjectService businessObjectService; 079 080 /** 081 * This is the web service method that creates a new account 1. Creates an account object using the parameters from KC and the 082 * default Account table 2. Creates an account automatic maintenance document and puts the account object into it 3. Returns the 083 * status object 084 * 085 * @param AccountAutoCreateDefaults 086 * @return AccountCreationStatusDTO 087 */ 088 public AccountCreationStatusDTO createAccount(AccountParametersDTO accountParameters) { 089 090 AccountCreationStatusDTO accountCreationStatus = new AccountCreationStatusDTO(); 091 accountCreationStatus.setErrorMessages(new ArrayList<String>()); 092 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_SUCCESS); 093 094 // check to see if the user has the permission to create account 095 String principalId = accountParameters.getPrincipalId(); 096 if (!isValidUser(principalId)) { 097 this.setFailStatus(accountCreationStatus, KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_INVALID_USER, new String[]{principalId})); 098 return accountCreationStatus; 099 } 100 101 102 // get the defaults table 103 String unitNumber = accountParameters.getUnit(); 104 AccountAutoCreateDefaults defaults = getAccountDefaults(unitNumber); 105 106 if (defaults == null) { 107 this.setFailStatus(accountCreationStatus, ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_ACCOUNT_PARAMS_UNIT_NOT_DEFINED); 108 return accountCreationStatus; 109 } 110 111 try { 112 // create an account object 113 Account account = createAccountObject(accountParameters, defaults); 114 115 //if invalid chart/account number, failure status and return to KC 116 if (! isValidAccount(account, accountCreationStatus)) { 117 return accountCreationStatus; 118 } 119 // create an account automatic maintenance document 120 createAutomaticCGAccountMaintenanceDocument(account, accountCreationStatus); 121 122 } catch (Exception ex ) { 123 this.setFailStatus(accountCreationStatus, ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_ACCOUNT_GENERATION_PROBLEM); 124 return accountCreationStatus; 125 } 126 127 // set required values to AccountCreationStatus 128 if (accountCreationStatus.getStatus().equals(ContractsAndGrantsConstants.KcWebService.STATUS_KC_SUCCESS)) { 129 accountCreationStatus.setAccountNumber(accountParameters.getAccountNumber()); 130 accountCreationStatus.setChartOfAccountsCode(defaults.getChartOfAccountsCode()); 131 } 132 133 return accountCreationStatus; 134 } 135 136 /** 137 * This method creates an account to be used for automatic maintenance document 138 * 139 * @param AccountParametersDTO 140 * @return Account 141 */ 142 public Account createAccountObject(AccountParametersDTO parameters, AccountAutoCreateDefaults defaults) { 143 144 Account account = new Account(); 145 146 // * Account: required but off campus indicator, closed, fringe benefit indicator, fringe benefit COA, endowment 147 account.setChartOfAccountsCode(defaults.getChartOfAccountsCode()); 148 account.setOrganizationCode(defaults.getOrganizationCode()); 149 account.setAccountNumber(parameters.getAccountNumber()); // what if account number is null? 150 account.setAccountName(parameters.getAccountName()); 151 account.setAccountPhysicalCampusCode(defaults.getAccountPhysicalCampusCode()); 152 if (parameters.getExpirationDate() != null) account.setAccountExpirationDate(new java.sql.Date(parameters.getExpirationDate().getTime())); 153 if (parameters.getEffectiveDate() != null) account.setAccountEffectiveDate(new java.sql.Date(parameters.getEffectiveDate().getTime())); 154 boolean isKCOverrideKFS = parameterService.getIndicatorParameter(Account.class, ContractsAndGrantsConstants.AccountCreationService.PARAMETER_KC_OVERRIDES_KFS_DEFAULT_ACCOUNT_IND); 155 if (isKCOverrideKFS) { 156 // set the right address based on the system parameter ACCOUNT_ADDRESS_TYPE 157 List<String> addressTypes = parameterService.getParameterValues(Account.class, ContractsAndGrantsConstants.AccountCreationService.PARAMETER_KC_ACCOUNT_ADDRESS_TYPE); 158 for (String addressType : addressTypes) { 159 if (addressType.equals(ContractsAndGrantsConstants.AccountCreationService.PI_ADDRESS_TYPE) && (!StringUtils.isBlank(parameters.getDefaultAddressStreetAddress()))) { 160 account.setAccountStreetAddress(parameters.getDefaultAddressStreetAddress()); 161 account.setAccountCityName(parameters.getDefaultAddressCityName()); 162 account.setAccountStateCode(parameters.getDefaultAddressStateCode()); 163 account.setAccountZipCode(parameters.getDefaultAddressZipCode()); 164 break; 165 } 166 else if (addressType.equals(ContractsAndGrantsConstants.AccountCreationService.ADMIN_ADDRESS_TYPE) && (!StringUtils.isBlank(parameters.getAdminContactAddressStreetAddress()))) { 167 account.setAccountStreetAddress(parameters.getAdminContactAddressStreetAddress()); 168 account.setAccountCityName(parameters.getAdminContactAddressCityName()); 169 account.setAccountStateCode(parameters.getAdminContactAddressStateCode()); 170 account.setAccountZipCode(parameters.getAdminContactAddressZipCode()); 171 break; 172 } 173 } 174 175 } else { 176 // use default address 177 account.setAccountStreetAddress(defaults.getAccountStreetAddress()); 178 account.setAccountCityName(defaults.getAccountCityName()); 179 account.setAccountStateCode(defaults.getAccountStateCode()); 180 account.setAccountZipCode(defaults.getAccountZipCode()); 181 } 182 183 //set the following from parameters 184 account.setAccountOffCampusIndicator(parameters.isOffCampusIndicator()); 185 account.setFinancialHigherEdFunctionCd(parameters.getHigherEdFunctionCode()); 186 account.setAcctIndirectCostRcvyTypeCd(parameters.getIndirectCostTypeCode()); 187 account.setFinancialIcrSeriesIdentifier(parameters.getIndirectCostRate()); 188 account.setAccountGuideline(new AccountGuideline()); 189 account.getAccountGuideline().setAccountExpenseGuidelineText(parameters.getExpenseGuidelineText()); 190 account.getAccountGuideline().setAccountIncomeGuidelineText(parameters.getIncomeGuidelineText()); 191 account.getAccountGuideline().setAccountPurposeText(parameters.getPurposeText()); 192 193 account.setClosed(false); 194 account.setAccountTypeCode(defaults.getAccountTypeCode()); 195 account.setSubFundGroupCode(defaults.getSubFundGroupCode()); 196 197 account.setAccountsFringesBnftIndicator(defaults.isAccountsFringesBnftIndicator()); 198 199 account.setReportsToAccountNumber(defaults.getReportsToAccountNumber()); 200 account.setReportsToChartOfAccountsCode(defaults.getReportsToChartOfAccountsCode()); 201 202 account.setAccountRestrictedStatusCode("R"); 203 account.setAccountRestrictedStatusDate(null); 204 205 account.setEndowmentIncomeChartOfAccounts(null); 206 account.setEndowmentIncomeAccountNumber(null); 207 208 // * Accounts Responsibility: required - fiscal officer principal name, account supervisor principal name, account manager 209 // principal name, budget record level, account sufficient funds 210 account.setAccountFiscalOfficerSystemIdentifier(defaults.getAccountFiscalOfficerSystemIdentifier()); 211 212 account.setAccountsSupervisorySystemsIdentifier(defaults.getAccountsSupervisorySystemsIdentifier()); 213 account.setAccountManagerSystemIdentifier(defaults.getAccountManagerSystemIdentifier()); 214 215 account.setContinuationFinChrtOfAcctCd(defaults.getContinuationFinChrtOfAcctCd()); 216 account.setContinuationAccountNumber(defaults.getContinuationAccountNumber()); 217 218 account.setIncomeStreamAccountNumber(defaults.getIncomeStreamAccountNumber()); 219 account.setIncomeStreamChartOfAccounts(defaults.getIncomeStreamChartOfAccounts()); 220 account.setIncomeStreamFinancialCoaCode(defaults.getIncomeStreamFinancialCoaCode()); 221 222 account.setBudgetRecordingLevelCode(defaults.getBudgetRecordingLevelCode()); 223 account.setAccountSufficientFundsCode(defaults.getAccountSufficientFundsCode()); 224 225 account.setPendingAcctSufficientFundsIndicator(defaults.isPendingAcctSufficientFundsIndicator()); 226 account.setExtrnlFinEncumSufficntFndIndicator(defaults.isExtrnlFinEncumSufficntFndIndicator()); 227 account.setIntrnlFinEncumSufficntFndIndicator(defaults.isIntrnlFinEncumSufficntFndIndicator()); 228 account.setFinPreencumSufficientFundIndicator(defaults.isFinPreencumSufficientFundIndicator()); 229 account.setFinancialObjectivePrsctrlIndicator(defaults.isFinancialObjectivePrsctrlIndicator()); 230 231 // * Contract and Grants: not required 232 account.setContractControlFinCoaCode(null); 233 account.setContractControlAccountNumber(null); 234 account.setIndirectCostRcvyFinCoaCode(defaults.getIndirectCostRcvyFinCoaCode()); 235 account.setIndirectCostRecoveryAcctNbr(defaults.getIndirectCostRecoveryAcctNbr()); 236 account.setContractsAndGrantsAccountResponsibilityId(defaults.getContractsAndGrantsAccountResponsibilityId()); 237 account.setAccountCfdaNumber(parameters.getCfdaNumber()); 238 239 return account; 240 } 241 242 protected void setFailStatus(AccountCreationStatusDTO accountCreationStatus, String message) { 243 accountCreationStatus.getErrorMessages().add(message); 244 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_FAILURE); 245 } 246 247 /** 248 * This method will create a maintenance document for CG account create, set its description and then sets the account business 249 * object in it. The document will then be tried to route, save or blanket approve automatically based on the system parameter. 250 * If successful, the method returns the newly created document number to the caller. 251 * 252 * @return documentNumber returns the documentNumber 253 * @see org.kuali.kfs.coa.document.service.CreateAccountService#createAutomaticCGAccountMaintenanceDocument() 254 */ 255 protected void createAutomaticCGAccountMaintenanceDocument(Account account, AccountCreationStatusDTO accountCreationStatus) { 256 257 // create a new maintenance document 258 MaintenanceDocument maintenanceAccountDocument = (MaintenanceDocument) createCGAccountMaintenanceDocument(accountCreationStatus); 259 260 if (ObjectUtils.isNotNull(maintenanceAccountDocument)) { 261 // set document header description... 262 maintenanceAccountDocument.getDocumentHeader().setDocumentDescription(ContractsAndGrantsConstants.AccountCreationService.AUTOMATCICG_ACCOUNT_MAINTENANCE_DOCUMENT_DESCRIPTION); 263 264 // set the account object in the maintenance document. 265 maintenanceAccountDocument.getNewMaintainableObject().setBusinessObject(account); 266 maintenanceAccountDocument.getNewMaintainableObject().setMaintenanceAction(KNSConstants.MAINTENANCE_NEW_ACTION); 267 // the maintenance document will now be routed based on the system parameter value for routing. 268 createRouteAutomaticCGAccountDocument(maintenanceAccountDocument, accountCreationStatus); 269 } 270 } 271 272 /** 273 * This method processes the workflow document actions like save, route and blanket approve depending on the 274 * ACCOUNT_AUTO_CREATE_ROUTE system parameter value. If the system parameter value is not of save or submit or blanketapprove, 275 * put an error message and quit. Throws an document WorkflowException if the specific document action fails to perform. 276 * 277 * @param maintenanceAccountDocument, errorMessages 278 * @return 279 */ 280 protected void createRouteAutomaticCGAccountDocument(MaintenanceDocument maintenanceAccountDocument, AccountCreationStatusDTO accountCreationStatus) { 281 282 try { 283 String accountAutoCreateRouteValue = getParameterService().getParameterValue(Account.class, ContractsAndGrantsConstants.AccountCreationService.PARAMETER_KC_ACCOUNT_ADMIN_AUTO_CREATE_ACCOUNT_WORKFLOW_ACTION); 284 285 // if the accountAutoCreateRouteValue is not save or submit or blanketApprove then put an error message and quit. 286 if (!accountAutoCreateRouteValue.equalsIgnoreCase(KFSConstants.WORKFLOW_DOCUMENT_SAVE) && !accountAutoCreateRouteValue.equalsIgnoreCase("submit") && !accountAutoCreateRouteValue.equalsIgnoreCase(KFSConstants.WORKFLOW_DOCUMENT_BLANKET_APPROVE)) { 287 this.setFailStatus( accountCreationStatus, ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_SYSTEM_PARAMETER_INCORRECT_DOCUMENT_ACTION_VALUE); 288 return; 289 } 290 291 if (accountAutoCreateRouteValue.equalsIgnoreCase(KFSConstants.WORKFLOW_DOCUMENT_SAVE)) { 292 293 //attempt to save if apply rules were successful and there are no errors 294 boolean rulesPassed = SpringContext.getBean(KualiRuleService.class).applyRules(new SaveDocumentEvent(maintenanceAccountDocument)); 295 296 if( rulesPassed && GlobalVariables.getMessageMap().hasNoErrors()){ 297 getDocumentService().saveDocument(maintenanceAccountDocument); 298 }else{ 299 //get errors from apply rules invocation, also clears global variables 300 accountCreationStatus.setErrorMessages(GlobalVariablesExtractHelper.extractGlobalVariableErrors()); 301 try{ 302 //save document, and catch VE's as we want to do this silently 303 getDocumentService().saveDocument(maintenanceAccountDocument); 304 }catch(ValidationException ve){} 305 306 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_SUCCESS); 307 LOG.error( KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_ACCOUNT_RULES_EXCEPTION, new String[]{maintenanceAccountDocument.getDocumentNumber()})); 308 } 309 310 } 311 else if (accountAutoCreateRouteValue.equalsIgnoreCase(KFSConstants.WORKFLOW_DOCUMENT_BLANKET_APPROVE)) { 312 313 //attempt to blanket approve if apply rules were successful and there are no errors 314 boolean rulesPassed = SpringContext.getBean(KualiRuleService.class).applyRules(new BlanketApproveDocumentEvent(maintenanceAccountDocument)); 315 316 if( rulesPassed && GlobalVariables.getMessageMap().hasNoErrors()){ 317 getDocumentService().blanketApproveDocument(maintenanceAccountDocument, "", null); 318 }else{ 319 //get errors from apply rules invocation, also clears global variables 320 accountCreationStatus.setErrorMessages(GlobalVariablesExtractHelper.extractGlobalVariableErrors()); 321 try{ 322 //save document, and catch VE's as we want to do this silently 323 getDocumentService().saveDocument(maintenanceAccountDocument); 324 }catch(ValidationException ve){} 325 326 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_SUCCESS); 327 LOG.error( KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_ACCOUNT_RULES_EXCEPTION, new String[]{maintenanceAccountDocument.getDocumentNumber()})); 328 } 329 330 } 331 else if (accountAutoCreateRouteValue.equalsIgnoreCase("submit")) { 332 333 //attempt to route if apply rules were successful and there are no errors 334 boolean rulesPassed = SpringContext.getBean(KualiRuleService.class).applyRules(new RouteDocumentEvent(maintenanceAccountDocument)); 335 336 if( rulesPassed && GlobalVariables.getMessageMap().hasNoErrors()){ 337 getDocumentService().routeDocument(maintenanceAccountDocument, "", null); 338 }else{ 339 //get errors from apply rules invocation, also clears global variables 340 accountCreationStatus.setErrorMessages(GlobalVariablesExtractHelper.extractGlobalVariableErrors()); 341 try{ 342 //save document, and catch VE's as we want to do this silently 343 getDocumentService().saveDocument(maintenanceAccountDocument); 344 }catch(ValidationException ve){} 345 346 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_SUCCESS); 347 LOG.error( KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_ACCOUNT_RULES_EXCEPTION, new String[]{maintenanceAccountDocument.getDocumentNumber()})); 348 } 349 350 } 351 352 // set the document number 353 accountCreationStatus.setDocumentNumber(maintenanceAccountDocument.getDocumentNumber()); 354 355 } 356 catch (WorkflowException wfe) { 357 358 LOG.error( KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_WORKFLOW_EXCEPTION_DOCUMENT_ACTIONS, null) + ": " + wfe.getMessage()); 359 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_FAILURE); 360 accountCreationStatus.getErrorMessages().add( KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.WARNING_KC_DOCUMENT_WORKFLOW_EXCEPTION_DOCUMENT_ACTIONS, null) + ": " + wfe.getMessage()); 361 362 try { 363 // save it even though it fails to route or blanket approve the document 364 try{ 365 getDocumentService().saveDocument(maintenanceAccountDocument); 366 }catch(ValidationException ve){ 367 //ok to catch validation exceptions at this point 368 } 369 accountCreationStatus.setDocumentNumber(maintenanceAccountDocument.getDocumentNumber()); 370 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_SUCCESS); 371 } 372 catch (WorkflowException e) { 373 LOG.error( KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.WARNING_KC_DOCUMENT_WORKFLOW_EXCEPTION_DOCUMENT_ACTIONS, null) + ": " + e.getMessage()); 374 accountCreationStatus.setErrorMessages(GlobalVariablesExtractHelper.extractGlobalVariableErrors()); 375 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_FAILURE); 376 } 377 378 } 379 catch (Exception ex) { 380 381 LOG.error("Unknown exception occurred: " + ex.getMessage()); 382 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_FAILURE); 383 accountCreationStatus.setErrorMessages(GlobalVariablesExtractHelper.extractGlobalVariableErrors()); 384 accountCreationStatus.getErrorMessages().add(KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.WARNING_KC_DOCUMENT_WORKFLOW_EXCEPTION_DOCUMENT_ACTIONS, null) + ": " + ex.getMessage()); 385 386 try { 387 // save it even though it fails to route or blanket approve the document 388 try{ 389 getDocumentService().saveDocument(maintenanceAccountDocument); 390 }catch(ValidationException ve){ 391 //ok to catch validation exceptions at this point 392 } 393 accountCreationStatus.setDocumentNumber(maintenanceAccountDocument.getDocumentNumber()); 394 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_SUCCESS); 395 } 396 catch (WorkflowException e) { 397 LOG.error( KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.WARNING_KC_DOCUMENT_WORKFLOW_EXCEPTION_DOCUMENT_ACTIONS, null) + ": " + e.getMessage()); 398 accountCreationStatus.setErrorMessages(GlobalVariablesExtractHelper.extractGlobalVariableErrors()); 399 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_FAILURE); 400 } 401 } 402 } 403 404 /** 405 * This method will use the DocumentService to create a new document. The documentTypeName is gathered by using 406 * MaintenanceDocumentDictionaryService which uses Account class to get the document type name. 407 * 408 * @param AccountCreationStatusDTO 409 * @return document returns a new document for the account document type or null if there is an exception thrown. 410 */ 411 public Document createCGAccountMaintenanceDocument(AccountCreationStatusDTO accountCreationStatus) { 412 413 boolean internalUserSession = false; 414 try { 415 if (GlobalVariables.getUserSession() == null) { 416 internalUserSession = true; 417 GlobalVariables.setUserSession(new UserSession(KNSConstants.SYSTEM_USER)); 418 GlobalVariables.clear(); 419 } 420 Document document = getDocumentService().getNewDocument(SpringContext.getBean(MaintenanceDocumentDictionaryService.class).getDocumentTypeName(Account.class)); 421 return document; 422 423 } 424 catch (Exception e) { 425 accountCreationStatus.setErrorMessages(GlobalVariablesExtractHelper.extractGlobalVariableErrors()); 426 accountCreationStatus.setStatus(ContractsAndGrantsConstants.KcWebService.STATUS_KC_FAILURE); 427 return null; 428 } 429 finally { 430 // if a user session was established for this call, clear it our 431 if (internalUserSession) { 432 GlobalVariables.clear(); 433 GlobalVariables.setUserSession(null); 434 } 435 } 436 } 437 438 /** 439 * This method looks up the default table 440 * 441 * @param String unitNumber 442 * @return AccountAutoCreateDefaults 443 */ 444 protected AccountAutoCreateDefaults getAccountDefaults(String unitNumber) { 445 446 AccountAutoCreateDefaults defaults = null; 447 448 if (unitNumber == null || unitNumber.isEmpty()) { 449 return null; 450 } 451 452 Map<String, String> criteria = new HashMap<String, String>(); 453 criteria.put("kcUnit", unitNumber); 454 defaults = (AccountAutoCreateDefaults) businessObjectService.findByPrimaryKey(AccountAutoCreateDefaults.class, criteria); 455 456 // if the matching defaults is null, try the parents in the hierarchy 457 if (defaults == null) { 458 459 List<String> parentUnits = null; 460 try { 461 parentUnits = SpringContext.getBean(ContractsAndGrantsModuleService.class).getParentUnits(unitNumber); 462 } 463 catch (Exception ex) { 464 LOG.error( KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_ACCOUNT_PARAMS_UNIT_NOTFOUND, null) + ": " + ex.getMessage()); 465 466 GlobalVariables.getMessageMap().putError(ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_ACCOUNT_PARAMS_UNIT_NOTFOUND, "kcUnit", ex.getMessage()); 467 468 } 469 470 if (parentUnits != null) { 471 for (String unit : parentUnits) { 472 criteria.put("kcUnit", unit); 473 defaults = (AccountAutoCreateDefaults) businessObjectService.findByPrimaryKey(AccountAutoCreateDefaults.class, criteria); 474 if (defaults != null) 475 break; 476 } 477 } 478 479 } 480 481 return defaults; 482 } 483 484 /** 485 * Check to see if the main link between KFS and KC is valid, namely the chart and account number. 486 * If these two values have some kind of error, then we don't want to generate an Account document 487 * and we'll want to return a failure to KC. 488 * 489 * 490 * @param account 491 * @param accountCreationStatus 492 * @return 493 */ 494 protected boolean isValidAccount(Account account, AccountCreationStatusDTO accountCreationStatus) { 495 boolean isValid = true; 496 String errorMessage = ""; 497 String strSize = ""; 498 499 if (account == null) { 500 //account was not created 501 setFailStatus(accountCreationStatus, ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_ACCOUNT_GENERATION_PROBLEM); 502 return false; 503 } 504 505 if (StringUtils.isBlank(account.getChartOfAccountsCode()) || StringUtils.isBlank(account.getAccountNumber())){ 506 //chart of accounts or account number blank 507 setFailStatus(accountCreationStatus, ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_ACCOUNT_MISSING_CHART_OR_ACCT_NBR); 508 return false; 509 } 510 511 if (!isValidChartCode(account.getChartOfAccountsCode())) { 512 //the chart of accounts code is not valid 513 setFailStatus( accountCreationStatus, ContractsAndGrantsConstants.AccountCreationService.AUTOMATCICG_ACCOUNT_MAINTENANCE_CHART_NOT_DEFINED); 514 return false; 515 } 516 517 if (!isValidAccountNumberLength(account.getAccountNumber(), accountCreationStatus)){ 518 //the account number is an inappropriate length 519 //error set in method 520 return false; 521 } 522 523 if (!checkUniqueAccountNumber(account.getAccountNumber())){ 524 //account is not unique 525 setFailStatus( accountCreationStatus, KcUtils.getErrorMessage(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_NMBR_NOT_UNIQUE, new String[]{account.getAccountNumber()})); 526 return false; 527 } 528 529 if (isValidChartAccount(account.getChartOfAccountsCode(), account.getAccountNumber())) { 530 //the chart and account already exist 531 setFailStatus( accountCreationStatus, ContractsAndGrantsConstants.AccountCreationService.AUTOMATCICG_ACCOUNT_MAINTENANCE_ACCT_ALREADY_DEFINED); 532 return false; 533 } 534 535 if (!checkAccountNumberPrefix(account.getAccountNumber(), accountCreationStatus)){ 536 //account begins with invalid prefix 537 //error set in method 538 return false; 539 } 540 541 return isValid; 542 } 543 544 public boolean accountsCanCrossCharts() { 545 return SpringContext.getBean(AccountService.class).accountsCanCrossCharts(); 546 } 547 548 public boolean isValidAccount(String accountNumber) { 549 Collection<Account> accounts = SpringContext.getBean(AccountService.class).getAccountsForAccountNumber(accountNumber); 550 return (accounts != null && !accounts.isEmpty()); 551 } 552 553 public boolean isValidChartCode(String chartOfAccountsCode) { 554 Chart chart = SpringContext.getBean(ChartService.class).getByPrimaryId(chartOfAccountsCode); 555 return (chart != null); 556 } 557 558 559 public boolean isValidChartAccount(String chartOfAccountsCode, String accountNumber) { 560 AccountService accountService = SpringContext.getBean(AccountService.class); 561 Account account = accountService.getByPrimaryId(chartOfAccountsCode, accountNumber); 562 return (account != null); 563 } 564 565 /** 566 * Checks an account numbers exact length 567 * 568 * @param accountNumber 569 * @param size to be returned 570 * @return 571 */ 572 protected boolean isValidAccountNumberLength(String accountNumber, AccountCreationStatusDTO accountCreationStatus){ 573 574 boolean isValid = false; 575 int fieldSize = -1; 576 577 //grab account number length from DD and set size 578 final BusinessObjectEntry entry = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(Account.class.getName()); 579 AttributeDefinition attributeDefinition = entry.getAttributeDefinition(KFSPropertyConstants.ACCOUNT_NUMBER); 580 581 if(ObjectUtils.isNotNull(attributeDefinition)){ 582 final ValidationPattern validationPattern = attributeDefinition.getValidationPattern(); 583 584 if(ObjectUtils.isNotNull(validationPattern) && validationPattern instanceof AlphaNumericValidationPattern){ 585 AlphaNumericValidationPattern alphaPattern = (AlphaNumericValidationPattern)validationPattern; 586 fieldSize = alphaPattern.getExactLength(); 587 } 588 } 589 590 //skip if account number null 591 if(ObjectUtils.isNotNull(accountNumber)){ 592 593 //data dictionary defined size must equal length of incoming value 594 if(fieldSize == accountNumber.length()){ 595 isValid = true; 596 } 597 } 598 599 if(isValid == false){ 600 setFailStatus( accountCreationStatus, KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.ERROR_KR_ALPHANUMERIC_VALIDATION_EXACT_LENGTH, new String[]{"account number", String.valueOf(fieldSize)})); 601 } 602 603 return isValid; 604 } 605 606 /** 607 * This method tests whether the accountNumber passed in is prefixed with an allowed prefix, or an illegal one. The illegal 608 * prefixes are passed in as an array of strings. 609 * 610 * @param accountNumber - The Account Number to be tested. 611 * @return false if the accountNumber starts with any of the illegalPrefixes, true otherwise 612 */ 613 protected boolean checkAccountNumberPrefix(String accountNumber, AccountCreationStatusDTO accountCreationStatus){ 614 615 boolean success = true; 616 617 // Enforce institutionally specified restrictions on account number prefixes 618 // (e.g. the account number cannot begin with a 3 or with 00.) 619 // Only bother trying if there is an account string to test 620 if (!StringUtils.isBlank(accountNumber)) { 621 622 List<String> illegalValues = getParameterService().getParameterValues(Account.class, ACCT_PREFIX_RESTRICTION); 623 624 for (String illegalValue : illegalValues) { 625 if (accountNumber.startsWith(illegalValue)) { 626 success = false; 627 setFailStatus( accountCreationStatus, KcUtils.getErrorMessage(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_NMBR_NOT_ALLOWED, new String[] { accountNumber, illegalValue })); 628 } 629 } 630 } 631 632 return success; 633 } 634 635 /** 636 * If accounts can't cross charts, then we need to make sure the account number is unique. 637 * 638 * @param accountNumber 639 * @return 640 */ 641 protected boolean checkUniqueAccountNumber(String accountNumber) { 642 boolean success = true; 643 644 // while account is not allowed to cross chart 645 //and with an account number that already exists 646 if (!SpringContext.getBean(AccountService.class).accountsCanCrossCharts() && 647 !SpringContext.getBean(AccountService.class).getAccountsForAccountNumber(accountNumber).isEmpty()) { 648 success = false; 649 } 650 651 return success; 652 } 653 654 /** 655 * This method check to see if the user can create the account maintenance document and set the user session 656 * 657 * @param String principalId 658 * @return boolean 659 */ 660 protected boolean isValidUser(String principalId) { 661 662 PersonService<Person> personService = KIMServiceLocator.getPersonService(); 663 if (principalId == null) return false; 664 Person user = personService.getPerson(principalId); 665 if (user == null) return false; 666 DocumentAuthorizer documentAuthorizer = new MaintenanceDocumentAuthorizerBase(); 667 if (documentAuthorizer.canInitiate(SpringContext.getBean(MaintenanceDocumentDictionaryService.class).getDocumentTypeName(Account.class), user)) { 668 // set the user session so that the user name can be displayed in the saved document 669 GlobalVariables.setUserSession(new UserSession(user.getPrincipalName())); 670 return true; 671 } 672 673 LOG.error(KcUtils.getErrorMessage(ContractsAndGrantsConstants.AccountCreationService.ERROR_KC_DOCUMENT_INVALID_USER, new String[]{principalId})); 674 675 return false; 676 } 677 678 /** 679 * Gets the documentService attribute. 680 * 681 * @return Current value of documentService. 682 */ 683 protected DocumentService getDocumentService() { 684 return documentService; 685 } 686 687 /** 688 * Sets the documentService attribute value. 689 * 690 * @param documentService 691 */ 692 public void setDocumentService(DocumentService documentService) { 693 this.documentService = documentService; 694 } 695 696 /** 697 * Gets the parameterService attribute. 698 * 699 * @return Returns the parameterService. 700 */ 701 protected ParameterService getParameterService() { 702 return parameterService; 703 } 704 705 /** 706 * Sets the parameterService attribute value. 707 * 708 * @param parameterService The parameterService to set. 709 */ 710 public void setParameterService(ParameterService parameterService) { 711 this.parameterService = parameterService; 712 } 713 714 protected DataDictionaryService getDataDictionaryService() { 715 return dataDictionaryService; 716 } 717 718 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 719 this.dataDictionaryService = dataDictionaryService; 720 } 721 722 /** 723 * Sets the businessObjectService attribute value. 724 * 725 * @param businessObjectService The businessObjectService to set. 726 */ 727 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 728 this.businessObjectService = businessObjectService; 729 } 730 731 /** 732 * Gets the businessObjectService attribute. 733 * 734 * @return Returns the businessObjectService. 735 */ 736 protected BusinessObjectService getBusinessObjectService() { 737 return businessObjectService; 738 } 739 740 }