Source Code Cross Referenced for AccountRule.java in  » ERP-CRM-Financial » Kuali-Financial-System » org » kuali » module » chart » rules » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » Kuali Financial System » org.kuali.module.chart.rules 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2005-2007 The Kuali Foundation.
0003:         * 
0004:         * Licensed under the Educational Community License, Version 1.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         * 
0008:         * http://www.opensource.org/licenses/ecl1.php
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:        package org.kuali.module.chart.rules;
0017:
0018:        import java.sql.Timestamp;
0019:        import java.util.Calendar;
0020:        import java.util.HashMap;
0021:        import java.util.List;
0022:        import java.util.Map;
0023:
0024:        import org.apache.commons.lang.StringUtils;
0025:        import org.apache.commons.lang.time.DateUtils;
0026:        import org.kuali.core.bo.user.UniversalUser;
0027:        import org.kuali.core.document.MaintenanceDocument;
0028:        import org.kuali.core.exceptions.UserNotFoundException;
0029:        import org.kuali.core.maintenance.rules.MaintenanceDocumentRuleBase;
0030:        import org.kuali.core.service.DataDictionaryService;
0031:        import org.kuali.core.service.DictionaryValidationService;
0032:        import org.kuali.core.service.KualiConfigurationService;
0033:        import org.kuali.core.util.ErrorMap;
0034:        import org.kuali.core.util.GlobalVariables;
0035:        import org.kuali.core.util.ObjectUtils;
0036:        import org.kuali.kfs.KFSConstants;
0037:        import org.kuali.kfs.KFSKeyConstants;
0038:        import org.kuali.kfs.KFSPropertyConstants;
0039:        import org.kuali.kfs.bo.Building;
0040:        import org.kuali.kfs.context.SpringContext;
0041:        import org.kuali.kfs.service.GeneralLedgerPendingEntryService;
0042:        import org.kuali.kfs.service.ParameterService;
0043:        import org.kuali.module.chart.bo.Account;
0044:        import org.kuali.module.chart.bo.AccountDescription;
0045:        import org.kuali.module.chart.bo.AccountGuideline;
0046:        import org.kuali.module.chart.bo.ChartUser;
0047:        import org.kuali.module.chart.bo.FundGroup;
0048:        import org.kuali.module.chart.bo.IcrAutomatedEntry;
0049:        import org.kuali.module.chart.bo.SubFundGroup;
0050:        import org.kuali.module.chart.service.AccountService;
0051:        import org.kuali.module.chart.service.SubFundGroupService;
0052:        import org.kuali.module.gl.service.BalanceService;
0053:        import org.kuali.module.labor.service.LaborLedgerPendingEntryService;
0054:
0055:        /**
0056:         * Business rule(s) applicable to AccountMaintenance documents.
0057:         */
0058:        public class AccountRule extends MaintenanceDocumentRuleBase {
0059:
0060:            protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0061:                    .getLogger(AccountRule.class);
0062:
0063:            private static final String ACCT_PREFIX_RESTRICTION = "PREFIXES";
0064:            private static final String ACCT_CAPITAL_SUBFUNDGROUP = "CAPITAL_SUB_FUND_GROUP";
0065:
0066:            private static final String GENERAL_FUND_CD = "GF";
0067:            private static final String RESTRICTED_FUND_CD = "RF";
0068:            private static final String ENDOWMENT_FUND_CD = "EN";
0069:            private static final String PLANT_FUND_CD = "PF";
0070:
0071:            private static final String RESTRICTED_CD_RESTRICTED = "R";
0072:            private static final String RESTRICTED_CD_UNRESTRICTED = "U";
0073:            private static final String RESTRICTED_CD_TEMPORARILY_RESTRICTED = "T";
0074:            private static final String SUB_FUND_GROUP_MEDICAL_PRACTICE_FUNDS = "MPRACT";
0075:            private static final String BUDGET_RECORDING_LEVEL_MIXED = "M";
0076:
0077:            private GeneralLedgerPendingEntryService generalLedgerPendingEntryService;
0078:            private LaborLedgerPendingEntryService laborLedgerPendingEntryService;
0079:            private BalanceService balanceService;
0080:            private AccountService accountService;
0081:
0082:            private Account oldAccount;
0083:            private Account newAccount;
0084:
0085:            public AccountRule() {
0086:
0087:                // Pseudo-inject some services.
0088:                //
0089:                // This approach is being used to make it simpler to convert the Rule classes
0090:                // to spring-managed with these services injected by Spring at some later date.
0091:                // When this happens, just remove these calls to the setters with
0092:                // SpringContext, and configure the bean defs for spring.
0093:                this .setGeneralLedgerPendingEntryService(SpringContext
0094:                        .getBean(GeneralLedgerPendingEntryService.class));
0095:                this .setBalanceService(SpringContext
0096:                        .getBean(BalanceService.class));
0097:                this .setAccountService(SpringContext
0098:                        .getBean(AccountService.class));
0099:                this .setLaborLedgerPendingEntryService(SpringContext
0100:                        .getBean(LaborLedgerPendingEntryService.class));
0101:            }
0102:
0103:            /**
0104:             * This method sets the convenience objects like newAccount and oldAccount, so you have short and easy handles to the new and
0105:             * old objects contained in the maintenance document. It also calls the BusinessObjectBase.refresh(), which will attempt to load
0106:             * all sub-objects from the DB by their primary keys, if available.
0107:             */
0108:            public void setupConvenienceObjects() {
0109:
0110:                // setup oldAccount convenience objects, make sure all possible sub-objects are populated
0111:                oldAccount = (Account) super .getOldBo();
0112:
0113:                // setup newAccount convenience objects, make sure all possible sub-objects are populated
0114:                newAccount = (Account) super .getNewBo();
0115:            }
0116:
0117:            /**
0118:             * This method calls the route rules but does not fail if any of them fail (this only happens on routing)
0119:             * 
0120:             * @see org.kuali.core.maintenance.rules.MaintenanceDocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.core.document.MaintenanceDocument)
0121:             */
0122:            protected boolean processCustomSaveDocumentBusinessRules(
0123:                    MaintenanceDocument document) {
0124:
0125:                LOG.info("processCustomSaveDocumentBusinessRules called");
0126:                // call the route rules to report all of the messages, but ignore the result
0127:                processCustomRouteDocumentBusinessRules(document);
0128:
0129:                // Save always succeeds, even if there are business rule failures
0130:                return true;
0131:            }
0132:
0133:            /**
0134:             * This method calls the following rules: checkAccountGuidelinesValidation checkEmptyValues checkGeneralRules checkCloseAccount
0135:             * checkContractsAndGrants checkExpirationDate checkFundGroup checkSubFundGroup checkFiscalOfficerIsValidKualiUser this rule
0136:             * will fail on routing
0137:             * 
0138:             * @see org.kuali.core.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.core.document.MaintenanceDocument)
0139:             */
0140:            protected boolean processCustomRouteDocumentBusinessRules(
0141:                    MaintenanceDocument document) {
0142:
0143:                LOG.info("processCustomRouteDocumentBusinessRules called");
0144:                setupConvenienceObjects();
0145:
0146:                // default to success
0147:                boolean success = true;
0148:
0149:                // validate the embedded AccountGuideline object
0150:                success &= checkAccountGuidelinesValidation(newAccount
0151:                        .getAccountGuideline());
0152:
0153:                success &= checkEmptyValues(document);
0154:                success &= checkGeneralRules(document);
0155:                success &= checkCloseAccount(document);
0156:                success &= checkContractsAndGrants(document);
0157:                success &= checkExpirationDate(document);
0158:                success &= checkFundGroup(document);
0159:                success &= checkSubFundGroup(document);
0160:                success &= checkFiscalOfficerIsValidKualiUser(newAccount
0161:                        .getAccountFiscalOfficerSystemIdentifier());
0162:
0163:                return success;
0164:            }
0165:
0166:            /**
0167:             * This method checks the basic rules for empty values in an account and associated objects with this account If guidelines are
0168:             * required for this Business Object it checks to make sure that it is filled out It also checks for partially filled out
0169:             * reference keys on the following: continuationAccount incomeStreamAccount endowmentIncomeAccount reportsToAccount
0170:             * contractControlAccount indirectCostRecoveryAcct
0171:             * 
0172:             * @param maintenanceDocument
0173:             * @return false if any of these are empty
0174:             */
0175:            protected boolean checkEmptyValues(
0176:                    MaintenanceDocument maintenanceDocument) {
0177:
0178:                LOG.info("checkEmptyValues called");
0179:
0180:                boolean success = true;
0181:
0182:                // guidelines are always required, except when the expirationDate is set, and its
0183:                // earlier than today
0184:                boolean guidelinesRequired = areGuidelinesRequired((Account) maintenanceDocument
0185:                        .getNewMaintainableObject().getBusinessObject());
0186:
0187:                // confirm that required guidelines are entered, if required
0188:                if (guidelinesRequired) {
0189:                    success &= checkEmptyBOField(
0190:                            "accountGuideline.accountExpenseGuidelineText",
0191:                            newAccount.getAccountGuideline()
0192:                                    .getAccountExpenseGuidelineText(),
0193:                            "Expense Guideline");
0194:                    success &= checkEmptyBOField(
0195:                            "accountGuideline.accountIncomeGuidelineText",
0196:                            newAccount.getAccountGuideline()
0197:                                    .getAccountIncomeGuidelineText(),
0198:                            "Income Guideline");
0199:                    success &= checkEmptyBOField(
0200:                            "accountGuideline.accountPurposeText", newAccount
0201:                                    .getAccountGuideline()
0202:                                    .getAccountPurposeText(), "Account Purpose");
0203:                }
0204:
0205:                // this set confirms that all fields which are grouped (ie, foreign keys of a reference
0206:                // object), must either be none filled out, or all filled out.
0207:                success &= checkForPartiallyFilledOutReferenceForeignKeys("continuationAccount");
0208:                success &= checkForPartiallyFilledOutReferenceForeignKeys("incomeStreamAccount");
0209:                success &= checkForPartiallyFilledOutReferenceForeignKeys("endowmentIncomeAccount");
0210:                success &= checkForPartiallyFilledOutReferenceForeignKeys("reportsToAccount");
0211:                success &= checkForPartiallyFilledOutReferenceForeignKeys("contractControlAccount");
0212:                success &= checkForPartiallyFilledOutReferenceForeignKeys("indirectCostRecoveryAcct");
0213:
0214:                return success;
0215:            }
0216:
0217:            /**
0218:             * This method validates that the account guidelines object is valid
0219:             * 
0220:             * @param accountGuideline
0221:             * @return true if account guideline is valid
0222:             */
0223:            protected boolean checkAccountGuidelinesValidation(
0224:                    AccountGuideline accountGuideline) {
0225:                ErrorMap map = GlobalVariables.getErrorMap();
0226:                int errorCount = map.getErrorCount();
0227:                GlobalVariables.getErrorMap().addToErrorPath(
0228:                        "document.newMaintainableObject.accountGuideline");
0229:                dictionaryValidationService.validateBusinessObject(
0230:                        accountGuideline, false);
0231:                GlobalVariables.getErrorMap().removeFromErrorPath(
0232:                        "document.newMaintainableObject.accountGuideline");
0233:                return map.getErrorCount() == errorCount;
0234:            }
0235:
0236:            /**
0237:             * This method determines whether the guidelines are required, based on business rules.
0238:             * 
0239:             * @param account - the populated Account bo to be evaluated
0240:             * @return true if guidelines are required, false otherwise
0241:             */
0242:            protected boolean areGuidelinesRequired(Account account) {
0243:
0244:                boolean result = true;
0245:
0246:                if (account.getAccountExpirationDate() != null) {
0247:                    Timestamp today = getDateTimeService()
0248:                            .getCurrentTimestamp();
0249:                    today.setTime(DateUtils.truncate(today,
0250:                            Calendar.DAY_OF_MONTH).getTime());
0251:                    if (account.getAccountExpirationDate().before(today)) {
0252:                        result = false;
0253:                    }
0254:                }
0255:                return result;
0256:            }
0257:
0258:            /**
0259:             * This method tests whether the accountNumber passed in is prefixed with an allowed prefix, or an illegal one. The illegal
0260:             * prefixes are passed in as an array of strings.
0261:             * 
0262:             * @param accountNumber - The Account Number to be tested.
0263:             * @param illegalValues - An Array of Strings of the unallowable prefixes.
0264:             * @return false if the accountNumber starts with any of the illegalPrefixes, true otherwise
0265:             */
0266:            protected boolean accountNumberStartsWithAllowedPrefix(
0267:                    String accountNumber, List<String> illegalValues) {
0268:                boolean result = true;
0269:                for (String illegalValue : illegalValues) {
0270:                    if (accountNumber.startsWith(illegalValue)) {
0271:                        result = false;
0272:                        putFieldError(
0273:                                "accountNumber",
0274:                                KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_NMBR_NOT_ALLOWED,
0275:                                new String[] { accountNumber, illegalValue });
0276:                    }
0277:                }
0278:                return result;
0279:            }
0280:
0281:            /**
0282:             * This method tests whether an account is being ReOpened by anyone except a system supervisor. Only system supervisors may
0283:             * reopen closed accounts.
0284:             * 
0285:             * @param document - populated document containing the old and new accounts
0286:             * @param user - the user who is trying to possibly reopen the account
0287:             * @return true if: document is an edit document, old was closed and new is open, and the user is not one of the System
0288:             *         Supervisors
0289:             */
0290:            protected boolean isNonSystemSupervisorEditingAClosedAccount(
0291:                    MaintenanceDocument document, UniversalUser user) {
0292:
0293:                boolean result = false;
0294:
0295:                if (document.isEdit()) {
0296:
0297:                    // get local references
0298:                    Account oldAccount = (Account) document
0299:                            .getOldMaintainableObject().getBusinessObject();
0300:                    Account newAccount = (Account) document
0301:                            .getNewMaintainableObject().getBusinessObject();
0302:
0303:                    // do the test
0304:                    if (oldAccount.isAccountClosedIndicator()
0305:                            && !user.isSupervisorUser()) {
0306:                        result = true;
0307:                    }
0308:                }
0309:                return result;
0310:            }
0311:
0312:            /**
0313:             * This method tests whether a given account has the T - Temporary value for Restricted Status Code, but does not have a
0314:             * Restricted Status Date, which is required when the code is T.
0315:             * 
0316:             * @param account
0317:             * @return true if the account is temporarily restricted but the status date is empty
0318:             */
0319:            protected boolean hasTemporaryRestrictedStatusCodeButNoRestrictedStatusDate(
0320:                    Account account) {
0321:
0322:                boolean result = false;
0323:
0324:                if (StringUtils.isNotBlank(account
0325:                        .getAccountRestrictedStatusCode())) {
0326:                    if (RESTRICTED_CD_TEMPORARILY_RESTRICTED
0327:                            .equalsIgnoreCase(account
0328:                                    .getAccountRestrictedStatusCode().trim())) {
0329:                        if (account.getAccountRestrictedStatusDate() == null) {
0330:                            result = true;
0331:                        }
0332:                    }
0333:                }
0334:                return result;
0335:            }
0336:
0337:            /**
0338:             * Checks whether the account restricted status code is the default from the sub fund group.
0339:             * 
0340:             * @param account
0341:             * @return true if the restricted status code is the same as the sub fund group's
0342:             */
0343:            protected boolean hasDefaultRestrictedStatusCode(Account account) {
0344:                boolean result = false;
0345:
0346:                if (StringUtils.isNotBlank(account
0347:                        .getAccountRestrictedStatusCode())) {
0348:                    result = account.getAccountRestrictedStatusCode().equals(
0349:                            account.getSubFundGroup()
0350:                                    .getAccountRestrictedStatusCode());
0351:                }
0352:
0353:                return result;
0354:            }
0355:
0356:            /**
0357:             * This method checks some of the general business rules associated with this document Calls the following rules:
0358:             * accountNumberStartsWithAllowedPrefix isNonSystemSupervisorEditingAClosedAccount
0359:             * hasTemporaryRestrictedStatusCodeButNoRestrictedStatusDate checkFringeBenefitAccountRule checkUserStatusAndType (on fiscal
0360:             * officer, supervisor and manager) ensures that the fiscal officer, supervisor and manager are not the same
0361:             * isContinuationAccountExpired
0362:             * 
0363:             * @param maintenanceDocument
0364:             * @return false on rules violation
0365:             */
0366:            protected boolean checkGeneralRules(
0367:                    MaintenanceDocument maintenanceDocument) {
0368:
0369:                LOG.info("checkGeneralRules called");
0370:                UniversalUser fiscalOfficer = newAccount
0371:                        .getAccountFiscalOfficerUser();
0372:                UniversalUser accountManager = newAccount
0373:                        .getAccountManagerUser();
0374:                UniversalUser accountSupervisor = newAccount
0375:                        .getAccountSupervisoryUser();
0376:
0377:                boolean success = true;
0378:
0379:                // Enforce institutionally specified restrictions on account number prefixes
0380:                // (e.g. the account number cannot begin with a 3 or with 00.)
0381:                // Only bother trying if there is an account string to test
0382:                if (!StringUtils.isBlank(newAccount.getAccountNumber())) {
0383:                    // test the number
0384:                    success &= accountNumberStartsWithAllowedPrefix(newAccount
0385:                            .getAccountNumber(), SpringContext.getBean(
0386:                            ParameterService.class).getParameterValues(
0387:                            Account.class, ACCT_PREFIX_RESTRICTION));
0388:                }
0389:
0390:                // only a FIS supervisor can reopen a closed account. (This is the central super user, not an account supervisor).
0391:                // we need to get the old maintanable doc here
0392:                if (isNonSystemSupervisorEditingAClosedAccount(
0393:                        maintenanceDocument, GlobalVariables.getUserSession()
0394:                                .getUniversalUser())) {
0395:                    success &= false;
0396:                    putFieldError(
0397:                            "accountClosedIndicator",
0398:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ONLY_SUPERVISORS_CAN_EDIT);
0399:                }
0400:
0401:                // when a restricted status code of 'T' (temporarily restricted) is selected, a restricted status
0402:                // date must be supplied.
0403:                if (hasTemporaryRestrictedStatusCodeButNoRestrictedStatusDate(newAccount)) {
0404:                    success &= false;
0405:                    putFieldError(
0406:                            "accountRestrictedStatusDate",
0407:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_RESTRICTED_STATUS_DT_REQ,
0408:                            newAccount.getAccountNumber());
0409:                }
0410:
0411:                // check FringeBenefit account rules
0412:                success &= checkFringeBenefitAccountRule(newAccount);
0413:
0414:                // the employee type for fiscal officer, account manager, and account supervisor must be 'P' – professional.
0415:                success &= checkUserStatusAndType(
0416:                        "accountFiscalOfficerUser.personUserIdentifier",
0417:                        fiscalOfficer);
0418:                success &= checkUserStatusAndType(
0419:                        "accountSupervisoryUser.personUserIdentifier",
0420:                        accountSupervisor);
0421:                success &= checkUserStatusAndType(
0422:                        "accountManagerUser.personUserIdentifier",
0423:                        accountManager);
0424:
0425:                // the supervisor cannot be the same as the fiscal officer or account manager.
0426:                if (isSupervisorSameAsFiscalOfficer(newAccount)) {
0427:                    success &= false;
0428:                    putFieldError(
0429:                            "accountsSupervisorySystemsIdentifier",
0430:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_SUPER_CANNOT_BE_FISCAL_OFFICER);
0431:                }
0432:                if (isSupervisorSameAsManager(newAccount)) {
0433:                    success &= false;
0434:                    putFieldError(
0435:                            "accountManagerSystemIdentifier",
0436:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_SUPER_CANNOT_BE_ACCT_MGR);
0437:                }
0438:
0439:                // disallow continuation account being expired
0440:                if (isContinuationAccountExpired(newAccount)) {
0441:                    success &= false;
0442:                    putFieldError(
0443:                            "continuationAccountNumber",
0444:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCOUNT_EXPIRED_CONTINUATION);
0445:                }
0446:
0447:                return success;
0448:            }
0449:
0450:            /**
0451:             * This method tests whether the continuation account entered (if any) has expired or not.
0452:             * 
0453:             * @param newAccount
0454:             * @return true if continuation account has expired
0455:             */
0456:            protected boolean isContinuationAccountExpired(Account newAccount) {
0457:
0458:                boolean result = false;
0459:
0460:                String chartCode = newAccount.getContinuationFinChrtOfAcctCd();
0461:                String accountNumber = newAccount
0462:                        .getContinuationAccountNumber();
0463:
0464:                // if either chartCode or accountNumber is not entered, then we
0465:                // cant continue, so exit
0466:                if (StringUtils.isBlank(chartCode)
0467:                        || StringUtils.isBlank(accountNumber)) {
0468:                    return result;
0469:                }
0470:
0471:                // attempt to retrieve the continuation account from the DB
0472:                Account continuation = null;
0473:                Map pkMap = new HashMap();
0474:                pkMap.put("chartOfAccountsCode", chartCode);
0475:                pkMap.put("accountNumber", accountNumber);
0476:                continuation = (Account) super .getBoService().findByPrimaryKey(
0477:                        Account.class, pkMap);
0478:
0479:                // if the object doesnt exist, then we cant continue, so exit
0480:                if (ObjectUtils.isNull(continuation)) {
0481:                    return result;
0482:                }
0483:
0484:                // at this point, we have a valid continuation account, so we just need to
0485:                // know whether its expired or not
0486:                result = continuation.isExpired();
0487:
0488:                return result;
0489:            }
0490:
0491:            /**
0492:             * the fringe benefit account (otherwise known as the reportsToAccount) is required if the fringe benefit code is set to N. The
0493:             * fringe benefit code of the account designated to accept the fringes must be Y.
0494:             * 
0495:             * @param newAccount
0496:             * @return
0497:             */
0498:            protected boolean checkFringeBenefitAccountRule(Account newAccount) {
0499:
0500:                boolean result = true;
0501:
0502:                // if this account is selected as a Fringe Benefit Account, then we have nothing
0503:                // to test, so exit
0504:                if (newAccount.isAccountsFringesBnftIndicator()) {
0505:                    return true;
0506:                }
0507:
0508:                // if fringe benefit is not selected ... continue processing
0509:
0510:                // fringe benefit account number is required
0511:                if (StringUtils.isBlank(newAccount.getReportsToAccountNumber())) {
0512:                    putFieldError(
0513:                            "reportsToAccountNumber",
0514:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_RPTS_TO_ACCT_REQUIRED_IF_FRINGEBENEFIT_FALSE);
0515:                    result &= false;
0516:                }
0517:
0518:                // fringe benefit chart of accounts code is required
0519:                if (StringUtils.isBlank(newAccount
0520:                        .getReportsToChartOfAccountsCode())) {
0521:                    putFieldError(
0522:                            "reportsToChartOfAccountsCode",
0523:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_RPTS_TO_ACCT_REQUIRED_IF_FRINGEBENEFIT_FALSE);
0524:                    result &= false;
0525:                }
0526:
0527:                // if either of the fringe benefit account fields are not present, then we're done
0528:                if (result == false) {
0529:                    return result;
0530:                }
0531:
0532:                // attempt to load the fringe benefit account
0533:                Account fringeBenefitAccount = accountService.getByPrimaryId(
0534:                        newAccount.getReportsToChartOfAccountsCode(),
0535:                        newAccount.getReportsToAccountNumber());
0536:
0537:                // fringe benefit account must exist
0538:                if (fringeBenefitAccount == null) {
0539:                    putFieldError("reportsToAccountNumber",
0540:                            KFSKeyConstants.ERROR_EXISTENCE, getFieldLabel(
0541:                                    Account.class, "reportsToAccountNumber"));
0542:                    return false;
0543:                }
0544:
0545:                // fringe benefit account must be active
0546:                if (fringeBenefitAccount.isAccountClosedIndicator()) {
0547:                    putFieldError("reportsToAccountNumber",
0548:                            KFSKeyConstants.ERROR_INACTIVE, getFieldLabel(
0549:                                    Account.class, "reportsToAccountNumber"));
0550:                    result &= false;
0551:                }
0552:
0553:                // make sure the fringe benefit account specified is set to fringe benefits = Y
0554:                if (!fringeBenefitAccount.isAccountsFringesBnftIndicator()) {
0555:                    putFieldError(
0556:                            "reportsToAccountNumber",
0557:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_RPTS_TO_ACCT_MUST_BE_FLAGGED_FRINGEBENEFIT,
0558:                            fringeBenefitAccount.getChartOfAccountsCode() + "-"
0559:                                    + fringeBenefitAccount.getAccountNumber());
0560:                    result &= false;
0561:                }
0562:
0563:                return result;
0564:            }
0565:
0566:            /**
0567:             * This method is a helper method for checking if the supervisor user is the same as the fiscal officer Calls
0568:             * {@link AccountRule#areTwoUsersTheSame(UniversalUser, UniversalUser)}
0569:             * 
0570:             * @param accountGlobals
0571:             * @return true if the two users are the same
0572:             */
0573:            protected boolean isSupervisorSameAsFiscalOfficer(Account account) {
0574:                return areTwoUsersTheSame(account.getAccountSupervisoryUser(),
0575:                        account.getAccountFiscalOfficerUser());
0576:            }
0577:
0578:            /**
0579:             * This method is a helper method for checking if the supervisor user is the same as the manager Calls
0580:             * {@link AccountRule#areTwoUsersTheSame(UniversalUser, UniversalUser)}
0581:             * 
0582:             * @param accountGlobals
0583:             * @return true if the two users are the same
0584:             */
0585:            protected boolean isSupervisorSameAsManager(Account account) {
0586:                return areTwoUsersTheSame(account.getAccountSupervisoryUser(),
0587:                        account.getAccountManagerUser());
0588:            }
0589:
0590:            /**
0591:             * This method checks to see if two users are the same BusinessObject using their identifiers
0592:             * 
0593:             * @param user1
0594:             * @param user2
0595:             * @return true if these two users are the same
0596:             */
0597:            protected boolean areTwoUsersTheSame(UniversalUser user1,
0598:                    UniversalUser user2) {
0599:                if (ObjectUtils.isNull(user1)) {
0600:                    return false;
0601:                }
0602:                if (ObjectUtils.isNull(user2)) {
0603:                    return false;
0604:                }
0605:                if (ObjectUtils.equalByKeys(user1, user2)) {
0606:                    return true;
0607:                } else {
0608:                    return false;
0609:                }
0610:            }
0611:
0612:            /**
0613:             * This method checks to see if the user passed in is of the type requested. If so, it returns true. If not, it returns false,
0614:             * and adds an error to the GlobalErrors.
0615:             * 
0616:             * @param propertyName - property to attach error to
0617:             * @param user - UniversalUser to be tested
0618:             * @return true if user is of the requested employee type, false if not, true if the user object is null
0619:             */
0620:            protected boolean checkUserStatusAndType(String propertyName,
0621:                    UniversalUser user) {
0622:
0623:                boolean success = true;
0624:
0625:                // if the user isn't populated, exit with success
0626:                // the actual existence check is performed in the general rules so not testing here
0627:                if (ObjectUtils.isNull(user)) {
0628:                    return success;
0629:                }
0630:
0631:                // user must be of the allowable statuses (A - Active)
0632:                if (!SpringContext
0633:                        .getBean(ParameterService.class)
0634:                        .getParameterEvaluator(
0635:                                Account.class,
0636:                                KFSConstants.ChartApcParms.ACCOUNT_USER_EMP_STATUSES,
0637:                                user.getEmployeeStatusCode())
0638:                        .evaluationSucceeds()) {
0639:                    success &= false;
0640:                    putFieldError(
0641:                            propertyName,
0642:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACTIVE_REQD_FOR_EMPLOYEE,
0643:                            getDdService().getAttributeLabel(Account.class,
0644:                                    propertyName));
0645:                }
0646:
0647:                // user must be of the allowable types (P - Professional)
0648:                if (!SpringContext
0649:                        .getBean(ParameterService.class)
0650:                        .getParameterEvaluator(
0651:                                Account.class,
0652:                                KFSConstants.ChartApcParms.ACCOUNT_USER_EMP_TYPES,
0653:                                user.getEmployeeTypeCode())
0654:                        .evaluationSucceeds()) {
0655:                    success &= false;
0656:                    putFieldError(
0657:                            propertyName,
0658:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_PRO_TYPE_REQD_FOR_EMPLOYEE,
0659:                            getDdService().getAttributeLabel(Account.class,
0660:                                    propertyName));
0661:                }
0662:
0663:                return success;
0664:            }
0665:
0666:            /**
0667:             * This method checks to see if the user is trying to close the account and if so if any rules are being violated Calls the
0668:             * additional rule checkAccountExpirationDateValidTodayOrEarlier
0669:             * 
0670:             * @param maintenanceDocument
0671:             * @return false on rules violation
0672:             */
0673:            protected boolean checkCloseAccount(
0674:                    MaintenanceDocument maintenanceDocument) {
0675:
0676:                LOG.info("checkCloseAccount called");
0677:
0678:                boolean success = true;
0679:                boolean isBeingClosed = false;
0680:
0681:                // if the account isnt being closed, then dont bother processing the rest of
0682:                // the method
0683:                if (!oldAccount.isAccountClosedIndicator()
0684:                        && newAccount.isAccountClosedIndicator()) {
0685:                    isBeingClosed = true;
0686:                }
0687:
0688:                if (!isBeingClosed) {
0689:                    return true;
0690:                }
0691:
0692:                // on an account being closed, the expiration date must be
0693:                success &= checkAccountExpirationDateValidTodayOrEarlier(newAccount);
0694:
0695:                // when closing an account, a continuation account is required
0696:                if (StringUtils.isBlank(newAccount
0697:                        .getContinuationAccountNumber())) {
0698:                    putFieldError(
0699:                            "continuationAccountNumber",
0700:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_CLOSE_CONTINUATION_ACCT_REQD);
0701:                    success &= false;
0702:                }
0703:                if (StringUtils.isBlank(newAccount
0704:                        .getContinuationFinChrtOfAcctCd())) {
0705:                    putFieldError(
0706:                            "continuationFinChrtOfAcctCd",
0707:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_CLOSE_CONTINUATION_ACCT_REQD);
0708:                    success &= false;
0709:                }
0710:
0711:                // must have no pending ledger entries
0712:                if (generalLedgerPendingEntryService
0713:                        .hasPendingGeneralLedgerEntry(newAccount)) {
0714:                    putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCOUNT_CLOSED_PENDING_LEDGER_ENTRIES);
0715:                    success &= false;
0716:                }
0717:
0718:                // beginning balance must be loaded in order to close account
0719:                if (!balanceService.beginningBalanceLoaded(newAccount)) {
0720:                    putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCOUNT_CLOSED_NO_LOADED_BEGINNING_BALANCE);
0721:                    success &= false;
0722:                }
0723:
0724:                // must have no base budget, must have no open encumbrances, must have no asset, liability or fund balance balances other
0725:                // than object code 9899
0726:                // (9899 is fund balance for us), and the process of closing income and expense into 9899 must take the 9899 balance to
0727:                // zero.
0728:                if (balanceService
0729:                        .hasAssetLiabilityFundBalanceBalances(newAccount)) {
0730:                    putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCOUNT_CLOSED_NO_FUND_BALANCES);
0731:                    success &= false;
0732:                }
0733:
0734:                // We must not have any pending labor ledger entries
0735:                if (laborLedgerPendingEntryService
0736:                        .hasPendingLaborLedgerEntry(newAccount)) {
0737:                    putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCOUNT_CLOSED_PENDING_LABOR_LEDGER_ENTRIES);
0738:                    success &= false;
0739:                }
0740:
0741:                return success;
0742:            }
0743:
0744:            /**
0745:             * This method checsk to see if the account expiration date is today's date or earlier
0746:             * 
0747:             * @param newAccount
0748:             * @return fails if the expiration date is null or after today's date
0749:             */
0750:            protected boolean checkAccountExpirationDateValidTodayOrEarlier(
0751:                    Account newAccount) {
0752:
0753:                // get today's date, with no time component
0754:                Timestamp todaysDate = getDateTimeService()
0755:                        .getCurrentTimestamp();
0756:                todaysDate.setTime(DateUtils.truncate(todaysDate,
0757:                        Calendar.DAY_OF_MONTH).getTime());
0758:                // TODO: convert this to using Wes' kuali DateUtils once we're using Date's instead of Timestamp
0759:
0760:                // get the expiration date, if any
0761:                Timestamp expirationDate = newAccount
0762:                        .getAccountExpirationDate();
0763:                if (ObjectUtils.isNull(expirationDate)) {
0764:                    putFieldError(
0765:                            "accountExpirationDate",
0766:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_CANNOT_BE_CLOSED_EXP_DATE_INVALID);
0767:                    return false;
0768:                }
0769:
0770:                // when closing an account, the account expiration date must be the current date or earlier
0771:                expirationDate.setTime(DateUtils.truncate(expirationDate,
0772:                        Calendar.DAY_OF_MONTH).getTime());
0773:                if (expirationDate.after(todaysDate)) {
0774:                    putFieldError(
0775:                            "accountExpirationDate",
0776:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_CANNOT_BE_CLOSED_EXP_DATE_INVALID);
0777:                    return false;
0778:                }
0779:
0780:                return true;
0781:            }
0782:
0783:            /**
0784:             * This method checks to see if any Contracts and Grants business rules were violated Calls the following sub-rules:
0785:             * checkCgRequiredFields checkCgIncomeStreamRequired
0786:             * 
0787:             * @param maintenanceDocument
0788:             * @return false on rules violation
0789:             */
0790:            protected boolean checkContractsAndGrants(
0791:                    MaintenanceDocument maintenanceDocument) {
0792:
0793:                LOG.info("checkContractsAndGrants called");
0794:
0795:                boolean success = true;
0796:
0797:                // Certain C&G fields are required if the Account belongs to the CG Fund Group
0798:                success &= checkCgRequiredFields(newAccount);
0799:
0800:                // Income Stream account is required if this account is CG fund group,
0801:                // or GF (general fund) fund group (with some exceptions)
0802:                success &= checkCgIncomeStreamRequired(newAccount);
0803:
0804:                return success;
0805:            }
0806:
0807:            /**
0808:             * This method checks to see if the income stream account is required
0809:             * 
0810:             * @param newAccount
0811:             * @return fails if it is required and not entered, or not valid
0812:             */
0813:            protected boolean checkCgIncomeStreamRequired(Account newAccount) {
0814:
0815:                boolean result = true;
0816:                boolean required = false;
0817:
0818:                // if the subFundGroup object is null, we cant test, so exit
0819:                if (ObjectUtils.isNull(newAccount.getSubFundGroup())) {
0820:                    return result;
0821:                }
0822:
0823:                // retrieve the subfundcode and fundgroupcode
0824:                String subFundGroupCode = newAccount.getSubFundGroupCode()
0825:                        .trim();
0826:                String fundGroupCode = newAccount.getSubFundGroup()
0827:                        .getFundGroupCode().trim();
0828:
0829:                String requiredByValue = "";
0830:                String requiredByLabel = "";
0831:
0832:                // if this is a CG fund group, then its required
0833:                if (SpringContext.getBean(SubFundGroupService.class)
0834:                        .isForContractsAndGrants(newAccount.getSubFundGroup())) {
0835:                    required = true;
0836:                    requiredByLabel = SpringContext.getBean(
0837:                            SubFundGroupService.class)
0838:                            .getContractsAndGrantsDenotingAttributeLabel();
0839:                    requiredByValue = SpringContext.getBean(
0840:                            SubFundGroupService.class)
0841:                            .getContractsAndGrantsDenotingValue();
0842:                }
0843:
0844:                // if this is a general fund group, then its required
0845:                else if (GENERAL_FUND_CD.equalsIgnoreCase(fundGroupCode)) {
0846:                    // unless its part of the MPRACT subfundgroup
0847:                    if (!SUB_FUND_GROUP_MEDICAL_PRACTICE_FUNDS
0848:                            .equalsIgnoreCase(subFundGroupCode)) {
0849:                        required = true;
0850:                        requiredByLabel = getDdService().getAttributeLabel(
0851:                                FundGroup.class,
0852:                                KFSConstants.FUND_GROUP_CODE_PROPERTY_NAME);
0853:                        requiredByValue = GENERAL_FUND_CD;
0854:                    }
0855:                }
0856:
0857:                // if the income stream account is not required, then we're done
0858:                if (!required) {
0859:                    return result;
0860:                }
0861:
0862:                DictionaryValidationService dvService = super 
0863:                        .getDictionaryValidationService();
0864:
0865:                // make sure both coaCode and accountNumber are filled out
0866:                boolean incomeStreamAccountIsValid = true;
0867:                if (!checkEmptyValue(newAccount
0868:                        .getIncomeStreamFinancialCoaCode())) {
0869:                    putFieldError(
0870:                            "incomeStreamFinancialCoaCode",
0871:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_INCOME_STREAM_ACCT_COA_CANNOT_BE_EMPTY,
0872:                            new String[] { requiredByLabel, requiredByValue });
0873:                    incomeStreamAccountIsValid = false;
0874:                }
0875:                if (!checkEmptyValue(newAccount.getIncomeStreamAccountNumber())) {
0876:                    putFieldError(
0877:                            "incomeStreamAccountNumber",
0878:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_INCOME_STREAM_ACCT_NBR_CANNOT_BE_EMPTY,
0879:                            new String[] { requiredByLabel, requiredByValue });
0880:                    incomeStreamAccountIsValid = false;
0881:                } else {
0882:                    // validate that the income stream account exists
0883:                    if (null != newAccount.getIncomeStreamAccountNumber()
0884:                            && null != newAccount
0885:                                    .getIncomeStreamFinancialCoaCode()) {
0886:                        if (newAccount.getIncomeStreamAccountNumber().equals(
0887:                                newAccount.getAccountNumber())
0888:                                && newAccount
0889:                                        .getIncomeStreamFinancialCoaCode()
0890:                                        .equals(
0891:                                                newAccount
0892:                                                        .getChartOfAccountsCode())) {
0893:                            // income stream account is valid
0894:                        } else if (!dvService.validateReferenceExists(
0895:                                newAccount, "incomeStreamAccount")) {
0896:                            putFieldError(
0897:                                    "incomeStreamAccountNumber",
0898:                                    KFSKeyConstants.ERROR_EXISTENCE,
0899:                                    "Income Stream Account: "
0900:                                            + newAccount
0901:                                                    .getIncomeStreamFinancialCoaCode()
0902:                                            + "-"
0903:                                            + newAccount
0904:                                                    .getIncomeStreamAccountNumber());
0905:                            incomeStreamAccountIsValid = false;
0906:                        }
0907:                    }
0908:                }
0909:
0910:                if (incomeStreamAccountIsValid) {
0911:                    result = true;
0912:                } else {
0913:                    result = null != newAccount.getAccountNumber()
0914:                            && null != newAccount
0915:                                    .getIncomeStreamAccountNumber();
0916:                    if (result) {
0917:                        result &= newAccount.getAccountNumber().equals(
0918:                                newAccount.getIncomeStreamAccountNumber());
0919:                        result &= newAccount.getChartOfAccountsCode().equals(
0920:                                newAccount.getIncomeStreamFinancialCoaCode());
0921:                    }
0922:                }
0923:
0924:                return result;
0925:            }
0926:
0927:            /**
0928:             * This method checks to make sure that if the contracts and grants fields are required they are entered correctly
0929:             * 
0930:             * @param newAccount
0931:             * @return
0932:             */
0933:            protected boolean checkCgRequiredFields(Account newAccount) {
0934:
0935:                boolean result = true;
0936:
0937:                // Certain C&G fields are required if the Account belongs to the CG Fund Group
0938:                if (ObjectUtils.isNotNull(newAccount.getSubFundGroup())) {
0939:                    if (SpringContext.getBean(SubFundGroupService.class)
0940:                            .isForContractsAndGrants(
0941:                                    newAccount.getSubFundGroup())) {
0942:                        result &= checkEmptyBOField(
0943:                                "acctIndirectCostRcvyTypeCd",
0944:                                newAccount.getAcctIndirectCostRcvyTypeCd(),
0945:                                replaceTokens(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_TYPE_CODE_CANNOT_BE_EMPTY));
0946:                        result &= checkEmptyBOField(
0947:                                "financialIcrSeriesIdentifier",
0948:                                newAccount.getFinancialIcrSeriesIdentifier(),
0949:                                replaceTokens(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_SERIES_IDENTIFIER_CANNOT_BE_EMPTY));
0950:
0951:                        // Validation for financialIcrSeriesIdentifier
0952:                        if (checkEmptyBOField(
0953:                                "financialIcrSeriesIdentifier",
0954:                                newAccount.getFinancialIcrSeriesIdentifier(),
0955:                                replaceTokens(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_SERIES_IDENTIFIER_CANNOT_BE_EMPTY))) {
0956:                            Map pkMap = new HashMap();
0957:                            pkMap.put("financialIcrSeriesIdentifier",
0958:                                    newAccount
0959:                                            .getFinancialIcrSeriesIdentifier());
0960:                            if (getBoService().countMatching(
0961:                                    IcrAutomatedEntry.class, pkMap) == 0) {
0962:                                putFieldError("financialIcrSeriesIdentifier",
0963:                                        KFSKeyConstants.ERROR_EXISTENCE,
0964:                                        "financialIcrSeriesIdentifier");
0965:                                result &= false;
0966:                            }
0967:                        }
0968:
0969:                        result &= checkEmptyBOField(
0970:                                "indirectCostRcvyFinCoaCode",
0971:                                newAccount.getIndirectCostRcvyFinCoaCode(),
0972:                                replaceTokens(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_CHART_CODE_CANNOT_BE_EMPTY));
0973:                        result &= checkEmptyBOField(
0974:                                "indirectCostRecoveryAcctNbr",
0975:                                newAccount.getIndirectCostRecoveryAcctNbr(),
0976:                                replaceTokens(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ICR_ACCOUNT_CANNOT_BE_EMPTY));
0977:                        result &= checkContractControlAccountNumberRequired(newAccount);
0978:                    } else {
0979:                        // this is not a C&G fund group. So users should not fill in any fields in the C&G tab.
0980:                        result &= checkCGFieldNotFilledIn(newAccount,
0981:                                "acctIndirectCostRcvyTypeCd");
0982:                        result &= checkCGFieldNotFilledIn(newAccount,
0983:                                "financialIcrSeriesIdentifier");
0984:                        result &= checkCGFieldNotFilledIn(newAccount,
0985:                                "indirectCostRcvyFinCoaCode");
0986:                        result &= checkCGFieldNotFilledIn(newAccount,
0987:                                "indirectCostRecoveryAcctNbr");
0988:                    }
0989:                }
0990:                return result;
0991:            }
0992:
0993:            /**
0994:             * This method is a helper method that replaces error tokens with values for contracts and grants labels
0995:             * 
0996:             * @param errorConstant
0997:             * @return error string that has had tokens "{0}" and "{1}" replaced
0998:             */
0999:            private String replaceTokens(String errorConstant) {
1000:                String cngLabel = SpringContext.getBean(
1001:                        SubFundGroupService.class)
1002:                        .getContractsAndGrantsDenotingAttributeLabel();
1003:                String cngValue = SpringContext.getBean(
1004:                        SubFundGroupService.class)
1005:                        .getContractsAndGrantsDenotingValue();
1006:                String result = SpringContext.getBean(
1007:                        KualiConfigurationService.class).getPropertyString(
1008:                        errorConstant);
1009:                result = StringUtils.replace(result, "{0}", cngLabel);
1010:                result = StringUtils.replace(result, "{1}", cngValue);
1011:                return result;
1012:            }
1013:
1014:            /**
1015:             * This method checks to make sure that if the contract control account exists it is the same as the Account that we are working
1016:             * on
1017:             * 
1018:             * @param newAccount
1019:             * @return false if the contract control account is entered and is not the same as the account we are maintaining
1020:             */
1021:            protected boolean checkContractControlAccountNumberRequired(
1022:                    Account newAccount) {
1023:
1024:                boolean result = true;
1025:
1026:                // Contract Control account must either exist or be the same as account being maintained
1027:
1028:                if (ObjectUtils.isNull(newAccount
1029:                        .getContractControlFinCoaCode())) {
1030:                    return result;
1031:                }
1032:                if (ObjectUtils.isNull(newAccount
1033:                        .getContractControlAccountNumber())) {
1034:                    return result;
1035:                }
1036:                if ((newAccount.getContractControlFinCoaCode()
1037:                        .equals(newAccount.getChartOfAccountsCode()))
1038:                        && (newAccount.getContractControlAccountNumber()
1039:                                .equals(newAccount.getAccountNumber()))) {
1040:                    return result;
1041:                }
1042:
1043:                // do an existence/active test
1044:                DictionaryValidationService dvService = super 
1045:                        .getDictionaryValidationService();
1046:                boolean referenceExists = dvService.validateReferenceExists(
1047:                        newAccount, "contractControlAccount");
1048:                if (!referenceExists) {
1049:                    putFieldError("contractControlAccountNumber",
1050:                            KFSKeyConstants.ERROR_EXISTENCE,
1051:                            "Contract Control Account: "
1052:                                    + newAccount.getContractControlFinCoaCode()
1053:                                    + "-"
1054:                                    + newAccount
1055:                                            .getContractControlAccountNumber());
1056:                    result &= false;
1057:                }
1058:
1059:                return result;
1060:            }
1061:
1062:            /**
1063:             * This method checks to see if any expiration date field rules were violated
1064:             * 
1065:             * @param maintenanceDocument
1066:             * @return false on rules violation
1067:             */
1068:            protected boolean checkExpirationDate(
1069:                    MaintenanceDocument maintenanceDocument) {
1070:
1071:                LOG.info("checkExpirationDate called");
1072:
1073:                boolean success = true;
1074:
1075:                Timestamp oldExpDate = oldAccount.getAccountExpirationDate();
1076:                Timestamp newExpDate = newAccount.getAccountExpirationDate();
1077:                Timestamp today = getDateTimeService().getCurrentTimestamp();
1078:                today.setTime(DateUtils.truncate(today, Calendar.DAY_OF_MONTH)
1079:                        .getTime()); // remove any time components
1080:
1081:                // When updating an account expiration date, the date must be today or later
1082:                // Only run this test if this maint doc
1083:                // is an edit doc
1084:                if (isUpdatedExpirationDateInvalid(maintenanceDocument)) {
1085:                    putFieldError(
1086:                            "accountExpirationDate",
1087:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_EXP_DATE_TODAY_LATER);
1088:                    success &= false;
1089:                }
1090:
1091:                // a continuation account is required if the expiration date is completed.
1092:                if (ObjectUtils.isNotNull(newExpDate)) {
1093:                    if (StringUtils.isBlank(newAccount
1094:                            .getContinuationAccountNumber())) {
1095:                        putFieldError(
1096:                                "continuationAccountNumber",
1097:                                KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_CONTINUATION_ACCT_REQD_IF_EXP_DATE_COMPLETED);
1098:                    }
1099:                    if (StringUtils.isBlank(newAccount
1100:                            .getContinuationFinChrtOfAcctCd())) {
1101:                        putFieldError(
1102:                                "continuationFinChrtOfAcctCd",
1103:                                KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_CONTINUATION_FINCODE_REQD_IF_EXP_DATE_COMPLETED);
1104:                        // putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_CONTINUATION_ACCT_REQD_IF_EXP_DATE_COMPLETED);
1105:                        success &= false;
1106:                    }
1107:                }
1108:
1109:                // If creating a new account if acct_expiration_dt is set then
1110:                // the acct_expiration_dt must be changed to a date that is today or later
1111:                if (maintenanceDocument.isNew()
1112:                        && ObjectUtils.isNotNull(newExpDate)) {
1113:                    if (!newExpDate.after(today) && !newExpDate.equals(today)) {
1114:                        putFieldError(
1115:                                "accountExpirationDate",
1116:                                KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_EXP_DATE_TODAY_LATER);
1117:                        // putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_EXP_DATE_TODAY_LATER);
1118:                        success &= false;
1119:                    }
1120:                }
1121:
1122:                // acct_expiration_dt can not be before acct_effect_dt
1123:                Timestamp effectiveDate = newAccount.getAccountEffectiveDate();
1124:                if (ObjectUtils.isNotNull(effectiveDate)
1125:                        && ObjectUtils.isNotNull(newExpDate)) {
1126:                    if (newExpDate.before(effectiveDate)) {
1127:                        putFieldError(
1128:                                "accountExpirationDate",
1129:                                KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_EXP_DATE_CANNOT_BE_BEFORE_EFFECTIVE_DATE);
1130:                        // putGlobalError(KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_EXP_DATE_CANNOT_BE_BEFORE_EFFECTIVE_DATE);
1131:                        success &= false;
1132:                    }
1133:                }
1134:
1135:                return success;
1136:            }
1137:
1138:            /**
1139:             * This method checks to see if the new expiration date is different from the old expiration and if it has if it is invalid
1140:             * 
1141:             * @param maintDoc
1142:             * @return true if expiration date has changed and is invalid
1143:             */
1144:            protected boolean isUpdatedExpirationDateInvalid(
1145:                    MaintenanceDocument maintDoc) {
1146:
1147:                // if this isnt an Edit document, we're not interested
1148:                if (!maintDoc.isEdit()) {
1149:                    return false;
1150:                }
1151:
1152:                Timestamp oldExpDate = oldAccount.getAccountExpirationDate();
1153:                Timestamp newExpDate = newAccount.getAccountExpirationDate();
1154:                Timestamp today = getDateTimeService().getCurrentTimestamp();
1155:                today.setTime(DateUtils.truncate(today, Calendar.DAY_OF_MONTH)
1156:                        .getTime()); // remove any time components
1157:
1158:                // When updating an account expiration date, the date must be today or later
1159:                // Only run this test if this maint doc
1160:                // is an edit doc
1161:                boolean expDateHasChanged = false;
1162:
1163:                // if the old version of the account had no expiration date, and the new
1164:                // one has a date
1165:                if (ObjectUtils.isNull(oldExpDate)
1166:                        && ObjectUtils.isNotNull(newExpDate)) {
1167:                    expDateHasChanged = true;
1168:                }
1169:
1170:                // if there was an old and a new expDate, but they're different
1171:                else if (ObjectUtils.isNotNull(oldExpDate)
1172:                        && ObjectUtils.isNotNull(newExpDate)) {
1173:                    if (!oldExpDate.equals(newExpDate)) {
1174:                        expDateHasChanged = true;
1175:                    }
1176:                }
1177:
1178:                // if the expiration date hasnt changed, we're not interested
1179:                if (!expDateHasChanged) {
1180:                    return false;
1181:                }
1182:
1183:                // make a shortcut to the newAccount
1184:                Account newAccount = (Account) maintDoc
1185:                        .getNewMaintainableObject().getBusinessObject();
1186:
1187:                // expirationDate must be today or later than today (cannot be before today)
1188:                if (newExpDate.equals(today) || newExpDate.after(today)) {
1189:                    return false;
1190:                } else
1191:                    return true;
1192:            }
1193:
1194:            /**
1195:             * This method checks to see if any Fund Group rules were violated Specifically: if we are dealing with a "GF" (General Fund) we
1196:             * cannot have an account with a budget recording level of "M" (Mixed)
1197:             * 
1198:             * @param maintenanceDocument
1199:             * @return false on rules violation
1200:             */
1201:            protected boolean checkFundGroup(
1202:                    MaintenanceDocument maintenanceDocument) {
1203:
1204:                LOG.info("checkFundGroup called");
1205:
1206:                boolean success = true;
1207:                SubFundGroup subFundGroup = newAccount.getSubFundGroup();
1208:
1209:                if (ObjectUtils.isNotNull(subFundGroup)) {
1210:
1211:                    // get values for fundGroupCode and restrictedStatusCode
1212:                    String fundGroupCode = "";
1213:                    String restrictedStatusCode = "";
1214:                    if (StringUtils.isNotBlank(subFundGroup.getFundGroupCode())) {
1215:                        fundGroupCode = subFundGroup.getFundGroupCode().trim();
1216:                    }
1217:                    if (StringUtils.isNotBlank(newAccount
1218:                            .getAccountRestrictedStatusCode())) {
1219:                        restrictedStatusCode = newAccount
1220:                                .getAccountRestrictedStatusCode().trim();
1221:                    }
1222:
1223:                    // an account in the general fund fund group cannot have a budget recording level of mixed.
1224:                    if (fundGroupCode.equalsIgnoreCase(GENERAL_FUND_CD)) {
1225:                        String budgetRecordingLevelCode = newAccount
1226:                                .getBudgetRecordingLevelCode();
1227:                        if (StringUtils.isNotEmpty(budgetRecordingLevelCode)) {
1228:                            if (budgetRecordingLevelCode
1229:                                    .equalsIgnoreCase(BUDGET_RECORDING_LEVEL_MIXED)) {
1230:                                putFieldError(
1231:                                        "budgetRecordingLevelCode",
1232:                                        KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_ACCT_GF_BUDGET_RECORD_LVL_MIXED);
1233:                                success &= false;
1234:                            }
1235:                        }
1236:                    }
1237:                }
1238:
1239:                return success;
1240:            }
1241:
1242:            /**
1243:             * This method insures the fiscal officer is a valid Kuali User
1244:             * 
1245:             * @param fiscalOfficerUserId
1246:             * @return true if they are a valid Kuali user
1247:             */
1248:            protected boolean checkFiscalOfficerIsValidKualiUser(
1249:                    String fiscalOfficerUserId) {
1250:                boolean result = true;
1251:                try {
1252:                    UniversalUser fiscalOfficer = getUniversalUserService()
1253:                            .getUniversalUser(fiscalOfficerUserId);
1254:                    if (fiscalOfficer != null
1255:                            && !fiscalOfficer
1256:                                    .isActiveForModule(ChartUser.MODULE_ID)) {
1257:                        result = false;
1258:                        putFieldError(
1259:                                "accountFiscalOfficerUser.personUserIdentifier",
1260:                                KFSKeyConstants.ERROR_DOCUMENT_ACCOUNT_FISCAL_OFFICER_MUST_BE_KUALI_USER);
1261:                    }
1262:                } catch (UserNotFoundException e) {
1263:                    result = false;
1264:                }
1265:
1266:                return result;
1267:            }
1268:
1269:            /**
1270:             * This method checks to see if any SubFund Group rules were violated Specifically: if SubFundGroup is empty or not "PFCMR" we
1271:             * cannot have a campus code or building code if SubFundGroup is "PFCMR" then campus code and building code "must" be entered
1272:             * and be valid codes
1273:             * 
1274:             * @param maintenanceDocument
1275:             * @return false on rules violation
1276:             */
1277:            protected boolean checkSubFundGroup(
1278:                    MaintenanceDocument maintenanceDocument) {
1279:
1280:                LOG.info("checkSubFundGroup called");
1281:
1282:                boolean success = true;
1283:
1284:                String subFundGroupCode = newAccount.getSubFundGroupCode();
1285:
1286:                if (newAccount.getAccountDescription() != null) {
1287:
1288:                    String campusCode = newAccount.getAccountDescription()
1289:                            .getCampusCode();
1290:                    String buildingCode = newAccount.getAccountDescription()
1291:                            .getBuildingCode();
1292:
1293:                    // check if sub fund group code is blank
1294:                    if (StringUtils.isBlank(subFundGroupCode)) {
1295:
1296:                        // check if campus code and building code are NOT blank
1297:                        if (!StringUtils.isBlank(campusCode)
1298:                                || !StringUtils.isBlank(buildingCode)) {
1299:
1300:                            // if sub_fund_grp_cd is blank, campus code should NOT be entered
1301:                            if (!StringUtils.isBlank(campusCode)) {
1302:                                putFieldError(
1303:                                        "accountDescription.campusCode",
1304:                                        KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_BLANK_SUBFUNDGROUP_WITH_CAMPUS_CD_FOR_BLDG,
1305:                                        subFundGroupCode);
1306:                                success &= false;
1307:                            }
1308:
1309:                            // if sub_fund_grp_cd is blank, then bldg_cd should NOT be entered
1310:                            if (!StringUtils.isBlank(buildingCode)) {
1311:                                putFieldError(
1312:                                        "accountDescription.buildingCode",
1313:                                        KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_BLANK_SUBFUNDGROUP_WITH_BUILDING_CD,
1314:                                        subFundGroupCode);
1315:                                success &= false;
1316:                            }
1317:
1318:                        } else {
1319:
1320:                            // if all sub fund group, campus code, building code are all blank return true
1321:                            return success;
1322:                        }
1323:
1324:                    } else if (!StringUtils.isBlank(subFundGroupCode)
1325:                            && !ObjectUtils
1326:                                    .isNull(newAccount.getSubFundGroup())) {
1327:
1328:                        // Attempt to get the right SubFundGroup code to check the following logic with. If the value isn't available, go
1329:                        // ahead
1330:                        // and die, as this indicates a misconfigured app, and important business rules wont be implemented without it.
1331:                        String capitalSubFundGroup = SpringContext.getBean(
1332:                                ParameterService.class).getParameterValue(
1333:                                Account.class, ACCT_CAPITAL_SUBFUNDGROUP);
1334:
1335:                        if (capitalSubFundGroup
1336:                                .equalsIgnoreCase(subFundGroupCode.trim())) {
1337:
1338:                            // if sub_fund_grp_cd is 'PFCMR' then campus_cd must be entered
1339:                            if (StringUtils.isBlank(campusCode)) {
1340:                                putFieldError(
1341:                                        "accountDescription.campusCode",
1342:                                        KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_CAMS_SUBFUNDGROUP_WITH_MISSING_CAMPUS_CD_FOR_BLDG);
1343:                                success &= false;
1344:                            }
1345:
1346:                            // if sub_fund_grp_cd is 'PFCMR' then bldg_cd must be entered
1347:                            if (StringUtils.isBlank(buildingCode)) {
1348:                                putFieldError(
1349:                                        "accountDescription.buildingCode",
1350:                                        KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_CAMS_SUBFUNDGROUP_WITH_MISSING_BUILDING_CD);
1351:                                success &= false;
1352:                            }
1353:
1354:                            // the building object (campusCode & buildingCode) must exist in the DB
1355:                            if (!StringUtils.isBlank(campusCode)
1356:                                    && !StringUtils.isBlank(buildingCode)) {
1357:
1358:                                // make sure that primary key fields are upper case
1359:                                DataDictionaryService dds = SpringContext
1360:                                        .getBean(DataDictionaryService.class);
1361:                                Boolean buildingCodeForceUppercase = dds
1362:                                        .getAttributeForceUppercase(
1363:                                                AccountDescription.class,
1364:                                                KFSPropertyConstants.BUILDING_CODE);
1365:                                if (StringUtils.isNotBlank(buildingCode)
1366:                                        && buildingCodeForceUppercase != null
1367:                                        && buildingCodeForceUppercase
1368:                                                .booleanValue() == true) {
1369:                                    buildingCode = buildingCode.toUpperCase();
1370:                                }
1371:
1372:                                Boolean campusCodeForceUppercase = dds
1373:                                        .getAttributeForceUppercase(
1374:                                                AccountDescription.class,
1375:                                                KFSPropertyConstants.CAMPUS_CODE);
1376:                                if (StringUtils.isNotBlank(campusCode)
1377:                                        && campusCodeForceUppercase != null
1378:                                        && campusCodeForceUppercase
1379:                                                .booleanValue() == true) {
1380:                                    campusCode = campusCode.toUpperCase();
1381:                                }
1382:
1383:                                Map pkMap = new HashMap();
1384:                                pkMap.put("campusCode", campusCode);
1385:                                pkMap.put("buildingCode", buildingCode);
1386:
1387:                                Building building = (Building) getBoService()
1388:                                        .findByPrimaryKey(Building.class, pkMap);
1389:                                if (building == null) {
1390:                                    putFieldError(
1391:                                            "accountDescription.campusCode",
1392:                                            KFSKeyConstants.ERROR_EXISTENCE,
1393:                                            campusCode);
1394:                                    putFieldError(
1395:                                            "accountDescription.buildingCode",
1396:                                            KFSKeyConstants.ERROR_EXISTENCE,
1397:                                            buildingCode);
1398:                                    success &= false;
1399:                                }
1400:                            }
1401:                        } else {
1402:
1403:                            // if sub_fund_grp_cd is NOT 'PFCMR', campus code should NOT be entered
1404:                            if (!StringUtils.isBlank(campusCode)) {
1405:                                putFieldError(
1406:                                        "accountDescription.campusCode",
1407:                                        KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_NONCAMS_SUBFUNDGROUP_WITH_CAMPUS_CD_FOR_BLDG,
1408:                                        subFundGroupCode);
1409:                                success &= false;
1410:                            }
1411:
1412:                            // if sub_fund_grp_cd is NOT 'PFCMR' then bldg_cd should NOT be entered
1413:                            if (!StringUtils.isBlank(buildingCode)) {
1414:                                putFieldError(
1415:                                        "accountDescription.buildingCode",
1416:                                        KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_NONCAMS_SUBFUNDGROUP_WITH_BUILDING_CD,
1417:                                        subFundGroupCode);
1418:                                success &= false;
1419:                            }
1420:                        }
1421:                    }
1422:
1423:                }
1424:
1425:                return success;
1426:            }
1427:
1428:            /**
1429:             * This method checks to see if the contracts and grants fields are filled in or not
1430:             * 
1431:             * @param account
1432:             * @param propertyName - property to attach error to
1433:             * @return false if the contracts and grants fields are blank
1434:             */
1435:            protected boolean checkCGFieldNotFilledIn(Account account,
1436:                    String propertyName) {
1437:                boolean success = true;
1438:                Object value = ObjectUtils.getPropertyValue(account,
1439:                        propertyName);
1440:                if ((value instanceof  String && !StringUtils.isBlank(value
1441:                        .toString()))
1442:                        || (value != null)) {
1443:                    success = false;
1444:                    putFieldError(
1445:                            propertyName,
1446:                            KFSKeyConstants.ERROR_DOCUMENT_ACCMAINT_CG_FIELDS_FILLED_FOR_NON_CG_ACCOUNT,
1447:                            new String[] { account.getSubFundGroupCode() });
1448:                }
1449:
1450:                return success;
1451:            }
1452:
1453:            /**
1454:             * This method sets the generalLedgerPendingEntryService
1455:             * 
1456:             * @param generalLedgerPendingEntryService
1457:             */
1458:            public void setGeneralLedgerPendingEntryService(
1459:                    GeneralLedgerPendingEntryService generalLedgerPendingEntryService) {
1460:                this .generalLedgerPendingEntryService = generalLedgerPendingEntryService;
1461:            }
1462:
1463:            /**
1464:             * This method sets the laborLedgerPendingEntryService
1465:             * 
1466:             * @param laborLedgerPendingEntryService
1467:             */
1468:            public void setLaborLedgerPendingEntryService(
1469:                    LaborLedgerPendingEntryService laborLedgerPendingEntryService) {
1470:                this .laborLedgerPendingEntryService = laborLedgerPendingEntryService;
1471:            }
1472:
1473:            /**
1474:             * This method sets the balanceService
1475:             * 
1476:             * @param balanceService
1477:             */
1478:            public void setBalanceService(BalanceService balanceService) {
1479:                this .balanceService = balanceService;
1480:            }
1481:
1482:            /**
1483:             * Sets the accountService attribute value.
1484:             * 
1485:             * @param accountService The accountService to set.
1486:             */
1487:            public final void setAccountService(AccountService accountService) {
1488:                this.accountService = accountService;
1489:            }
1490:
1491:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.