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 }