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.coa.document.validation.impl; 017 018 import java.sql.Date; 019 import java.sql.Timestamp; 020 import java.util.Calendar; 021 import java.util.Iterator; 022 import java.util.List; 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.Organization; 028 import org.kuali.kfs.coa.service.OrganizationService; 029 import org.kuali.kfs.sys.KFSConstants; 030 import org.kuali.kfs.sys.KFSKeyConstants; 031 import org.kuali.kfs.sys.KFSPropertyConstants; 032 import org.kuali.kfs.sys.context.SpringContext; 033 import org.kuali.kfs.sys.identity.KfsKimAttributes; 034 import org.kuali.rice.kim.bo.Person; 035 import org.kuali.rice.kim.bo.types.dto.AttributeSet; 036 import org.kuali.rice.kim.service.IdentityManagementService; 037 import org.kuali.rice.kim.util.KimConstants; 038 import org.kuali.rice.kns.document.MaintenanceDocument; 039 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; 040 import org.kuali.rice.kns.service.ParameterService; 041 import org.kuali.rice.kns.util.GlobalVariables; 042 import org.kuali.rice.kns.util.ObjectUtils; 043 044 /** 045 * This class implements the business rules specific to the {@link Org} Maintenance Document. 046 */ 047 public class OrgRule extends MaintenanceDocumentRuleBase { 048 049 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(OrgRule.class); 050 051 052 protected static OrganizationService orgService; 053 054 protected Organization oldOrg; 055 protected Organization newOrg; 056 protected boolean isHrmsOrgActivated; 057 058 /** 059 * Constructs a OrgRule and pseudo-injects services 060 */ 061 public OrgRule() { 062 super(); 063 064 // Pseudo-inject some services. 065 // 066 // This approach is being used to make it simpler to convert the Rule classes 067 // to spring-managed with these services injected by Spring at some later date. 068 // When this happens, just remove these calls to the setters with 069 // SpringContext, and configure the bean defs for spring. 070 if (orgService == null) { 071 orgService = SpringContext.getBean(OrganizationService.class); 072 } 073 } 074 075 /** 076 * This performs the following checks on document approve: 077 * <ul> 078 * <li>{@link OrgRule#checkExistenceAndActive()}</li> 079 * <li>{@link OrgRule#checkOrgClosureRules(MaintenanceDocument)}</li> 080 * <li>{@link OrgRule#checkSimpleRules(MaintenanceDocument)}</li> 081 * <li>{@link OrgRule#checkDefaultAccountNumber(MaintenanceDocument)}</li> 082 * </ul> 083 * This rule fails on rule failure 084 * 085 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomApproveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument) 086 */ 087 protected boolean processCustomApproveDocumentBusinessRules(MaintenanceDocument document) { 088 089 boolean success = true; 090 091 LOG.info("Entering processCustomApproveDocumentBusinessRules()"); 092 093 // determine whether HRMS ORG is activated in this app instance 094 isHrmsOrgActivated = isHrmsOrgActivated(); 095 096 // check that all sub-objects whose keys are specified have matching objects in the db 097 success &= checkExistenceAndActive(); 098 099 success &= checkOrgClosureRules(document); 100 101 // check that end date is greater than begin date and Reports To Chart/Org should not be same as this Chart/Org 102 success &= checkSimpleRules(document); 103 104 // check that defaultAccount is present unless 105 // ( (orgType = U or C) and ( document is a "create new" )) 106 success &= checkDefaultAccountNumber(document); 107 return success; 108 } 109 110 /** 111 * This performs the following checks on document route: 112 * <ul> 113 * <li>{@link OrgRule#checkExistenceAndActive()}</li> 114 * <li>{@link OrgRule#checkOrgClosureRules(MaintenanceDocument)}</li> 115 * <li>{@link OrgRule#checkSimpleRules(MaintenanceDocument)}</li> 116 * <li>{@link OrgRule#checkDefaultAccountNumber(MaintenanceDocument)}</li> 117 * </ul> 118 * This rule fails on rule failure 119 * 120 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument) 121 */ 122 protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) { 123 124 boolean success = true; 125 126 LOG.info("Entering processCustomRouteDocumentBusinessRules()"); 127 128 // determine whether HRMS ORG is activated in this app instance 129 isHrmsOrgActivated = isHrmsOrgActivated(); 130 131 // check that all sub-objects whose keys are specified have matching objects in the db 132 success &= checkExistenceAndActive(); 133 134 // check that end date is greater than begin date and Reports To Chart/Org should not be same as this Chart/Org 135 success &= checkSimpleRules(document); 136 137 // check that defaultAccount is present unless 138 // ( (orgType = U or C) and ( document is a "create new" )) 139 success &= checkDefaultAccountNumber(document); 140 141 success &= checkOrgClosureRules(document); 142 143 return success; 144 } 145 146 /** 147 * This performs the following checks on document save: 148 * <ul> 149 * <li>{@link OrgRule#checkExistenceAndActive()}</li> 150 * <li>{@link OrgRule#checkOrgClosureRules(MaintenanceDocument)}</li> 151 * <li>{@link OrgRule#checkSimpleRules(MaintenanceDocument)}</li> 152 * <li>{@link OrgRule#checkDefaultAccountNumber(MaintenanceDocument)}</li> 153 * </ul> 154 * This rule does not fail on rule failure 155 * 156 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument) 157 */ 158 protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) { 159 160 LOG.info("Entering processCustomSaveDocumentBusinessRules()"); 161 162 // determine whether HRMS ORG is activated in this app instance 163 isHrmsOrgActivated = isHrmsOrgActivated(); 164 165 // check that all sub-objects whose keys are specified have matching objects in the db 166 checkExistenceAndActive(); 167 168 checkOrgClosureRules(document); 169 170 // check that end date is greater than begin date and Reports To Chart/Org should not be same as this Chart/Org 171 checkSimpleRules(document); 172 173 // check that defaultAccount is present unless 174 // ( (orgType = U or C) and ( document is a "create new" )) 175 checkDefaultAccountNumber(document); 176 177 return true; 178 } 179 180 /** 181 * This checks to see if the org is active 182 * 183 * @return true if the org is inactive or false otherwise 184 */ 185 protected boolean checkExistenceAndActive() { 186 187 LOG.info("Entering checkExistenceAndActive()"); 188 boolean success = true; 189 190 // shortcut out with no enforcement if this org is closed 191 if (!newOrg.isActive()) { 192 return success; 193 } 194 195 success &= checkPlantAttributes(); 196 197 return success; 198 } 199 200 /** 201 * This checks to see if a user is authorized for plant fields modification. If not then it returns true (without activating 202 * fields). If the org does not have to report to itself then it checks to see if the plant fields have been filled out 203 * correctly and fails if they haven't 204 * 205 * @return false if user can edit plant fields but they have not been filled out correctly 206 */ 207 protected boolean checkPlantAttributes() { 208 209 boolean success = true; 210 211 /* 212 * KULCOA-1132 - exit if the user is not a member of the plant maintainer work group. 213 */ 214 215 // get user 216 Person user = GlobalVariables.getUserSession().getPerson(); 217 218 // if not authroized to edit plant fields, exit with true 219 if (isPlantAuthorized(user) == false) { 220 return true; 221 } 222 223 // relax this edit for 224 if (!getOrgMustReportToSelf(newOrg)) { 225 // require Org Plant ChartCode 226 success &= checkEmptyBOField("organizationPlantChartCode", newOrg.getOrganizationPlantChartCode(), "Organization Plant Chart of Accounts Code"); 227 228 // require Org Plant AccountNumber 229 success &= checkEmptyBOField("organizationPlantAccountNumber", newOrg.getOrganizationPlantAccountNumber(), "Organization Plant Account Number"); 230 231 // require Campus Plant ChartCode 232 success &= checkEmptyBOField("campusPlantChartCode", newOrg.getCampusPlantChartCode(), "Campus Plant Chart of Accounts Code"); 233 234 // require Org Plant ChartCode 235 success &= checkEmptyBOField("campusPlantAccountNumber", newOrg.getCampusPlantAccountNumber(), "Campus Plant Account Number"); 236 237 // validate Org Plant Account 238 success &= getDictionaryValidationService().validateReferenceExistsAndIsActive(newOrg, "organizationPlantAccount", MAINTAINABLE_ERROR_PREFIX + "organizationPlantAccountNumber", "Organization Plant Account"); 239 240 // validate Campus Plant Account 241 success &= getDictionaryValidationService().validateReferenceExistsAndIsActive(newOrg, "campusPlantAccount", MAINTAINABLE_ERROR_PREFIX + "campusPlantAccountNumber", "Campus Plant Account"); 242 } 243 244 return success; 245 } 246 247 /** 248 * This method enforces the business rules surrounding when an Org becomes closed/inactive. If we are editing and switching the 249 * org to inactive or if it is a new doc and it is marked as inactive then we assume we are closing the org. If we are not then 250 * we return true. If we are then we return false if there are still active accounts tied to the org 251 * 252 * @param document 253 * @return false if trying to close org but it still has accounts that are active linked to it 254 */ 255 protected boolean checkOrgClosureRules(MaintenanceDocument document) { 256 257 boolean success = true; 258 boolean orgBeingClosed = false; 259 260 // if its an edit, and its being closed 261 if (document.isEdit()) { 262 if (oldOrg.isActive() && !newOrg.isActive()) { 263 orgBeingClosed = true; 264 } 265 } 266 267 // if its new, and is being created as closed 268 if (document.isNew()) { 269 if (!newOrg.isActive()) { 270 orgBeingClosed = true; 271 } 272 } 273 274 // if the org isnt being closed, stop processing here 275 if (!orgBeingClosed) { 276 return success; 277 } 278 279 // FROM HERE ON WE'RE ASSUMING THE ORG IS BEING CLOSED 280 281 // do not allow the org to be closed while there are active accounts tied 282 // to this org 283 List childAccounts = orgService.getActiveAccountsByOrg(newOrg.getChartOfAccountsCode(), newOrg.getOrganizationCode()); 284 if (childAccounts.size() > 0) { 285 286 // get the first three accounts on the list for display 287 StringBuffer childAccountList = new StringBuffer(); 288 int count = 0; 289 String delim = ""; 290 for (Iterator iter = childAccounts.iterator(); iter.hasNext();) { 291 Account account = (Account) iter.next(); 292 childAccountList.append(delim + account.getChartOfAccountsCode() + "-" + account.getAccountNumber()); 293 count++; 294 if (count >= 1) { 295 delim = ", "; 296 } 297 if (count >= 3) { 298 break; 299 } 300 } 301 if (childAccounts.size() > count) { 302 childAccountList.append(", ... (" + (childAccounts.size() - count) + " more)"); 303 } 304 305 putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_OPEN_CHILD_ACCOUNTS_ON_ORG_CLOSURE, childAccountList.toString()); 306 success &= false; 307 } 308 309 // do not allow this org to be closed while there are still active orgs 310 // that have this org as their reportsToOrg 311 List childOrgs = orgService.getActiveChildOrgs(newOrg.getChartOfAccountsCode(), newOrg.getOrganizationCode()); 312 if (childOrgs.size() > 0) { 313 314 // get the first three orgs on the list for display 315 StringBuffer childOrgsList = new StringBuffer(); 316 int count = 0; 317 String delim = ""; 318 for (Iterator iter = childOrgs.iterator(); iter.hasNext();) { 319 Organization org = (Organization) iter.next(); 320 childOrgsList.append(delim + org.getChartOfAccountsCode() + "-" + org.getOrganizationCode()); 321 count++; 322 if (count >= 1) { 323 delim = ", "; 324 } 325 if (count >= 3) { 326 break; 327 } 328 } 329 if (childOrgs.size() > count) { 330 childOrgsList.append(", ... (" + (childOrgs.size() - count) + " more)"); 331 } 332 333 putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_OPEN_CHILD_ORGS_ON_ORG_CLOSURE, childOrgsList.toString()); 334 success &= false; 335 } 336 337 338 // if org is being closed, end-date must be valid and present 339 if (ObjectUtils.isNull(newOrg.getOrganizationEndDate())) { 340 success &= false; 341 putFieldError("organizationEndDate", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_END_DATE_REQUIRED_ON_ORG_CLOSURE); 342 } 343 return success; 344 345 } 346 347 /** 348 * This checks to see if the org is active and if it the HRMS org is active 349 * 350 * @param document 351 * @return true if either the org is inactive or isHrmsOrgActivated is false 352 */ 353 protected boolean checkHrmsOrgRules(MaintenanceDocument document) { 354 355 boolean success = true; 356 357 // shortcut out with no enforcement if this org is closed 358 if (!newOrg.isActive()) { 359 return success; 360 } 361 362 // short circuit and fail if HRMSOrg is turned off 363 if (!isHrmsOrgActivated) { 364 return success; 365 } 366 367 // if the system has a HRMS Org record attached to this org record, then prompt the 368 // user to fill out the HRMS Org info 369 370 // HRMS Org Campus == Org Campus 371 // HRMS Org campus code must be the same as Org campus code 372 373 374 // if the 375 return success; 376 } 377 378 /** 379 * This checks our {@link Parameter} rules to see if this org needs to report to itself 380 * 381 * @param organization 382 * @return true if it does 383 */ 384 protected boolean getOrgMustReportToSelf(Organization organization) { 385 return SpringContext.getBean(ParameterService.class).getParameterEvaluator(Organization.class, KFSConstants.ChartApcParms.ORG_MUST_REPORT_TO_SELF_ORG_TYPES, organization.getOrganizationTypeCode()).evaluationSucceeds(); 386 } 387 388 /** 389 * This checks the following conditions: 390 * <ul> 391 * <li>begin date must be greater than or equal to end date</li> 392 * <li>start date must be greater than or equal to today if new Document</li> 393 * <li>Reports To Chart/Org should not be same as this Chart/Org</li> 394 * </ul> 395 * 396 * @param document 397 * @return true if it passes all the rules, false otherwise 398 */ 399 protected boolean checkSimpleRules(MaintenanceDocument document) { 400 401 boolean success = true; 402 String lastReportsToChartOfAccountsCode; 403 String lastReportsToOrganizationCode; 404 boolean continueSearch; 405 Organization tempOrg; 406 Integer loopCount; 407 Integer maxLoopCount = 40; 408 409 // begin date must be greater than or equal to end date 410 if ((ObjectUtils.isNotNull(newOrg.getOrganizationBeginDate()) && (ObjectUtils.isNotNull(newOrg.getOrganizationEndDate())))) { 411 412 Date beginDate = newOrg.getOrganizationBeginDate(); 413 Date endDate = newOrg.getOrganizationEndDate(); 414 415 if (endDate.before(beginDate)) { 416 putFieldError("organizationEndDate", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_END_DATE_GREATER_THAN_BEGIN_DATE); 417 success &= false; 418 } 419 } 420 421 // start date must be greater than or equal to today if new Document 422 if ((ObjectUtils.isNotNull(newOrg.getOrganizationBeginDate()) && (document.isNew()))) { 423 Timestamp today = getDateTimeService().getCurrentTimestamp(); 424 today.setTime(DateUtils.truncate(today, Calendar.DAY_OF_MONTH).getTime()); 425 if (newOrg.getOrganizationBeginDate().before(today)) { 426 putFieldError("organizationBeginDate", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_STARTDATE_IN_PAST); 427 success &= false; 428 } 429 } 430 431 // Reports To Chart/Org should not be same as this Chart/Org 432 // However, allow special case where organization type is listed in the business rules 433 if (ObjectUtils.isNotNull(newOrg.getReportsToChartOfAccountsCode()) && ObjectUtils.isNotNull(newOrg.getReportsToOrganizationCode()) && ObjectUtils.isNotNull(newOrg.getChartOfAccountsCode()) && ObjectUtils.isNotNull(newOrg.getOrganizationCode())) { 434 if (!getOrgMustReportToSelf(newOrg)) { 435 436 if ((newOrg.getReportsToChartOfAccountsCode().equals(newOrg.getChartOfAccountsCode())) && (newOrg.getReportsToOrganizationCode().equals(newOrg.getOrganizationCode()))) { 437 putFieldError("reportsToOrganizationCode", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_REPORTING_ORG_CANNOT_BE_SAME_ORG); 438 success = false; 439 } 440 else { 441 // Don't allow a circular reference on Reports to Chart/Org 442 // terminate the search when a top-level org is found 443 lastReportsToChartOfAccountsCode = newOrg.getReportsToChartOfAccountsCode(); 444 lastReportsToOrganizationCode = newOrg.getReportsToOrganizationCode(); 445 continueSearch = true; 446 loopCount = 0; 447 do { 448 tempOrg = orgService.getByPrimaryId(lastReportsToChartOfAccountsCode, lastReportsToOrganizationCode); 449 loopCount++; 450 ; 451 if (ObjectUtils.isNull(tempOrg)) { 452 continueSearch = false; 453 // if a null is returned on the first iteration, then the reports-to org does not exist 454 // fail the validation 455 if (loopCount == 1) { 456 putFieldError("reportsToOrganizationCode", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_REPORTING_ORG_MUST_EXIST); 457 success = false; 458 } 459 } 460 else { 461 // on the first iteration, check whether the reports-to organization is active 462 if (loopCount == 1 && !tempOrg.isActive()) { 463 putFieldError("reportsToOrganizationCode", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_REPORTING_ORG_MUST_EXIST); 464 success = false; 465 continueSearch = false; 466 } 467 else { 468 // LOG.info("Found Org = " + lastReportsToChartOfAccountsCode + "/" + 469 // lastReportsToOrganizationCode); 470 lastReportsToChartOfAccountsCode = tempOrg.getReportsToChartOfAccountsCode(); 471 lastReportsToOrganizationCode = tempOrg.getReportsToOrganizationCode(); 472 473 if ((tempOrg.getReportsToChartOfAccountsCode().equals(newOrg.getChartOfAccountsCode())) && (tempOrg.getReportsToOrganizationCode().equals(newOrg.getOrganizationCode()))) { 474 putFieldError("reportsToOrganizationCode", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_REPORTING_ORG_CANNOT_BE_CIRCULAR_REF_TO_SAME_ORG); 475 success = false; 476 continueSearch = false; 477 } 478 } 479 } 480 if (loopCount > maxLoopCount) { 481 continueSearch = false; 482 } 483 // stop the search if we reach an org that must report to itself 484 if (continueSearch && SpringContext.getBean(ParameterService.class).getParameterEvaluator(Organization.class, KFSConstants.ChartApcParms.ORG_MUST_REPORT_TO_SELF_ORG_TYPES, tempOrg.getOrganizationTypeCode()).evaluationSucceeds()) { 485 continueSearch = false; 486 } 487 488 } while (continueSearch == true); 489 } // end else (checking for circular ref) 490 } 491 else { // org must report to self (university level organization) 492 if (!(newOrg.getReportsToChartOfAccountsCode().equals(newOrg.getChartOfAccountsCode()) && newOrg.getReportsToOrganizationCode().equals(newOrg.getOrganizationCode()))) { 493 putFieldError("reportsToOrganizationCode", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_REPORTING_ORG_MUST_BE_SAME_ORG); 494 success = false; 495 } 496 // org must be the only one of that type 497 String topLevelOrgTypeCode = SpringContext.getBean(ParameterService.class).getParameterValue(Organization.class, KFSConstants.ChartApcParms.ORG_MUST_REPORT_TO_SELF_ORG_TYPES); 498 List<Organization> topLevelOrgs = orgService.getActiveOrgsByType(topLevelOrgTypeCode); 499 if (!topLevelOrgs.isEmpty()) { 500 // is the new org in the topLevelOrgs list? If not, then there's an error; if so, we're editing the top level 501 // org 502 if (!topLevelOrgs.contains(newOrg)) { 503 putFieldError("organizationTypeCode", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_ONLY_ONE_TOP_LEVEL_ORG, topLevelOrgs.get(0).getChartOfAccountsCode() + "-" + topLevelOrgs.get(0).getOrganizationCode()); 504 success = false; 505 } 506 } 507 } 508 } 509 510 511 return success; 512 } 513 514 515 /** 516 * This checks that defaultAccount is present unless ( (orgType = U or C) and ( document is a "create new" or "edit" )) 517 * 518 * @param document 519 * @return false if missing default account number and it is not an exempt type code 520 */ 521 protected boolean checkDefaultAccountNumber(MaintenanceDocument document) { 522 523 boolean success = true; 524 boolean exemptOrganizationTypeCode = false; 525 boolean missingDefaultAccountNumber = StringUtils.isBlank(newOrg.getOrganizationDefaultAccountNumber()); 526 527 if (ObjectUtils.isNotNull(newOrg.getOrganizationTypeCode())) { 528 String organizationTypeCode = newOrg.getOrganizationTypeCode(); 529 if (SpringContext.getBean(ParameterService.class).getParameterEvaluator(Organization.class, KFSConstants.ChartApcParms.DEFAULT_ACCOUNT_NOT_REQUIRED_ORG_TYPES, newOrg.getOrganizationTypeCode()).evaluationSucceeds()) { 530 exemptOrganizationTypeCode = true; 531 } 532 } 533 534 if (missingDefaultAccountNumber && (!exemptOrganizationTypeCode || (!document.isNew() && !document.isEdit()))) { 535 putFieldError("organizationDefaultAccountNumber", KFSKeyConstants.ERROR_DOCUMENT_ORGMAINT_DEFAULT_ACCOUNT_NUMBER_REQUIRED); 536 success &= false; 537 } 538 539 return success; 540 } 541 542 /** 543 * This method compares an old and new value, and determines if they've changed. If the old was null/blank, and the new is not, 544 * return true. If the old had a value, and the new is null/blank, return true. If both old and new had a value, and the values 545 * are different (excluding trailing or leading whitespaces, and excluding case changes), return true. If none of the above, 546 * return false. 547 * 548 * @param oldValue - Old value to test. 549 * @param newValue - New value to test. 550 * @return true or false, based on the algorithm described above. 551 */ 552 protected boolean fieldsHaveChanged(String oldValue, String newValue) { 553 554 // if old was null/blank and new is not 555 if (StringUtils.isBlank(oldValue) && StringUtils.isNotBlank(newValue)) { 556 return true; 557 } 558 559 // if old had a value, but new is null/blank 560 if (StringUtils.isNotBlank(oldValue) && StringUtils.isBlank(newValue)) { 561 return true; 562 } 563 564 // at this point, we know that we had a value before, and we have a 565 // value now, so we need to test whether this value has changed 566 if (oldValue != null && newValue != null) { 567 if (!oldValue.trim().equalsIgnoreCase(newValue.trim())) { 568 return true; 569 } 570 } 571 572 // if we've made it to here, then no changes have happened to the values 573 return false; 574 } 575 576 /** 577 * This method looks up in the ParameterService whether ther HRMS Org system is turned on. 578 * 579 * @return true or false depending on the app configuration 580 */ 581 protected boolean isHrmsOrgActivated() { 582 return SpringContext.getBean(ParameterService.class).getIndicatorParameter(Organization.class, KFSConstants.ChartApcParms.APC_HRMS_ACTIVE_KEY); 583 } 584 585 /** 586 * This method sets the convenience objects like newOrg and oldOrg, so you have short and easy handles to the new and old 587 * objects contained in the maintenance document. It also calls the BusinessObjectBase.refresh(), which will attempt to load all 588 * sub-objects from the DB by their primary keys, if available. 589 * 590 * @param document - the maintenanceDocument being evaluated 591 */ 592 public void setupConvenienceObjects() { 593 594 // setup oldAccount convenience objects, make sure all possible sub-objects are populated 595 oldOrg = (Organization) super.getOldBo(); 596 597 // setup newAccount convenience objects, make sure all possible sub-objects are populated 598 newOrg = (Organization) super.getNewBo(); 599 } 600 601 /** 602 * This method tests whether the specified user is part of the group that grants authorization to the Plant fields. 603 * 604 * @param user - the user to test 605 * @return true if user is part of the group, false otherwise 606 */ 607 protected boolean isPlantAuthorized(Person user) { 608 String principalId = user.getPrincipalId(); 609 String namespaceCode = KFSConstants.ParameterNamespaces.KNS; 610 String permissionTemplateName = KimConstants.PermissionTemplateNames.MODIFY_FIELD; 611 612 AttributeSet roleQualifiers = new AttributeSet(); 613 roleQualifiers.put(KfsKimAttributes.CHART_OF_ACCOUNTS_CODE, newOrg.getChartOfAccountsCode()); 614 615 AttributeSet permissionDetails = new AttributeSet(); 616 permissionDetails.put(KfsKimAttributes.COMPONENT_NAME, Organization.class.getSimpleName()); 617 permissionDetails.put(KfsKimAttributes.PROPERTY_NAME, KFSPropertyConstants.ORGANIZATION_PLANT_CHART_CODE); 618 619 IdentityManagementService identityManagementService = SpringContext.getBean(IdentityManagementService.class); 620 Boolean isAuthorized = identityManagementService.isAuthorizedByTemplateName(principalId, namespaceCode, permissionTemplateName, permissionDetails, roleQualifiers); 621 if (!isAuthorized) { 622 LOG.info("User '" + user.getPrincipalName() + "' has no access to the Plant Chart."); 623 return false; 624 } 625 626 permissionDetails.put(KfsKimAttributes.PROPERTY_NAME, KFSPropertyConstants.ORGANIZATION_PLANT_ACCOUNT_NUMBER); 627 isAuthorized = identityManagementService.isAuthorizedByTemplateName(principalId, namespaceCode, permissionTemplateName, permissionDetails, roleQualifiers); 628 if (!isAuthorized) { 629 LOG.info("User '" + user.getPrincipalName() + "' has no access to the Plant account."); 630 return false; 631 } 632 633 LOG.info("User '" + user.getPrincipalName() + "' has access to the Plant fields."); 634 return true; 635 } 636 }