Source Code Cross Referenced for DisbursementVoucherDocumentRule.java in  » ERP-CRM-Financial » Kuali-Financial-System » org » kuali » module » financial » 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.financial.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.financial.rules;
0017:
0018:        import static org.kuali.kfs.KFSConstants.GL_CREDIT_CODE;
0019:        import static org.kuali.kfs.KFSConstants.GL_DEBIT_CODE;
0020:
0021:        import java.util.List;
0022:
0023:        import org.apache.commons.lang.StringUtils;
0024:        import org.kuali.core.bo.PersistableBusinessObject;
0025:        import org.kuali.core.bo.user.AuthenticationUserId;
0026:        import org.kuali.core.bo.user.PersonTaxId;
0027:        import org.kuali.core.bo.user.UniversalUser;
0028:        import org.kuali.core.document.Document;
0029:        import org.kuali.core.exceptions.UserNotFoundException;
0030:        import org.kuali.core.rule.event.ApproveDocumentEvent;
0031:        import org.kuali.core.service.BusinessObjectService;
0032:        import org.kuali.core.service.DictionaryValidationService;
0033:        import org.kuali.core.service.DocumentAuthorizationService;
0034:        import org.kuali.core.service.UniversalUserService;
0035:        import org.kuali.core.util.ErrorMap;
0036:        import org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper;
0037:        import org.kuali.core.util.GlobalVariables;
0038:        import org.kuali.core.util.KualiDecimal;
0039:        import org.kuali.core.util.ObjectUtils;
0040:        import org.kuali.core.workflow.service.KualiWorkflowDocument;
0041:        import org.kuali.kfs.KFSConstants;
0042:        import org.kuali.kfs.KFSKeyConstants;
0043:        import org.kuali.kfs.KFSPropertyConstants;
0044:        import org.kuali.kfs.bo.AccountingLine;
0045:        import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
0046:        import org.kuali.kfs.bo.SourceAccountingLine;
0047:        import org.kuali.kfs.context.SpringContext;
0048:        import org.kuali.kfs.document.AccountingDocument;
0049:        import org.kuali.kfs.rule.GenerateGeneralLedgerDocumentPendingEntriesRule;
0050:        import org.kuali.kfs.rules.AccountingDocumentRuleBase;
0051:        import org.kuali.kfs.service.OptionsService;
0052:        import org.kuali.kfs.service.ParameterEvaluator;
0053:        import org.kuali.module.chart.bo.ChartUser;
0054:        import org.kuali.module.chart.bo.ObjectCode;
0055:        import org.kuali.module.financial.bo.DisbursementVoucherNonEmployeeExpense;
0056:        import org.kuali.module.financial.bo.DisbursementVoucherPayeeDetail;
0057:        import org.kuali.module.financial.bo.NonResidentAlienTaxPercent;
0058:        import org.kuali.module.financial.bo.Payee;
0059:        import org.kuali.module.financial.bo.TravelCompanyCode;
0060:        import org.kuali.module.financial.bo.WireCharge;
0061:        import org.kuali.module.financial.document.DisbursementVoucherDocument;
0062:        import org.kuali.module.financial.document.authorization.DisbursementVoucherDocumentAuthorizer;
0063:        import org.kuali.module.financial.service.DisbursementVoucherTaxService;
0064:        import org.kuali.module.financial.service.DisbursementVoucherTravelService;
0065:        import org.kuali.module.financial.service.UniversityDateService;
0066:
0067:        /**
0068:         * Business rule(s) applicable to Disbursement Voucher documents.
0069:         */
0070:        public class DisbursementVoucherDocumentRule extends
0071:                AccountingDocumentRuleBase
0072:                implements 
0073:                DisbursementVoucherRuleConstants,
0074:                GenerateGeneralLedgerDocumentPendingEntriesRule<AccountingDocument> {
0075:            private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0076:                    .getLogger(DisbursementVoucherDocumentRule.class);
0077:            private static final String DV_PAYMENT_REASON_PROPERTY_PATH = KFSPropertyConstants.DV_PAYEE_DETAIL
0078:                    + "." + KFSPropertyConstants.DISB_VCHR_PAYMENT_REASON_CODE;
0079:            private static final String DV_PAYEE_ID_NUMBER_PROPERTY_PATH = KFSPropertyConstants.DV_PAYEE_DETAIL
0080:                    + "." + KFSPropertyConstants.DISB_VCHR_PAYEE_ID_NUMBER;
0081:            private static String taxGroupName;
0082:            private static String travelGroupName;
0083:            private static String wireTransferGroupName;
0084:            private static String frnGroupName;
0085:            private static String adminGroupName;
0086:
0087:            /**
0088:             * Constructs a DisbursementVoucherDocumentRule instance.
0089:             */
0090:            public DisbursementVoucherDocumentRule() {
0091:                setMaxDictionaryValidationDepth(0);
0092:            }
0093:
0094:            /**
0095:             * Returns true disbursement voucher can be saved successfully (i.e. a non-employee travel company and prepaid expenses company is provided)
0096:             * 
0097:             * @param document submitted disbursement voucher document
0098:             * @return true if disbursement voucher can be saved successfully
0099:             * 
0100:             * @see org.kuali.core.rules.DocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.core.document.Document)
0101:             */
0102:            @Override
0103:            protected boolean processCustomSaveDocumentBusinessRules(
0104:                    Document document) {
0105:                boolean valid = super 
0106:                        .processCustomSaveDocumentBusinessRules(document);
0107:
0108:                DisbursementVoucherDocument disbursementVoucherDocument = (DisbursementVoucherDocument) document;
0109:
0110:                // check non employee travel company exists
0111:                int i = 0;
0112:                List<DisbursementVoucherNonEmployeeExpense> expenses = disbursementVoucherDocument
0113:                        .getDvNonEmployeeTravel().getDvNonEmployeeExpenses();
0114:                for (DisbursementVoucherNonEmployeeExpense expense : expenses) {
0115:                    TravelCompanyCode travelCompanyCode = retrieveCompany(
0116:                            expense.getDisbVchrExpenseCode(), expense
0117:                                    .getDisbVchrExpenseCompanyName());
0118:
0119:                    if (ObjectUtils.isNull(travelCompanyCode)) {
0120:                        GlobalVariables
0121:                                .getErrorMap()
0122:                                .putErrorWithoutFullErrorPath(
0123:                                        KFSPropertyConstants.DOCUMENT
0124:                                                + "."
0125:                                                + KFSPropertyConstants.DV_NON_EMPLOYEE_TRAVEL
0126:                                                + "."
0127:                                                + KFSPropertyConstants.DV_NON_EMPLOYEE_EXPENSES
0128:                                                + "["
0129:                                                + i
0130:                                                + "]"
0131:                                                + "."
0132:                                                + KFSPropertyConstants.DISB_VCHR_EXPENSE_COMPANY_NAME,
0133:                                        KFSKeyConstants.ERROR_EXISTENCE,
0134:                                        "Company ");
0135:                    }
0136:
0137:                    i++;
0138:                }
0139:
0140:                // check prepaid expenses company exists
0141:                i = 0;
0142:                List<DisbursementVoucherNonEmployeeExpense> prePaidExpenses = disbursementVoucherDocument
0143:                        .getDvNonEmployeeTravel()
0144:                        .getDvPrePaidEmployeeExpenses();
0145:                for (DisbursementVoucherNonEmployeeExpense prePaidExpense : prePaidExpenses) {
0146:                    TravelCompanyCode travelCompanyCode = retrieveCompany(
0147:                            prePaidExpense.getDisbVchrExpenseCode(),
0148:                            prePaidExpense.getDisbVchrExpenseCompanyName());
0149:
0150:                    if (ObjectUtils.isNull(travelCompanyCode)) {
0151:                        GlobalVariables
0152:                                .getErrorMap()
0153:                                .putErrorWithoutFullErrorPath(
0154:                                        KFSPropertyConstants.DOCUMENT
0155:                                                + "."
0156:                                                + KFSPropertyConstants.DV_NON_EMPLOYEE_TRAVEL
0157:                                                + "."
0158:                                                + KFSPropertyConstants.DV_PRE_PAID_EMPLOYEE_EXPENSES
0159:                                                + "["
0160:                                                + i
0161:                                                + "]"
0162:                                                + "."
0163:                                                + KFSPropertyConstants.DISB_VCHR_EXPENSE_COMPANY_NAME,
0164:                                        KFSKeyConstants.ERROR_EXISTENCE,
0165:                                        "Company ");
0166:                    }
0167:
0168:                    i++;
0169:                }
0170:
0171:                return valid;
0172:            }
0173:
0174:            /**
0175:             * Overrides to call super. If super fails, then we invoke some DV specific rules about FO routing to double check if the
0176:             * individual has special conditions that they can alter accounting lines by.
0177:             * 
0178:             * @param financialdocument submitted disbursement voucher document
0179:             * @param accountingLine accounting line in disbursement voucher
0180:             * @param action accounting line action
0181:             * @return true if accounting line is accessible
0182:             * 
0183:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#checkAccountingLineAccountAccessibility(org.kuali.core.document.FinancialDocument,
0184:             *      org.kuali.core.bo.AccountingLine, org.kuali.module.financial.rules.FinancialDocumentRuleBase.AccountingLineAction)
0185:             */
0186:            @Override
0187:            protected boolean checkAccountingLineAccountAccessibility(
0188:                    AccountingDocument financialDocument,
0189:                    AccountingLine accountingLine, AccountingLineAction action) {
0190:                // first check parent's isAccessible method for basic FO authz checking
0191:                boolean isAccessible = accountIsAccessible(financialDocument,
0192:                        accountingLine);
0193:
0194:                // get the authorizer class to check for special conditions routing and if the user is part of a particular workgroup
0195:                // but only if the document is enroute
0196:                if (!isAccessible
0197:                        && financialDocument.getDocumentHeader()
0198:                                .getWorkflowDocument().stateIsEnroute()) {
0199:                    DisbursementVoucherDocumentAuthorizer dvAuthorizer = (DisbursementVoucherDocumentAuthorizer) SpringContext
0200:                            .getBean(DocumentAuthorizationService.class)
0201:                            .getDocumentAuthorizer(financialDocument);
0202:                    // if approval is requested and it is special conditions routing and the user is in a special conditions routing
0203:                    // workgroup then
0204:                    // the line is accessible
0205:                    if (financialDocument.getDocumentHeader()
0206:                            .getWorkflowDocument().isApprovalRequested()
0207:                            && dvAuthorizer.isSpecialRouting(financialDocument,
0208:                                    GlobalVariables.getUserSession()
0209:                                            .getUniversalUser())
0210:                            && (isUserInTaxGroup() || isUserInTravelGroup()
0211:                                    || isUserInFRNGroup()
0212:                                    || isUserInWireGroup() || isUserInDvAdminGroup())) {
0213:                        isAccessible = true;
0214:                    }
0215:                }
0216:
0217:                // report (and log) errors
0218:                if (!isAccessible) {
0219:                    String[] errorParams = new String[] {
0220:                            accountingLine.getAccountNumber(),
0221:                            GlobalVariables.getUserSession().getUniversalUser()
0222:                                    .getPersonUserIdentifier() };
0223:                    GlobalVariables.getErrorMap().putError(
0224:                            KFSPropertyConstants.ACCOUNT_NUMBER,
0225:                            action.accessibilityErrorKey, errorParams);
0226:                }
0227:
0228:                return isAccessible;
0229:            }
0230:
0231:            /**
0232:             * Returns true if processCustomAddAccountingLineBusinessRules(financialDocument, updatedAccountingLine) returns true.
0233:             * 
0234:             * @param financialDocument submitted disbursement voucher document
0235:             * @param originalAccountingLine original accounting line
0236:             * @param updatedAccountingLine updated accounting line
0237:             * @return same value as processCustomAddAccountingLineBusinessRules(financialDocument, updatedAccountingLine)
0238:             * 
0239:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomUpdateAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
0240:             *      org.kuali.core.bo.AccountingLine, org.kuali.core.bo.AccountingLine)
0241:             */
0242:            @Override
0243:            protected boolean processCustomUpdateAccountingLineBusinessRules(
0244:                    AccountingDocument financialDocument,
0245:                    AccountingLine originalAccountingLine,
0246:                    AccountingLine updatedAccountingLine) {
0247:                return processCustomAddAccountingLineBusinessRules(
0248:                        financialDocument, updatedAccountingLine);
0249:            }
0250:
0251:            /**
0252:             * Override to check if we are in special handling where the check amount and accounting line total can decrease, else amounts
0253:             * should not have changed.
0254:             * 
0255:             * @param approveEvent event fired when approving document
0256:             * @return true check total did not decrease
0257:             * 
0258:             * @see org.kuali.core.rule.DocumentRuleBase#processCustomApproveDocumentBusinessRules(org.kuali.core.rule.event.ApproveDocumentEvent)
0259:             */
0260:            @Override
0261:            protected boolean processCustomApproveDocumentBusinessRules(
0262:                    ApproveDocumentEvent approveEvent) {
0263:                DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) approveEvent
0264:                        .getDocument();
0265:
0266:                // amounts can only decrease
0267:                DisbursementVoucherDocumentAuthorizer dvAuthorizer = (DisbursementVoucherDocumentAuthorizer) SpringContext
0268:                        .getBean(DocumentAuthorizationService.class)
0269:                        .getDocumentAuthorizer(dvDocument);
0270:                if (dvAuthorizer.isSpecialRouting(dvDocument, GlobalVariables
0271:                        .getUserSession().getUniversalUser())
0272:                        && (isUserInTaxGroup() || isUserInTravelGroup()
0273:                                || isUserInFRNGroup() || isUserInWireGroup())) {
0274:                    boolean approveOK = true;
0275:
0276:                    // users in foreign or wire workgroup can increase or decrease amounts because of currency conversion
0277:                    if (!isUserInFRNGroup() && !isUserInWireGroup()) {
0278:                        DisbursementVoucherDocument persistedDocument = (DisbursementVoucherDocument) retrievePersistedDocument(dvDocument);
0279:                        if (persistedDocument == null) {
0280:                            handleNonExistentDocumentWhenApproving(dvDocument);
0281:                            return approveOK;
0282:                        } else {
0283:                            // check total cannot decrease
0284:                            if (persistedDocument
0285:                                    .getDisbVchrCheckTotalAmount()
0286:                                    .isLessThan(
0287:                                            dvDocument
0288:                                                    .getDisbVchrCheckTotalAmount())) {
0289:                                GlobalVariables
0290:                                        .getErrorMap()
0291:                                        .putError(
0292:                                                KFSPropertyConstants.DOCUMENT
0293:                                                        + "."
0294:                                                        + KFSPropertyConstants.DISB_VCHR_CHECK_TOTAL_AMOUNT,
0295:                                                KFSKeyConstants.ERROR_DV_CHECK_TOTAL_CHANGE);
0296:                                approveOK = false;
0297:                            }
0298:                        }
0299:                    }
0300:
0301:                    return approveOK;
0302:                } else {
0303:                    // amounts must not have been changed
0304:                    return super 
0305:                            .processCustomApproveDocumentBusinessRules(approveEvent);
0306:                }
0307:            }
0308:
0309:            /**
0310:             * Return true if accounting line can be added successfully (i.e. payment reason and payee must be selected before
0311:             * accounting line can be entered) 
0312:             * 
0313:             * @param financialDocument submitted financial document
0314:             * @param accountingLine accounting line 
0315:             * @return true if accounting line can be added successfully (i.e. payment reason and payee must be selected before
0316:             * accounting line can be entered) 
0317:             * 
0318:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomAddAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
0319:             *      org.kuali.core.bo.AccountingLine)
0320:             */
0321:            @Override
0322:            public boolean processCustomAddAccountingLineBusinessRules(
0323:                    AccountingDocument financialDocument,
0324:                    AccountingLine accountingLine) {
0325:                boolean allow = true;
0326:
0327:                LOG.debug("validating accounting line # "
0328:                        + accountingLine.getSequenceNumber());
0329:
0330:                // don't validate generated tax lines
0331:                if (((DisbursementVoucherDocument) financialDocument)
0332:                        .getDvNonResidentAlienTax() != null) {
0333:                    List taxLineNumbers = SpringContext
0334:                            .getBean(DisbursementVoucherTaxService.class)
0335:                            .getNRATaxLineNumbers(
0336:                                    ((DisbursementVoucherDocument) financialDocument)
0337:                                            .getDvNonResidentAlienTax()
0338:                                            .getFinancialDocumentAccountingLineText());
0339:                    if (taxLineNumbers.contains(accountingLine
0340:                            .getSequenceNumber())) {
0341:                        return true;
0342:                    }
0343:                }
0344:
0345:                DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) financialDocument;
0346:                ErrorMap errors = GlobalVariables.getErrorMap();
0347:
0348:                /* payment reason must be selected before an accounting line can be entered */
0349:                if (StringUtils.isBlank(dvDocument.getDvPayeeDetail()
0350:                        .getDisbVchrPaymentReasonCode())) {
0351:                    if (!errors
0352:                            .containsMessageKey(KFSKeyConstants.ERROR_DV_ADD_LINE_MISSING_PAYMENT_REASON)) {
0353:                        errors
0354:                                .putErrorWithoutFullErrorPath(
0355:                                        KFSPropertyConstants.DOCUMENT
0356:                                                + "."
0357:                                                + DV_PAYMENT_REASON_PROPERTY_PATH,
0358:                                        KFSKeyConstants.ERROR_DV_ADD_LINE_MISSING_PAYMENT_REASON);
0359:                    }
0360:                    allow = false;
0361:                }
0362:
0363:                /* payee must be selected before an accounting line can be entered */
0364:                if (StringUtils.isBlank(dvDocument.getDvPayeeDetail()
0365:                        .getDisbVchrPayeeIdNumber())) {
0366:                    if (!errors
0367:                            .containsMessageKey(KFSKeyConstants.ERROR_DV_ADD_LINE_MISSING_PAYEE)) {
0368:                        errors
0369:                                .putErrorWithoutFullErrorPath(
0370:                                        KFSPropertyConstants.DOCUMENT
0371:                                                + "."
0372:                                                + DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
0373:                                        KFSKeyConstants.ERROR_DV_ADD_LINE_MISSING_PAYEE);
0374:                    }
0375:                    allow = false;
0376:                }
0377:
0378:                if (allow) {
0379:                    LOG.debug("beginning object code validation ");
0380:                    allow = validateObjectCode(financialDocument,
0381:                            accountingLine);
0382:
0383:                    LOG.debug("beginning account number validation ");
0384:                    allow = allow
0385:                            & validateAccountNumber(financialDocument,
0386:                                    accountingLine);
0387:                }
0388:
0389:                LOG.debug("end validating accounting line, has errors: "
0390:                        + allow);
0391:
0392:                return allow;
0393:            }
0394:
0395:            /**
0396:             * Final business rule edits on routing of disbursement voucher document.
0397:             * 
0398:             * @param document submitted disbursement voucher document
0399:             * @return true is disbursement voucher document can be routed with out any problems
0400:             * 
0401:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.core.document.FinancialDocument)
0402:             */
0403:            @Override
0404:            protected boolean processCustomRouteDocumentBusinessRules(
0405:                    Document document) {
0406:                DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) document;
0407:                DisbursementVoucherPayeeDetail payeeDetail = dvDocument
0408:                        .getDvPayeeDetail();
0409:
0410:                GlobalVariables.getErrorMap().addToErrorPath(
0411:                        KFSPropertyConstants.DOCUMENT);
0412:
0413:                LOG.debug("processing route rules for document "
0414:                        + document.getDocumentNumber());
0415:
0416:                validateDocumentFields(dvDocument);
0417:
0418:                LOG.debug("validating payment reason");
0419:                validatePaymentReason(dvDocument);
0420:
0421:                LOG.debug("validating payee initiator id");
0422:                validatePayeeInitiatorID(dvDocument);
0423:
0424:                if (payeeDetail.isPayee()) {
0425:                    LOG.debug("validating payee information");
0426:                    validatePayeeInformation(dvDocument);
0427:                }
0428:
0429:                if (payeeDetail.isEmployee()) {
0430:                    LOG.debug("validating employee information");
0431:                    validateEmployeeInformation(dvDocument);
0432:                }
0433:
0434:                /* specific validation depending on payment method */
0435:                if (PAYMENT_METHOD_WIRE.equals(dvDocument
0436:                        .getDisbVchrPaymentMethodCode())) {
0437:                    LOG.debug("validating wire transfer");
0438:                    validateWireTransfer(dvDocument);
0439:                } else if (PAYMENT_METHOD_DRAFT.equals(dvDocument
0440:                        .getDisbVchrPaymentMethodCode())) {
0441:                    LOG.debug("validating foreign draft");
0442:                    validateForeignDraft(dvDocument);
0443:                }
0444:
0445:                /* if nra payment and user is in tax group, check nra tab */
0446:                if (dvDocument.getDvPayeeDetail().isDisbVchrAlienPaymentCode()
0447:                        && isUserInTaxGroup()) {
0448:                    LOG.debug("validating non resident alien tax");
0449:                    validateNonResidentAlienInformation(dvDocument);
0450:                }
0451:
0452:                // non-employee travel
0453:
0454:                // retrieve nonemployee travel payment reasons
0455:                if (isTravelNonEmplPaymentReason(dvDocument)) {
0456:                    LOG.debug("validating non employee travel");
0457:                    validateNonEmployeeTravel(dvDocument);
0458:                }
0459:
0460:                // pre-paid travel
0461:
0462:                // retrieve prepaid travel payment reasons
0463:                if (isTravelPrepaidPaymentReason(dvDocument)) {
0464:                    LOG.debug("validating pre paid travel");
0465:                    validatePrePaidTravel(dvDocument);
0466:                }
0467:
0468:                LOG.debug("validating document amounts");
0469:                validateDocumentAmounts(dvDocument);
0470:
0471:                LOG.debug("validating accounting line counts");
0472:                validateAccountingLineCounts(dvDocument);
0473:
0474:                LOG.debug("validating documentaton location");
0475:                validateDocumentationLocation(dvDocument);
0476:
0477:                GlobalVariables.getErrorMap().removeFromErrorPath(
0478:                        KFSPropertyConstants.DOCUMENT);
0479:
0480:                LOG
0481:                        .debug("finished route validation for document, has errors: "
0482:                                + !GlobalVariables.getErrorMap().isEmpty());
0483:
0484:                return GlobalVariables.getErrorMap().isEmpty();
0485:            }
0486:
0487:            /**
0488:             * Returns whether the document's payment reason is for travel by a non-employee
0489:             * 
0490:             * @param disbursementVoucherDocument submitted disbursement voucher document
0491:             * @return true if payment reason is travel by a non-employee
0492:             * 
0493:             */
0494:            public boolean isTravelNonEmplPaymentReason(
0495:                    DisbursementVoucherDocument disbursementVoucherDocument) {
0496:                ParameterEvaluator travelNonEmplPaymentReasonEvaluator = getParameterService()
0497:                        .getParameterEvaluator(
0498:                                DisbursementVoucherDocument.class,
0499:                                DisbursementVoucherRuleConstants.NONEMPLOYEE_TRAVEL_PAY_REASONS_PARM_NM,
0500:                                disbursementVoucherDocument.getDvPayeeDetail()
0501:                                        .getDisbVchrPaymentReasonCode());
0502:                return travelNonEmplPaymentReasonEvaluator.evaluationSucceeds();
0503:            }
0504:
0505:            /**
0506:             * Returns whether the document's payment reason is for prepaid travel
0507:             * 
0508:             * @param disbursementVoucherDocument
0509:             * @return true if payment reason is for pre-paid travel reason
0510:             */
0511:            public boolean isTravelPrepaidPaymentReason(
0512:                    DisbursementVoucherDocument disbursementVoucherDocument) {
0513:                ParameterEvaluator travelNonEmplPaymentReasonEvaluator = getParameterService()
0514:                        .getParameterEvaluator(
0515:                                DisbursementVoucherDocument.class,
0516:                                DisbursementVoucherRuleConstants.PREPAID_TRAVEL_PAY_REASONS_PARM_NM,
0517:                                disbursementVoucherDocument.getDvPayeeDetail()
0518:                                        .getDisbVchrPaymentReasonCode());
0519:                return travelNonEmplPaymentReasonEvaluator.evaluationSucceeds();
0520:            }
0521:
0522:            /**
0523:             * Override to change the doc type based on payment method. This is needed to pick up different offset definitions.
0524:             * 
0525:             * @param financialDocument submitted accounting document
0526:             * @param accountingLine accounting line in submitted accounting document 
0527:             * @param explicitEntry explicit GLPE 
0528:             * 
0529:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(org.kuali.core.document.FinancialDocument,
0530:             *      org.kuali.core.bo.AccountingLine, org.kuali.module.gl.bo.GeneralLedgerPendingEntry)
0531:             */
0532:            protected void customizeExplicitGeneralLedgerPendingEntry(
0533:                    AccountingDocument financialDocument,
0534:                    AccountingLine accountingLine,
0535:                    GeneralLedgerPendingEntry explicitEntry) {
0536:                DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) financialDocument;
0537:
0538:                /* change document type based on payment method to pick up different offsets */
0539:                if (PAYMENT_METHOD_CHECK.equals(dvDocument
0540:                        .getDisbVchrPaymentMethodCode())) {
0541:                    LOG.debug("changing doc type on pending entry "
0542:                            + explicitEntry
0543:                                    .getTransactionLedgerEntrySequenceNumber()
0544:                            + " to " + DOCUMENT_TYPE_CHECKACH);
0545:                    explicitEntry
0546:                            .setFinancialDocumentTypeCode(DOCUMENT_TYPE_CHECKACH);
0547:                } else {
0548:                    LOG.debug("changing doc type on pending entry "
0549:                            + explicitEntry
0550:                                    .getTransactionLedgerEntrySequenceNumber()
0551:                            + " to " + DOCUMENT_TYPE_CHECKACH);
0552:                    explicitEntry
0553:                            .setFinancialDocumentTypeCode(DOCUMENT_TYPE_WTFD);
0554:                }
0555:            }
0556:
0557:            /**
0558:             * Return true if GLPE's are generated successfully (i.e. there are either 0 GLPE's or 1 GLPE in dibursement voucher document)
0559:             * 
0560:             * @param financialDocument submitted financial document
0561:             * @param sequenceHelper helper class to keep track of GLPE sequence
0562:             * @return true if GLPE's are generated successfully
0563:             * 
0564:             * @see org.kuali.core.rule.GenerateGeneralLedgerDocumentPendingEntriesRule#processGenerateDocumentGeneralLedgerPendingEntries(org.kuali.core.document.FinancialDocument,org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper)
0565:             */
0566:            public boolean processGenerateDocumentGeneralLedgerPendingEntries(
0567:                    AccountingDocument financialDocument,
0568:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
0569:                DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) financialDocument;
0570:                if (dvDocument.getGeneralLedgerPendingEntries() == null
0571:                        || dvDocument.getGeneralLedgerPendingEntries().size() < 2) {
0572:                    LOG.warn("No gl entries for accounting lines.");
0573:                    return true;
0574:                    // throw new RuntimeException("No gl entries for accounting lines.");
0575:                }
0576:
0577:                /*
0578:                 * only generate additional charge entries for payment method wire charge, and if the fee has not been waived
0579:                 */
0580:                if (PAYMENT_METHOD_WIRE.equals(dvDocument
0581:                        .getDisbVchrPaymentMethodCode())
0582:                        && !dvDocument
0583:                                .getDvWireTransfer()
0584:                                .isDisbursementVoucherWireTransferFeeWaiverIndicator()) {
0585:                    LOG.debug("generating wire charge gl pending entries.");
0586:
0587:                    // retrieve wire charge
0588:                    WireCharge wireCharge = retrieveWireCharge();
0589:
0590:                    // generate debits
0591:                    GeneralLedgerPendingEntry chargeEntry = processWireChargeDebitEntries(
0592:                            dvDocument, sequenceHelper, wireCharge);
0593:
0594:                    // generate credits
0595:                    processWireChargeCreditEntries(dvDocument, sequenceHelper,
0596:                            wireCharge, chargeEntry);
0597:                }
0598:
0599:                return true;
0600:            }
0601:
0602:            /**
0603:             * Builds an explicit and offset for the wire charge debit. The account associated with the first accounting is used for the
0604:             * debit. The explicit and offset entries for the first accounting line and copied and customized for the wire charge.
0605:             * 
0606:             * @param dvDocument submitted disbursement voucher document
0607:             * @param sequenceHelper helper class to keep track of GLPE sequence 
0608:             * @param wireCharge wireCharge object from current fiscal year
0609:             * @return GeneralLedgerPendingEntry generated wire charge debit
0610:             */
0611:            private GeneralLedgerPendingEntry processWireChargeDebitEntries(
0612:                    DisbursementVoucherDocument dvDocument,
0613:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper,
0614:                    WireCharge wireCharge) {
0615:
0616:                // increment the sequence counter
0617:                sequenceHelper.increment();
0618:
0619:                // grab the explicit entry for the first accounting line and adjust for wire charge entry
0620:                GeneralLedgerPendingEntry explicitEntry = (GeneralLedgerPendingEntry) ObjectUtils
0621:                        .deepCopy(dvDocument.getGeneralLedgerPendingEntry(0));
0622:                explicitEntry
0623:                        .setTransactionLedgerEntrySequenceNumber(new Integer(
0624:                                sequenceHelper.getSequenceCounter()));
0625:                explicitEntry.setFinancialObjectCode(wireCharge
0626:                        .getExpenseFinancialObjectCode());
0627:                explicitEntry
0628:                        .setFinancialSubObjectCode(GENERAL_LEDGER_PENDING_ENTRY_CODE
0629:                                .getBlankFinancialSubObjectCode());
0630:                explicitEntry.setFinancialObjectTypeCode(SpringContext.getBean(
0631:                        OptionsService.class).getCurrentYearOptions()
0632:                        .getFinObjTypeExpenditureexpCd());
0633:                explicitEntry.setTransactionDebitCreditCode(GL_DEBIT_CODE);
0634:
0635:                if (KFSConstants.COUNTRY_CODE_UNITED_STATES.equals(dvDocument
0636:                        .getDvWireTransfer().getDisbVchrBankCountryCode())) {
0637:                    explicitEntry.setTransactionLedgerEntryAmount(wireCharge
0638:                            .getDomesticChargeAmt());
0639:                } else {
0640:                    explicitEntry.setTransactionLedgerEntryAmount(wireCharge
0641:                            .getForeignChargeAmt());
0642:                }
0643:
0644:                explicitEntry
0645:                        .setTransactionLedgerEntryDescription("Automatic debit for wire transfer fee");
0646:
0647:                dvDocument.getGeneralLedgerPendingEntries().add(explicitEntry);
0648:
0649:                // create offset
0650:                sequenceHelper.increment();
0651:
0652:                // handle the offset entry
0653:                GeneralLedgerPendingEntry offsetEntry = (GeneralLedgerPendingEntry) ObjectUtils
0654:                        .deepCopy(explicitEntry);
0655:                populateOffsetGeneralLedgerPendingEntry(dvDocument
0656:                        .getPostingYear(), explicitEntry, sequenceHelper,
0657:                        offsetEntry);
0658:
0659:                dvDocument.getGeneralLedgerPendingEntries().add(offsetEntry);
0660:
0661:                return explicitEntry;
0662:            }
0663:
0664:            /**
0665:             * Builds an explicit and offset for the wire charge credit. The account and income object code found in the wire charge table
0666:             * is used for the entry.
0667:             * 
0668:             * @param dvDocument submitted disbursement voucher document
0669:             * @param sequenceHelper helper class to keep track of GLPE sequence 
0670:             * @param chargeEntry GLPE charge
0671:             * @param wireCharge wireCharge object from current fiscal year
0672:             *  
0673:             */
0674:            private void processWireChargeCreditEntries(
0675:                    DisbursementVoucherDocument dvDocument,
0676:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper,
0677:                    WireCharge wireCharge, GeneralLedgerPendingEntry chargeEntry) {
0678:
0679:                // increment the sequence counter
0680:                sequenceHelper.increment();
0681:
0682:                // copy the charge entry and adjust for credit
0683:                GeneralLedgerPendingEntry explicitEntry = (GeneralLedgerPendingEntry) ObjectUtils
0684:                        .deepCopy(chargeEntry);
0685:                explicitEntry
0686:                        .setTransactionLedgerEntrySequenceNumber(new Integer(
0687:                                sequenceHelper.getSequenceCounter()));
0688:                explicitEntry.setChartOfAccountsCode(wireCharge
0689:                        .getChartOfAccountsCode());
0690:                explicitEntry.setAccountNumber(wireCharge.getAccountNumber());
0691:                explicitEntry.setFinancialObjectCode(wireCharge
0692:                        .getIncomeFinancialObjectCode());
0693:
0694:                // retrieve object type
0695:                ObjectCode objectCode = new ObjectCode();
0696:                objectCode.setUniversityFiscalYear(explicitEntry
0697:                        .getUniversityFiscalYear());
0698:                objectCode.setChartOfAccountsCode(wireCharge
0699:                        .getChartOfAccountsCode());
0700:                objectCode.setFinancialObjectCode(wireCharge
0701:                        .getIncomeFinancialObjectCode());
0702:                objectCode = (ObjectCode) SpringContext.getBean(
0703:                        BusinessObjectService.class).retrieve(objectCode);
0704:
0705:                explicitEntry.setFinancialObjectTypeCode(objectCode
0706:                        .getFinancialObjectTypeCode());
0707:                explicitEntry.setTransactionDebitCreditCode(GL_CREDIT_CODE);
0708:
0709:                explicitEntry
0710:                        .setFinancialSubObjectCode(GENERAL_LEDGER_PENDING_ENTRY_CODE
0711:                                .getBlankFinancialSubObjectCode());
0712:                explicitEntry
0713:                        .setSubAccountNumber(GENERAL_LEDGER_PENDING_ENTRY_CODE
0714:                                .getBlankSubAccountNumber());
0715:                explicitEntry.setProjectCode(GENERAL_LEDGER_PENDING_ENTRY_CODE
0716:                        .getBlankProjectCode());
0717:
0718:                explicitEntry
0719:                        .setTransactionLedgerEntryDescription("Automatic credit for wire transfer fee");
0720:
0721:                dvDocument.getGeneralLedgerPendingEntries().add(explicitEntry);
0722:
0723:                // create offset
0724:                sequenceHelper.increment();
0725:
0726:                // handle the offset entry
0727:                GeneralLedgerPendingEntry offsetEntry = (GeneralLedgerPendingEntry) ObjectUtils
0728:                        .deepCopy(explicitEntry);
0729:                populateOffsetGeneralLedgerPendingEntry(dvDocument
0730:                        .getPostingYear(), explicitEntry, sequenceHelper,
0731:                        offsetEntry);
0732:
0733:                dvDocument.getGeneralLedgerPendingEntries().add(offsetEntry);
0734:            }
0735:
0736:            /**
0737:             * Validates conditional required fields. Note fields that are always required are validated by the dictionary framework.
0738:             * 
0739:             * @param document submitted disbursement voucher document
0740:             */
0741:            private void validateDocumentFields(
0742:                    DisbursementVoucherDocument document) {
0743:                ErrorMap errors = GlobalVariables.getErrorMap();
0744:
0745:                // validate document required fields, and payee fields, and formatting
0746:                SpringContext.getBean(DictionaryValidationService.class)
0747:                        .validateDocument(document);
0748:                errors.addToErrorPath(KFSPropertyConstants.DV_PAYEE_DETAIL);
0749:                SpringContext.getBean(DictionaryValidationService.class)
0750:                        .validateBusinessObject(document.getDvPayeeDetail());
0751:                errors
0752:                        .removeFromErrorPath(KFSPropertyConstants.DV_PAYEE_DETAIL);
0753:                if (!errors.isEmpty()) {
0754:                    return;
0755:                }
0756:
0757:                /* remit name & address required if special handling is indicated */
0758:                if (document.isDisbVchrSpecialHandlingCode()) {
0759:                    if (StringUtils.isBlank(document.getDvPayeeDetail()
0760:                            .getDisbVchrRemitPersonName())
0761:                            || StringUtils.isBlank(document.getDvPayeeDetail()
0762:                                    .getDisbVchrPayeeLine1Addr())) {
0763:                        errors.putErrorWithoutFullErrorPath(
0764:                                KFSConstants.GENERAL_SPECHAND_TAB_ERRORS,
0765:                                KFSKeyConstants.ERROR_DV_SPECIAL_HANDLING);
0766:                    }
0767:                }
0768:
0769:                /* if no documentation is selected, must be a note explaining why */
0770:                if (NO_DOCUMENTATION_LOCATION.equals(document
0771:                        .getDisbursementVoucherDocumentationLocationCode())
0772:                        && hasNoNotes(document)) {
0773:                    errors
0774:                            .putError(
0775:                                    KFSPropertyConstants.DISBURSEMENT_VOUCHER_DOCUMENTATION_LOCATION_CODE,
0776:                                    KFSKeyConstants.ERROR_DV_NO_DOCUMENTATION_NOTE_MISSING);
0777:                }
0778:
0779:                /* if special handling indicated, must be a note exlaining why */
0780:                if (document.isDisbVchrSpecialHandlingCode()
0781:                        && hasNoNotes(document)) {
0782:                    errors
0783:                            .putErrorWithoutFullErrorPath(
0784:                                    KFSConstants.GENERAL_PAYMENT_TAB_ERRORS,
0785:                                    KFSKeyConstants.ERROR_DV_SPECIAL_HANDLING_NOTE_MISSING);
0786:                }
0787:
0788:                /* if exception attached indicated, must be a note exlaining why */
0789:                if (document.isExceptionIndicator() && hasNoNotes(document)) {
0790:                    errors
0791:                            .putErrorWithoutFullErrorPath(
0792:                                    KFSConstants.GENERAL_PAYMENT_TAB_ERRORS,
0793:                                    KFSKeyConstants.ERROR_DV_EXCEPTION_ATTACHED_NOTE_MISSING);
0794:                }
0795:
0796:                /* city, state & zip must be given for us */
0797:                if (KFSConstants.COUNTRY_CODE_UNITED_STATES.equals(document
0798:                        .getDvPayeeDetail().getDisbVchrPayeeCountryCode())) {
0799:                    if (StringUtils.isBlank(document.getDvPayeeDetail()
0800:                            .getDisbVchrPayeeCityName())) {
0801:                        errors
0802:                                .putError(
0803:                                        KFSPropertyConstants.DV_PAYEE_DETAIL
0804:                                                + "."
0805:                                                + KFSPropertyConstants.DISB_VCHR_PAYEE_CITY_NAME,
0806:                                        KFSKeyConstants.ERROR_DV_PAYEE_CITY_NAME);
0807:                    }
0808:                    if (StringUtils.isBlank(document.getDvPayeeDetail()
0809:                            .getDisbVchrPayeeStateCode())) {
0810:                        errors
0811:                                .putError(
0812:                                        KFSPropertyConstants.DV_PAYEE_DETAIL
0813:                                                + "."
0814:                                                + KFSPropertyConstants.DISB_VCHR_PAYEE_STATE_CODE,
0815:                                        KFSKeyConstants.ERROR_DV_PAYEE_STATE_CODE);
0816:                    }
0817:                    if (StringUtils.isBlank(document.getDvPayeeDetail()
0818:                            .getDisbVchrPayeeZipCode())) {
0819:                        errors
0820:                                .putError(
0821:                                        KFSPropertyConstants.DV_PAYEE_DETAIL
0822:                                                + "."
0823:                                                + KFSPropertyConstants.DISB_VCHR_PAYEE_ZIP_CODE,
0824:                                        KFSKeyConstants.ERROR_DV_PAYEE_ZIP_CODE);
0825:                    }
0826:                }
0827:
0828:                /* country required except for employee payees */
0829:                if (!document.getDvPayeeDetail().isEmployee()
0830:                        && StringUtils.isBlank(document.getDvPayeeDetail()
0831:                                .getDisbVchrPayeeCountryCode())) {
0832:                    errors
0833:                            .putError(
0834:                                    KFSPropertyConstants.DV_PAYEE_DETAIL
0835:                                            + "."
0836:                                            + KFSPropertyConstants.DISB_VCHR_PAYEE_COUNTRY_CODE,
0837:                                    KFSKeyConstants.ERROR_REQUIRED,
0838:                                    "Payee Country ");
0839:                }
0840:            }
0841:
0842:            /**
0843:             * Return true if disbursement voucher does not have any notes
0844:             * 
0845:             * @param document submitted disbursement voucher document
0846:             * @return whether the given document has no notes
0847:             */
0848:            private static boolean hasNoNotes(
0849:                    DisbursementVoucherDocument document) {
0850:                // TODO: this is not optimal it shouldn't get it directly from DocHeader revisit later
0851:                return (document.getDocumentHeader().getBoNotes() == null || document
0852:                        .getDocumentHeader().getBoNotes().size() == 0);
0853:            }
0854:
0855:            /**
0856:             * Validates wire transfer tab information
0857:             * 
0858:             * @param document submitted disbursement voucher document
0859:             */
0860:            private void validateWireTransfer(
0861:                    DisbursementVoucherDocument document) {
0862:                ErrorMap errors = GlobalVariables.getErrorMap();
0863:
0864:                errors.addToErrorPath(KFSPropertyConstants.DV_WIRE_TRANSFER);
0865:                SpringContext.getBean(DictionaryValidationService.class)
0866:                        .validateBusinessObject(document.getDvWireTransfer());
0867:
0868:                if (KFSConstants.COUNTRY_CODE_UNITED_STATES.equals(document
0869:                        .getDvWireTransfer().getDisbVchrBankCountryCode())
0870:                        && StringUtils.isBlank(document.getDvWireTransfer()
0871:                                .getDisbVchrBankRoutingNumber())) {
0872:                    errors.putError(
0873:                            KFSPropertyConstants.DISB_VCHR_BANK_ROUTING_NUMBER,
0874:                            KFSKeyConstants.ERROR_DV_BANK_ROUTING_NUMBER);
0875:                }
0876:
0877:                if (KFSConstants.COUNTRY_CODE_UNITED_STATES.equals(document
0878:                        .getDvWireTransfer().getDisbVchrBankCountryCode())
0879:                        && StringUtils.isBlank(document.getDvWireTransfer()
0880:                                .getDisbVchrBankStateCode())) {
0881:                    errors.putError(
0882:                            KFSPropertyConstants.DISB_VCHR_BANK_STATE_CODE,
0883:                            KFSKeyConstants.ERROR_REQUIRED, "Bank State");
0884:                }
0885:
0886:                /* cannot have attachment checked for wire transfer */
0887:                if (document.isDisbVchrAttachmentCode()) {
0888:                    errors
0889:                            .putErrorWithoutFullErrorPath(
0890:                                    KFSPropertyConstants.DOCUMENT
0891:                                            + "."
0892:                                            + KFSPropertyConstants.DISB_VCHR_ATTACHMENT_CODE,
0893:                                    KFSKeyConstants.ERROR_DV_WIRE_ATTACHMENT);
0894:                }
0895:
0896:                errors
0897:                        .removeFromErrorPath(KFSPropertyConstants.DV_WIRE_TRANSFER);
0898:            }
0899:
0900:            /**
0901:             * Validates foreign draft tab information
0902:             * 
0903:             * @param document submitted disbursement voucher document
0904:             */
0905:            private void validateForeignDraft(
0906:                    DisbursementVoucherDocument document) {
0907:                ErrorMap errors = GlobalVariables.getErrorMap();
0908:                errors.addToErrorPath(KFSPropertyConstants.DV_WIRE_TRANSFER);
0909:
0910:                /* currency type code required */
0911:                if (StringUtils.isBlank(document.getDvWireTransfer()
0912:                        .getDisbursementVoucherForeignCurrencyTypeCode())) {
0913:                    GlobalVariables
0914:                            .getErrorMap()
0915:                            .putError(
0916:                                    KFSPropertyConstants.DISB_VCHR_FD_CURRENCY_TYPE_CODE,
0917:                                    KFSKeyConstants.ERROR_DV_CURRENCY_TYPE_CODE);
0918:                }
0919:
0920:                /* currency type name required */
0921:                if (StringUtils.isBlank(document.getDvWireTransfer()
0922:                        .getDisbursementVoucherForeignCurrencyTypeName())) {
0923:                    GlobalVariables
0924:                            .getErrorMap()
0925:                            .putError(
0926:                                    KFSPropertyConstants.DISB_VCHR_FD_CURRENCY_TYPE_NAME,
0927:                                    KFSKeyConstants.ERROR_DV_CURRENCY_TYPE_NAME);
0928:                }
0929:
0930:                errors
0931:                        .removeFromErrorPath(KFSPropertyConstants.DV_WIRE_TRANSFER);
0932:            }
0933:
0934:            /**
0935:             * Validates fields for an alien payment.
0936:             * 
0937:             * @param document submitted disbursement voucher document
0938:             */
0939:            public void validateNonResidentAlienInformation(
0940:                    DisbursementVoucherDocument document) {
0941:                ErrorMap errors = GlobalVariables.getErrorMap();
0942:
0943:                errors
0944:                        .addToErrorPath(KFSPropertyConstants.DV_NON_RESIDENT_ALIEN_TAX);
0945:
0946:                /* income class code required */
0947:                if (StringUtils.isBlank(document.getDvNonResidentAlienTax()
0948:                        .getIncomeClassCode())) {
0949:                    errors.putError(KFSPropertyConstants.INCOME_CLASS_CODE,
0950:                            KFSKeyConstants.ERROR_REQUIRED,
0951:                            "Income class code ");
0952:                } else {
0953:                    /* for foreign source or treaty exempt, non reportable, tax percents must be 0 and gross indicator can not be checked */
0954:                    if (document.getDvNonResidentAlienTax()
0955:                            .isForeignSourceIncomeCode()
0956:                            || document.getDvNonResidentAlienTax()
0957:                                    .isIncomeTaxTreatyExemptCode()
0958:                            || NRA_TAX_INCOME_CLASS_NON_REPORTABLE
0959:                                    .equals(document.getDvNonResidentAlienTax()
0960:                                            .getIncomeClassCode())) {
0961:
0962:                        if ((document.getDvNonResidentAlienTax()
0963:                                .getFederalIncomeTaxPercent() != null && !(new KualiDecimal(
0964:                                0).equals(document.getDvNonResidentAlienTax()
0965:                                .getFederalIncomeTaxPercent())))) {
0966:                            errors
0967:                                    .putError(
0968:                                            KFSPropertyConstants.FEDERAL_INCOME_TAX_PERCENT,
0969:                                            KFSKeyConstants.ERROR_DV_FEDERAL_TAX_NOT_ZERO);
0970:                        }
0971:
0972:                        if ((document.getDvNonResidentAlienTax()
0973:                                .getStateIncomeTaxPercent() != null && !(new KualiDecimal(
0974:                                0).equals(document.getDvNonResidentAlienTax()
0975:                                .getStateIncomeTaxPercent())))) {
0976:                            errors
0977:                                    .putError(
0978:                                            KFSPropertyConstants.STATE_INCOME_TAX_PERCENT,
0979:                                            KFSKeyConstants.ERROR_DV_STATE_TAX_NOT_ZERO);
0980:                        }
0981:
0982:                        if (document.getDvNonResidentAlienTax()
0983:                                .isIncomeTaxGrossUpCode()) {
0984:                            errors
0985:                                    .putError(
0986:                                            KFSPropertyConstants.INCOME_TAX_GROSS_UP_CODE,
0987:                                            KFSKeyConstants.ERROR_DV_GROSS_UP_INDICATOR);
0988:                        }
0989:
0990:                        if (NRA_TAX_INCOME_CLASS_NON_REPORTABLE.equals(document
0991:                                .getDvNonResidentAlienTax()
0992:                                .getIncomeClassCode())
0993:                                && StringUtils.isNotBlank(document
0994:                                        .getDvNonResidentAlienTax()
0995:                                        .getPostalCountryCode())) {
0996:                            errors
0997:                                    .putError(
0998:                                            KFSPropertyConstants.POSTAL_COUNTRY_CODE,
0999:                                            KFSKeyConstants.ERROR_DV_POSTAL_COUNTRY_CODE);
1000:                        }
1001:                    } else {
1002:                        if (document.getDvNonResidentAlienTax()
1003:                                .getFederalIncomeTaxPercent() == null) {
1004:                            errors
1005:                                    .putError(
1006:                                            KFSPropertyConstants.FEDERAL_INCOME_TAX_PERCENT,
1007:                                            KFSKeyConstants.ERROR_REQUIRED,
1008:                                            "Federal tax percent ");
1009:                        } else {
1010:                            // check tax percent is in nra tax pct table for income class code
1011:                            NonResidentAlienTaxPercent taxPercent = new NonResidentAlienTaxPercent();
1012:                            taxPercent.setIncomeClassCode(document
1013:                                    .getDvNonResidentAlienTax()
1014:                                    .getIncomeClassCode());
1015:                            taxPercent
1016:                                    .setIncomeTaxTypeCode(FEDERAL_TAX_TYPE_CODE);
1017:                            taxPercent.setIncomeTaxPercent(document
1018:                                    .getDvNonResidentAlienTax()
1019:                                    .getFederalIncomeTaxPercent());
1020:
1021:                            PersistableBusinessObject retrievedPercent = SpringContext
1022:                                    .getBean(BusinessObjectService.class)
1023:                                    .retrieve(taxPercent);
1024:                            if (retrievedPercent == null) {
1025:                                errors
1026:                                        .putError(
1027:                                                KFSPropertyConstants.FEDERAL_INCOME_TAX_PERCENT,
1028:                                                KFSKeyConstants.ERROR_DV_INVALID_FED_TAX_PERCENT,
1029:                                                new String[] {
1030:                                                        document
1031:                                                                .getDvNonResidentAlienTax()
1032:                                                                .getFederalIncomeTaxPercent()
1033:                                                                .toString(),
1034:                                                        document
1035:                                                                .getDvNonResidentAlienTax()
1036:                                                                .getIncomeClassCode() });
1037:                            }
1038:                        }
1039:
1040:                        if (document.getDvNonResidentAlienTax()
1041:                                .getStateIncomeTaxPercent() == null) {
1042:                            errors
1043:                                    .putError(
1044:                                            KFSPropertyConstants.STATE_INCOME_TAX_PERCENT,
1045:                                            KFSKeyConstants.ERROR_REQUIRED,
1046:                                            "State tax percent ");
1047:                        } else {
1048:                            NonResidentAlienTaxPercent taxPercent = new NonResidentAlienTaxPercent();
1049:                            taxPercent.setIncomeClassCode(document
1050:                                    .getDvNonResidentAlienTax()
1051:                                    .getIncomeClassCode());
1052:                            taxPercent
1053:                                    .setIncomeTaxTypeCode(STATE_TAX_TYPE_CODE);
1054:                            taxPercent.setIncomeTaxPercent(document
1055:                                    .getDvNonResidentAlienTax()
1056:                                    .getStateIncomeTaxPercent());
1057:
1058:                            PersistableBusinessObject retrievedPercent = SpringContext
1059:                                    .getBean(BusinessObjectService.class)
1060:                                    .retrieve(taxPercent);
1061:                            if (retrievedPercent == null) {
1062:                                errors
1063:                                        .putError(
1064:                                                KFSPropertyConstants.STATE_INCOME_TAX_PERCENT,
1065:                                                KFSKeyConstants.ERROR_DV_INVALID_STATE_TAX_PERCENT,
1066:                                                new String[] {
1067:                                                        document
1068:                                                                .getDvNonResidentAlienTax()
1069:                                                                .getStateIncomeTaxPercent()
1070:                                                                .toString(),
1071:                                                        document
1072:                                                                .getDvNonResidentAlienTax()
1073:                                                                .getIncomeClassCode() });
1074:                            }
1075:                        }
1076:                    }
1077:                }
1078:
1079:                /* country code required, unless income type is nonreportable */
1080:                if (StringUtils.isBlank(document.getDvNonResidentAlienTax()
1081:                        .getPostalCountryCode())
1082:                        && !NRA_TAX_INCOME_CLASS_NON_REPORTABLE.equals(document
1083:                                .getDvNonResidentAlienTax()
1084:                                .getIncomeClassCode())) {
1085:                    errors.putError(KFSPropertyConstants.POSTAL_COUNTRY_CODE,
1086:                            KFSKeyConstants.ERROR_REQUIRED, "Country code ");
1087:                }
1088:
1089:                errors
1090:                        .removeFromErrorPath(KFSPropertyConstants.DV_NON_RESIDENT_ALIEN_TAX);
1091:            }
1092:
1093:            /**
1094:             * Validates non employee travel information.
1095:             * 
1096:             * @param document submitted disbursement voucher document
1097:             */
1098:            private void validateNonEmployeeTravel(
1099:                    DisbursementVoucherDocument document) {
1100:                ErrorMap errors = GlobalVariables.getErrorMap();
1101:
1102:                errors
1103:                        .addToErrorPath(KFSPropertyConstants.DV_NON_EMPLOYEE_TRAVEL);
1104:                SpringContext.getBean(DictionaryValidationService.class)
1105:                        .validateBusinessObjectsRecursively(
1106:                                document.getDvNonEmployeeTravel(), 1);
1107:
1108:                /* travel from and to state required if country is us */
1109:                if (KFSConstants.COUNTRY_CODE_UNITED_STATES.equals(document
1110:                        .getDvNonEmployeeTravel().getDvTravelFromCountryCode())
1111:                        && StringUtils.isBlank(document
1112:                                .getDvNonEmployeeTravel()
1113:                                .getDisbVchrTravelFromStateCode())) {
1114:                    errors
1115:                            .putError(
1116:                                    KFSPropertyConstants.DISB_VCHR_TRAVEL_FROM_STATE_CODE,
1117:                                    KFSKeyConstants.ERROR_DV_TRAVEL_FROM_STATE);
1118:                }
1119:                if (KFSConstants.COUNTRY_CODE_UNITED_STATES.equals(document
1120:                        .getDvNonEmployeeTravel()
1121:                        .getDisbVchrTravelToCountryCode())
1122:                        && StringUtils.isBlank(document
1123:                                .getDvNonEmployeeTravel()
1124:                                .getDisbVchrTravelToStateCode())) {
1125:                    errors
1126:                            .putError(
1127:                                    KFSPropertyConstants.DISB_VCHR_TRAVEL_TO_STATE_CODE,
1128:                                    KFSKeyConstants.ERROR_DV_TRAVEL_TO_STATE);
1129:                }
1130:
1131:                if (!errors.isEmpty()) {
1132:                    errors
1133:                            .removeFromErrorPath(KFSPropertyConstants.DV_NON_EMPLOYEE_TRAVEL);
1134:                    return;
1135:                }
1136:
1137:                /* must fill in all required per diem fields if any field is filled in */
1138:                boolean perDiemSectionComplete = validatePerDiemSection(
1139:                        document, errors);
1140:
1141:                /* must fill in all required personal vehicle fields if any field is filled in */
1142:                boolean personalVehicleSectionComplete = validatePersonalVehicleSection(
1143:                        document, errors);
1144:
1145:                /* must have per diem change message if actual amount is different from calculated amount */
1146:                if (perDiemSectionComplete) { // Only validate if per diem section is filled in
1147:                    if (document.getDvNonEmployeeTravel()
1148:                            .getDisbVchrPerdiemCalculatedAmt().compareTo(
1149:                                    document.getDvNonEmployeeTravel()
1150:                                            .getDisbVchrPerdiemActualAmount()) != 0
1151:                            && StringUtils.isBlank(document
1152:                                    .getDvNonEmployeeTravel()
1153:                                    .getDvPerdiemChangeReasonText())) {
1154:                        errors
1155:                                .putError(
1156:                                        KFSPropertyConstants.DV_PERDIEM_CHANGE_REASON_TEXT,
1157:                                        KFSKeyConstants.ERROR_DV_PERDIEM_CHANGE_REQUIRED);
1158:                    }
1159:                }
1160:
1161:                /* make sure per diem fields have not changed since the per diem amount calculation */
1162:                if (perDiemSectionComplete) { // Only validate if per diem section is filled in
1163:                    KualiDecimal calculatedPerDiem = SpringContext.getBean(
1164:                            DisbursementVoucherTravelService.class)
1165:                            .calculatePerDiemAmount(
1166:                                    document.getDvNonEmployeeTravel()
1167:                                            .getDvPerdiemStartDttmStamp(),
1168:                                    document.getDvNonEmployeeTravel()
1169:                                            .getDvPerdiemEndDttmStamp(),
1170:                                    document.getDvNonEmployeeTravel()
1171:                                            .getDisbVchrPerdiemRate());
1172:                    if (calculatedPerDiem.compareTo(document
1173:                            .getDvNonEmployeeTravel()
1174:                            .getDisbVchrPerdiemCalculatedAmt()) != 0) {
1175:                        errors.putErrorWithoutFullErrorPath(
1176:                                KFSConstants.GENERAL_NONEMPLOYEE_TAB_ERRORS,
1177:                                KFSKeyConstants.ERROR_DV_PER_DIEM_CALC_CHANGE);
1178:                    }
1179:                }
1180:
1181:                /* total on non-employee travel must equal Check Total */
1182:                /* if tax has been take out, need to add back in the tax amount for the check */
1183:                KualiDecimal paidAmount = document
1184:                        .getDisbVchrCheckTotalAmount();
1185:                paidAmount = paidAmount.add(SpringContext.getBean(
1186:                        DisbursementVoucherTaxService.class)
1187:                        .getNonResidentAlienTaxAmount(document));
1188:                // Ignore this rule if the DV has been coded for NRA tax, because amounts will not balance after tax coding.
1189:                boolean nraTaxCoded = !"".equalsIgnoreCase(document
1190:                        .getDvNonResidentAlienTax().getIncomeClassCode())
1191:                        && !"N".equalsIgnoreCase(document
1192:                                .getDvNonResidentAlienTax()
1193:                                .getIncomeClassCode());
1194:                if (!nraTaxCoded
1195:                        && paidAmount.compareTo(document
1196:                                .getDvNonEmployeeTravel()
1197:                                .getTotalTravelAmount()) != 0) {
1198:                    errors.putErrorWithoutFullErrorPath(
1199:                            KFSConstants.DV_CHECK_TRAVEL_TOTAL_ERROR,
1200:                            KFSKeyConstants.ERROR_DV_TRAVEL_CHECK_TOTAL);
1201:                }
1202:
1203:                /* make sure mileage fields have not changed since the mileage amount calculation */
1204:                if (personalVehicleSectionComplete) {
1205:                    KualiDecimal currentCalcAmt = document
1206:                            .getDvNonEmployeeTravel()
1207:                            .getDisbVchrMileageCalculatedAmt();
1208:                    KualiDecimal currentActualAmt = document
1209:                            .getDvNonEmployeeTravel()
1210:                            .getDisbVchrPersonalCarAmount();
1211:                    if (ObjectUtils.isNotNull(currentCalcAmt)
1212:                            && ObjectUtils.isNotNull(currentActualAmt)) {
1213:                        KualiDecimal calculatedMileageAmount = SpringContext
1214:                                .getBean(DisbursementVoucherTravelService.class)
1215:                                .calculateMileageAmount(
1216:                                        document
1217:                                                .getDvNonEmployeeTravel()
1218:                                                .getDvPersonalCarMileageAmount(),
1219:                                        document.getDvNonEmployeeTravel()
1220:                                                .getDvPerdiemStartDttmStamp());
1221:                        if (calculatedMileageAmount.compareTo(document
1222:                                .getDvNonEmployeeTravel()
1223:                                .getDisbVchrMileageCalculatedAmt()) != 0) {
1224:                            errors
1225:                                    .putErrorWithoutFullErrorPath(
1226:                                            KFSConstants.GENERAL_NONEMPLOYEE_TAB_ERRORS,
1227:                                            KFSKeyConstants.ERROR_DV_MILEAGE_CALC_CHANGE);
1228:                        }
1229:
1230:                        // determine if the rule is flagged off in the parm setting
1231:                        boolean performTravelMileageLimitInd = getParameterService()
1232:                                .getIndicatorParameter(
1233:                                        DisbursementVoucherDocument.class,
1234:                                        NONEMPLOYEE_TRAVEL_ACTUAL_MILEAGE_LIMIT_PARM_NM);
1235:                        if (performTravelMileageLimitInd) {
1236:                            // if actual amount is greater than calculated amount
1237:                            if (currentCalcAmt.subtract(currentActualAmt)
1238:                                    .isNegative()) {
1239:                                errors
1240:                                        .putError(
1241:                                                KFSPropertyConstants.DV_PERSONAL_CAR_AMOUNT,
1242:                                                KFSKeyConstants.ERROR_DV_ACTUAL_MILEAGE_TOO_HIGH);
1243:                            }
1244:                        }
1245:                    }
1246:                }
1247:
1248:                errors
1249:                        .removeFromErrorPath(KFSPropertyConstants.DV_NON_EMPLOYEE_TRAVEL);
1250:            }
1251:
1252:            /**
1253:             * This method checks to see if the per diem section of the non employee travel tab contains any values. If this section
1254:             * contains any values, the section is validated to ensure that all the required fields for this section are populated.
1255:             * 
1256:             * @param document submitted disbursement voucher document
1257:             * @param errors map containing any generated errors 
1258:             * @return true if per diem section is used by user and that all fields contain values.
1259:             */
1260:            private boolean validatePerDiemSection(
1261:                    DisbursementVoucherDocument document, ErrorMap errors) {
1262:                boolean perDiemSectionComplete = true;
1263:
1264:                // Checks to see if any per diem fields are filled in
1265:                boolean perDiemUsed = StringUtils.isNotBlank(document
1266:                        .getDvNonEmployeeTravel()
1267:                        .getDisbVchrPerdiemCategoryName())
1268:                        || ObjectUtils.isNotNull(document
1269:                                .getDvNonEmployeeTravel()
1270:                                .getDisbVchrPerdiemRate())
1271:                        || ObjectUtils.isNotNull(document
1272:                                .getDvNonEmployeeTravel()
1273:                                .getDisbVchrPerdiemCalculatedAmt())
1274:                        || ObjectUtils.isNotNull(document
1275:                                .getDvNonEmployeeTravel()
1276:                                .getDisbVchrPerdiemActualAmount());
1277:
1278:                // If any per diem fields contain data, validates that all required per diem fields are filled in
1279:                if (perDiemUsed) {
1280:                    if (StringUtils.isBlank(document.getDvNonEmployeeTravel()
1281:                            .getDisbVchrPerdiemCategoryName())) {
1282:                        errors
1283:                                .putError(
1284:                                        KFSPropertyConstants.DISB_VCHR_PERDIEM_CATEGORY_NAME,
1285:                                        KFSKeyConstants.ERROR_DV_PER_DIEM_CATEGORY);
1286:                        perDiemSectionComplete = false;
1287:                    }
1288:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1289:                            .getDisbVchrPerdiemRate())) {
1290:                        errors.putError(
1291:                                KFSPropertyConstants.DISB_VCHR_PERDIEM_RATE,
1292:                                KFSKeyConstants.ERROR_DV_PER_DIEM_RATE);
1293:                        perDiemSectionComplete = false;
1294:                    }
1295:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1296:                            .getDisbVchrPerdiemCalculatedAmt())) {
1297:                        errors
1298:                                .putError(
1299:                                        KFSPropertyConstants.DISB_VCHR_PERDIEM_CALCULATED_AMT,
1300:                                        KFSKeyConstants.ERROR_DV_PER_DIEM_CALC_AMT);
1301:                        perDiemSectionComplete = false;
1302:                    }
1303:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1304:                            .getDisbVchrPerdiemActualAmount())) {
1305:                        errors
1306:                                .putError(
1307:                                        KFSPropertyConstants.DISB_VCHR_PERDIEM_ACTUAL_AMOUNT,
1308:                                        KFSKeyConstants.ERROR_DV_PER_DIEM_ACTUAL_AMT);
1309:                        perDiemSectionComplete = false;
1310:                    }
1311:                }
1312:                perDiemSectionComplete = perDiemSectionComplete && perDiemUsed;
1313:                return perDiemSectionComplete;
1314:            }
1315:
1316:            /**
1317:             * This method checks to see if the per diem section of the non employee travel tab contains any values. If this section
1318:             * contains any values, the section is validated to ensure that all the required fields for this section are populated.
1319:             * 
1320:             * @param document submitted disbursement voucher document
1321:             * @param errors map containing any generated errors 
1322:             * @return true if per diem section is used by user and that all fields contain values.
1323:             */
1324:            private boolean validatePersonalVehicleSection(
1325:                    DisbursementVoucherDocument document, ErrorMap errors) {
1326:                boolean personalVehicleSectionComplete = true;
1327:
1328:                // Checks to see if any per diem fields are filled in
1329:                boolean personalVehilcleUsed = ObjectUtils
1330:                        .isNotNull(document.getDvNonEmployeeTravel()
1331:                                .getDisbVchrAutoFromCityName())
1332:                        || ObjectUtils.isNotNull(document
1333:                                .getDvNonEmployeeTravel()
1334:                                .getDisbVchrAutoFromStateCode())
1335:                        || ObjectUtils.isNotNull(document
1336:                                .getDvNonEmployeeTravel()
1337:                                .getDisbVchrAutoToCityName())
1338:                        || ObjectUtils.isNotNull(document
1339:                                .getDvNonEmployeeTravel()
1340:                                .getDisbVchrAutoToStateCode())
1341:                        || ObjectUtils.isNotNull(document
1342:                                .getDvNonEmployeeTravel()
1343:                                .getDvPersonalCarMileageAmount())
1344:                        || ObjectUtils.isNotNull(document
1345:                                .getDvNonEmployeeTravel()
1346:                                .getDisbVchrMileageCalculatedAmt())
1347:                        || ObjectUtils.isNotNull(document
1348:                                .getDvNonEmployeeTravel()
1349:                                .getDisbVchrPersonalCarAmount());
1350:
1351:                // If any per diem fields contain data, validates that all required per diem fields are filled in
1352:                if (personalVehilcleUsed) {
1353:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1354:                            .getDisbVchrAutoFromCityName())) {
1355:                        errors
1356:                                .putError(
1357:                                        KFSPropertyConstants.DISB_VCHR_AUTO_FROM_CITY_NAME,
1358:                                        KFSKeyConstants.ERROR_DV_AUTO_FROM_CITY);
1359:                        personalVehicleSectionComplete = false;
1360:                    }
1361:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1362:                            .getDisbVchrAutoToCityName())) {
1363:                        errors
1364:                                .putError(
1365:                                        KFSPropertyConstants.DISB_VCHR_AUTO_TO_CITY_NAME,
1366:                                        KFSKeyConstants.ERROR_DV_AUTO_TO_CITY);
1367:                        personalVehicleSectionComplete = false;
1368:                    }
1369:
1370:                    // are state fields required always or only for US travel?
1371:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1372:                            .getDisbVchrAutoFromStateCode())) {
1373:                        errors
1374:                                .putError(
1375:                                        KFSPropertyConstants.DISB_VCHR_AUTO_FROM_STATE_CODE,
1376:                                        KFSKeyConstants.ERROR_DV_AUTO_FROM_STATE);
1377:                        personalVehicleSectionComplete = false;
1378:                    }
1379:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1380:                            .getDisbVchrAutoToStateCode())) {
1381:                        errors
1382:                                .putError(
1383:                                        KFSPropertyConstants.DISB_VCHR_AUTO_TO_STATE_CODE,
1384:                                        KFSKeyConstants.ERROR_DV_AUTO_TO_STATE);
1385:                        personalVehicleSectionComplete = false;
1386:                    }
1387:                    // end state field validation
1388:
1389:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1390:                            .getDvPersonalCarMileageAmount())) {
1391:                        errors
1392:                                .putError(
1393:                                        KFSPropertyConstants.DV_PERSONAL_CAR_MILEAGE_AMOUNT,
1394:                                        KFSKeyConstants.ERROR_DV_MILEAGE_AMT);
1395:                        personalVehicleSectionComplete = false;
1396:                    }
1397:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1398:                            .getDisbVchrMileageCalculatedAmt())) {
1399:                        errors
1400:                                .putError(
1401:                                        KFSPropertyConstants.DISB_VCHR_MILEAGE_CALCULATED_AMT,
1402:                                        KFSKeyConstants.ERROR_DV_MILEAGE_CALC_AMT);
1403:                        personalVehicleSectionComplete = false;
1404:                    }
1405:                    if (ObjectUtils.isNull(document.getDvNonEmployeeTravel()
1406:                            .getDisbVchrPersonalCarAmount())) {
1407:                        errors
1408:                                .putError(
1409:                                        KFSPropertyConstants.DISB_VCHR_PERSONAL_CAR_AMOUNT,
1410:                                        KFSKeyConstants.ERROR_DV_MILEAGE_ACTUAL_AMT);
1411:                        personalVehicleSectionComplete = false;
1412:                    }
1413:                }
1414:                personalVehicleSectionComplete = personalVehicleSectionComplete
1415:                        && personalVehilcleUsed;
1416:                return personalVehicleSectionComplete;
1417:            }
1418:
1419:            /**
1420:             * Validates pre paid travel information.
1421:             * 
1422:             * @param document submitted disbursement voucher document
1423:             */
1424:            private void validatePrePaidTravel(
1425:                    DisbursementVoucherDocument document) {
1426:                ErrorMap errors = GlobalVariables.getErrorMap();
1427:
1428:                errors
1429:                        .addToErrorPath(KFSPropertyConstants.DV_PRE_CONFERENCE_DETAIL);
1430:                SpringContext.getBean(DictionaryValidationService.class)
1431:                        .validateBusinessObjectsRecursively(
1432:                                document.getDvPreConferenceDetail(), 1);
1433:                if (!errors.isEmpty()) {
1434:                    errors
1435:                            .removeFromErrorPath(KFSPropertyConstants.DV_PRE_CONFERENCE_DETAIL);
1436:                    return;
1437:                }
1438:
1439:                /* check conference end date is not before conference start date */
1440:                if (document.getDvPreConferenceDetail()
1441:                        .getDisbVchrConferenceEndDate().compareTo(
1442:                                document.getDvPreConferenceDetail()
1443:                                        .getDisbVchrConferenceStartDate()) < 0) {
1444:                    errors.putError(
1445:                            KFSPropertyConstants.DISB_VCHR_CONFERENCE_END_DATE,
1446:                            KFSKeyConstants.ERROR_DV_CONF_END_DATE);
1447:                }
1448:
1449:                /* total on prepaid travel must equal Check Total */
1450:                /* if tax has been take out, need to add back in the tax amount for the check */
1451:                KualiDecimal paidAmount = document
1452:                        .getDisbVchrCheckTotalAmount();
1453:                paidAmount = paidAmount.add(SpringContext.getBean(
1454:                        DisbursementVoucherTaxService.class)
1455:                        .getNonResidentAlienTaxAmount(document));
1456:                if (paidAmount.compareTo(document.getDvPreConferenceDetail()
1457:                        .getDisbVchrConferenceTotalAmt()) != 0) {
1458:                    errors.putErrorWithoutFullErrorPath(
1459:                            KFSConstants.GENERAL_PREPAID_TAB_ERRORS,
1460:                            KFSKeyConstants.ERROR_DV_PREPAID_CHECK_TOTAL);
1461:                }
1462:
1463:                errors
1464:                        .removeFromErrorPath(KFSPropertyConstants.DV_PRE_CONFERENCE_DETAIL);
1465:            }
1466:
1467:            /**
1468:             * Validates the selected documentation location field.
1469:             * 
1470:             * @param document submitted disbursement voucher document
1471:             */
1472:            private void validateDocumentationLocation(
1473:                    DisbursementVoucherDocument document) {
1474:                String documentationLocationCode = document
1475:                        .getDisbursementVoucherDocumentationLocationCode();
1476:
1477:                if (ObjectUtils.isNotNull(document.getDvPayeeDetail()
1478:                        .getDisbVchrPaymentReasonCode())) {
1479:                    // payment reason restrictions
1480:                    getParameterService()
1481:                            .getParameterEvaluator(
1482:                                    document.getClass(),
1483:                                    DisbursementVoucherRuleConstants.VALID_DOC_LOC_BY_PAYMENT_REASON_PARM,
1484:                                    DisbursementVoucherRuleConstants.INVALID_DOC_LOC_BY_PAYMENT_REASON_PARM,
1485:                                    document.getDvPayeeDetail()
1486:                                            .getDisbVchrPaymentReasonCode(),
1487:                                    documentationLocationCode)
1488:                            .evaluateAndAddError(
1489:                                    document.getClass(),
1490:                                    KFSPropertyConstants.DISBURSEMENT_VOUCHER_DOCUMENTATION_LOCATION_CODE);
1491:                }
1492:
1493:                // alien indicator restrictions
1494:                if (document.getDvPayeeDetail().isDisbVchrAlienPaymentCode()) {
1495:                    getParameterService()
1496:                            .getParameterEvaluator(
1497:                                    DisbursementVoucherDocument.class,
1498:                                    ALIEN_INDICATOR_CHECKED_PARM_NM,
1499:                                    documentationLocationCode)
1500:                            .evaluateAndAddError(
1501:                                    document.getClass(),
1502:                                    KFSPropertyConstants.DISBURSEMENT_VOUCHER_DOCUMENTATION_LOCATION_CODE);
1503:                }
1504:
1505:                // initiator campus code restrictions
1506:                getParameterService()
1507:                        .getParameterEvaluator(
1508:                                DisbursementVoucherDocument.class,
1509:                                DisbursementVoucherRuleConstants.VALID_DOC_LOC_BY_CAMPUS_PARM,
1510:                                DisbursementVoucherRuleConstants.INVALID_DOC_LOC_BY_CAMPUS_PARM,
1511:                                ((ChartUser) getInitiator(document)
1512:                                        .getModuleUser(ChartUser.MODULE_ID))
1513:                                        .getOrganization()
1514:                                        .getOrganizationPhysicalCampusCode(),
1515:                                documentationLocationCode)
1516:                        .evaluateAndAddError(
1517:                                document.getClass(),
1518:                                KFSPropertyConstants.DISBURSEMENT_VOUCHER_DOCUMENTATION_LOCATION_CODE);
1519:            }
1520:
1521:            /**
1522:             * Validates the payment reason is valid with the other document attributes.
1523:             * 
1524:             * @param document submitted disbursement voucher document
1525:             */
1526:            public void validatePaymentReason(
1527:                    DisbursementVoucherDocument document) {
1528:                ErrorMap errors = GlobalVariables.getErrorMap();
1529:                String paymentReasonCode = document.getDvPayeeDetail()
1530:                        .getDisbVchrPaymentReasonCode();
1531:
1532:                // restrictions on payment reason when alien indicator is checked
1533:                if (document.getDvPayeeDetail().isDisbVchrAlienPaymentCode()) {
1534:                    ParameterEvaluator alienPaymentReasonsEvaluator = getParameterService()
1535:                            .getParameterEvaluator(
1536:                                    DisbursementVoucherDocument.class,
1537:                                    ALIEN_PAYMENT_REASONS_PARM_NM,
1538:                                    paymentReasonCode);
1539:                    alienPaymentReasonsEvaluator.evaluateAndAddError(document
1540:                            .getClass(), DV_PAYMENT_REASON_PROPERTY_PATH);
1541:                }
1542:
1543:                // check revolving fund restrictions
1544:                // retrieve revolving fund payment reasons
1545:                ParameterEvaluator revolvingFundPaymentReasonCodeEvaluator = getParameterService()
1546:                        .getParameterEvaluator(
1547:                                DisbursementVoucherDocument.class,
1548:                                REVOLVING_FUND_PAY_REASONS_PARM_NM,
1549:                                paymentReasonCode);
1550:                if (revolvingFundPaymentReasonCodeEvaluator
1551:                        .evaluationSucceeds()
1552:                        && !document.getDvPayeeDetail()
1553:                                .isDvPayeeRevolvingFundCode()
1554:                        && !document.getDvPayeeDetail().isVendor()) {
1555:                    errors.putError(DV_PAYMENT_REASON_PROPERTY_PATH,
1556:                            KFSKeyConstants.ERROR_DV_REVOLVING_PAYMENT_REASON,
1557:                            paymentReasonCode);
1558:                }
1559:
1560:                // if payment reason is moving, payee must be an employee or have payee ownership type I (individual)
1561:                ParameterEvaluator movingPaymentReasonCodeEvaluator = getParameterService()
1562:                        .getParameterEvaluator(
1563:                                DisbursementVoucherDocument.class,
1564:                                MOVING_PAY_REASONS_PARM_NM, paymentReasonCode);
1565:                if (movingPaymentReasonCodeEvaluator.evaluationSucceeds()) {
1566:                    if (!document.getDvPayeeDetail().isEmployee()) {
1567:                        boolean invalidMovingPayee = false;
1568:                        if (document.getDvPayeeDetail().isPayee()) {
1569:                            Payee payee = retrievePayee(document
1570:                                    .getDvPayeeDetail()
1571:                                    .getDisbVchrPayeeIdNumber());
1572:                            // payee must be an individual
1573:                            if (!OWNERSHIP_TYPE_INDIVIDUAL.equals(payee
1574:                                    .getPayeeOwnershipTypCd())) {
1575:                                invalidMovingPayee = true;
1576:                            }
1577:                        } else {
1578:                            // vendors cannot be paid for moving
1579:                            invalidMovingPayee = true;
1580:                        }
1581:
1582:                        if (invalidMovingPayee) {
1583:                            errors
1584:                                    .putError(
1585:                                            DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
1586:                                            KFSKeyConstants.ERROR_DV_MOVING_PAYMENT_PAYEE);
1587:                        }
1588:                    }
1589:                }
1590:
1591:                // for research payments over a certain limit the payee must be a vendor
1592:                ParameterEvaluator researchPaymentReasonCodeEvaluator = getParameterService()
1593:                        .getParameterEvaluator(
1594:                                DisbursementVoucherDocument.class,
1595:                                RESEARCH_PAY_REASONS_PARM_NM, paymentReasonCode);
1596:                if (researchPaymentReasonCodeEvaluator.evaluationSucceeds()) {
1597:                    // check rule is active
1598:                    if (getParameterService().parameterExists(
1599:                            DisbursementVoucherDocument.class,
1600:                            RESEARCH_CHECK_LIMIT_AMOUNT_PARM_NM)
1601:                            && StringUtils
1602:                                    .isNotBlank(getParameterService()
1603:                                            .getParameterValue(
1604:                                                    DisbursementVoucherDocument.class,
1605:                                                    RESEARCH_CHECK_LIMIT_AMOUNT_PARM_NM))) {
1606:                        String researchPayLimit = getParameterService()
1607:                                .getParameterValue(
1608:                                        DisbursementVoucherDocument.class,
1609:                                        RESEARCH_CHECK_LIMIT_AMOUNT_PARM_NM);
1610:                        KualiDecimal payLimit = new KualiDecimal(
1611:                                researchPayLimit);
1612:                        if (document.getDisbVchrCheckTotalAmount()
1613:                                .isGreaterEqual(payLimit)
1614:                                && !document.getDvPayeeDetail().isVendor()) {
1615:                            errors
1616:                                    .putError(
1617:                                            DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
1618:                                            KFSKeyConstants.ERROR_DV_RESEARCH_PAYMENT_PAYEE,
1619:                                            payLimit.toString());
1620:                        }
1621:                    }
1622:                }
1623:            }
1624:
1625:            /**
1626:             * Validates that the payee is not the initiator.
1627:             * 
1628:             * @param document submitted disbursement voucher document
1629:             */
1630:            public void validatePayeeInitiatorID(
1631:                    DisbursementVoucherDocument document) {
1632:                DisbursementVoucherPayeeDetail payeeDetail = document
1633:                        .getDvPayeeDetail();
1634:
1635:                String uuid = "";
1636:                if (payeeDetail.isPayee()
1637:                        && StringUtils.isNotBlank(payeeDetail
1638:                                .getDisbVchrPayeeIdNumber())) {
1639:                    Payee dvPayee = retrievePayee(payeeDetail
1640:                            .getDisbVchrPayeeIdNumber());
1641:                    // if the payee tax type is SSN, then check the tax number
1642:                    if (dvPayee != null
1643:                            && TAX_TYPE_SSN.equals(dvPayee
1644:                                    .getTaxpayerTypeCode())) {
1645:                        // check ssn against employee table
1646:                        UniversalUser user = new UniversalUser();
1647:                        user.setPersonTaxIdentifier(dvPayee.getTaxIdNumber());
1648:                        user = (UniversalUser) SpringContext.getBean(
1649:                                BusinessObjectService.class).retrieve(user);
1650:                        if (user != null) {
1651:                            uuid = user.getPersonUniversalIdentifier();
1652:                        }
1653:                    }
1654:                } else if (payeeDetail.isEmployee()) {
1655:                    // payee id number is uuid
1656:                    uuid = payeeDetail.getDisbVchrPayeeIdNumber();
1657:                }
1658:
1659:                // if a uuid was found, check it against the initiator uuid
1660:                if (StringUtils.isNotBlank(uuid)) {
1661:                    UniversalUser initUser = getInitiator(document);
1662:                    if (uuid.equals(initUser.getPersonUniversalIdentifier())) {
1663:                        GlobalVariables.getErrorMap().putError(
1664:                                DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
1665:                                KFSKeyConstants.ERROR_PAYEE_INITIATOR);
1666:                    }
1667:                }
1668:            }
1669:
1670:            /**
1671:             * Validate attributes of the payee for the document.
1672:             * 
1673:             * @param document submitted disbursement voucher document
1674:             */
1675:            public void validatePayeeInformation(
1676:                    DisbursementVoucherDocument document) {
1677:                DisbursementVoucherPayeeDetail payeeDetail = document
1678:                        .getDvPayeeDetail();
1679:
1680:                if (StringUtils.isBlank(payeeDetail.getDisbVchrPayeeIdNumber())) {
1681:                    return;
1682:                }
1683:
1684:                ErrorMap errors = GlobalVariables.getErrorMap();
1685:
1686:                /* Retrieve Payee */
1687:                Payee dvPayee = retrievePayee(payeeDetail
1688:                        .getDisbVchrPayeeIdNumber());
1689:                if (dvPayee == null) {
1690:                    errors.putError(DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
1691:                            KFSKeyConstants.ERROR_EXISTENCE, "Payee ID ");
1692:                    return;
1693:                }
1694:
1695:                /* DV Payee must be active */
1696:                if (!dvPayee.isPayeeActiveCode()) {
1697:                    errors.putError(DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
1698:                            KFSKeyConstants.ERROR_INACTIVE, "Payee ID ");
1699:                    return;
1700:                }
1701:
1702:                /* check payment reason is allowed for payee type */
1703:                ParameterEvaluator paymentReasonsByTypeEvaluator = getParameterService()
1704:                        .getParameterEvaluator(
1705:                                DisbursementVoucherDocument.class,
1706:                                DisbursementVoucherRuleConstants.VALID_PAYMENT_REASONS_BY_PAYEE_TYPE_PARM,
1707:                                DisbursementVoucherRuleConstants.INVALID_PAYMENT_REASONS_BY_PAYEE_TYPE_PARM,
1708:                                DisbursementVoucherRuleConstants.DV_PAYEE_TYPE_PAYEE,
1709:                                document.getDvPayeeDetail()
1710:                                        .getDisbVchrPaymentReasonCode());
1711:                paymentReasonsByTypeEvaluator.evaluateAndAddError(document
1712:                        .getClass(), DV_PAYMENT_REASON_PROPERTY_PATH);
1713:
1714:                /* for payees with tax type ssn, check employee restrictions */
1715:                if (TAX_TYPE_SSN.equals(dvPayee.getTaxpayerTypeCode())) {
1716:                    if (isActiveEmployeeSSN(dvPayee.getTaxIdNumber())) {
1717:                        // determine if the rule is flagged off in the parm setting
1718:                        boolean performPrepaidEmployeeInd = getParameterService()
1719:                                .getIndicatorParameter(
1720:                                        DisbursementVoucherDocument.class,
1721:                                        PERFORM_PREPAID_EMPL_PARM_NM);
1722:
1723:                        if (performPrepaidEmployeeInd) {
1724:                            /* active payee employees cannot be paid for prepaid travel */
1725:                            ParameterEvaluator travelPrepaidPaymentReasonCodeEvaluator = getParameterService()
1726:                                    .getParameterEvaluator(
1727:                                            DisbursementVoucherDocument.class,
1728:                                            PREPAID_TRAVEL_PAY_REASONS_PARM_NM,
1729:                                            payeeDetail
1730:                                                    .getDisbVchrPaymentReasonCode());
1731:                            if (travelPrepaidPaymentReasonCodeEvaluator
1732:                                    .evaluationSucceeds()) {
1733:                                errors
1734:                                        .putError(
1735:                                                DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
1736:                                                KFSKeyConstants.ERROR_ACTIVE_EMPLOYEE_PREPAID_TRAVEL);
1737:                            }
1738:
1739:                        }
1740:                    } else if (isEmployeeSSN(dvPayee.getTaxIdNumber())) {
1741:                        // check parm setting for paid outside payroll check
1742:                        boolean performPaidOutsidePayrollInd = getParameterService()
1743:                                .getIndicatorParameter(
1744:                                        DisbursementVoucherDocument.class,
1745:                                        DisbursementVoucherRuleConstants.CHECK_EMPLOYEE_PAID_OUTSIDE_PAYROLL_PARM_NM);
1746:
1747:                        if (performPaidOutsidePayrollInd) {
1748:                            /* If payee is type payee and employee, payee record must be flagged as paid outside of payroll */
1749:                            if (!dvPayee.isPayeeEmployeeCode()) {
1750:                                errors
1751:                                        .putError(
1752:                                                DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
1753:                                                KFSKeyConstants.ERROR_EMPLOYEE_PAID_OUTSIDE_PAYROLL);
1754:                            }
1755:                        }
1756:                    }
1757:                }
1758:            }
1759:
1760:            /**
1761:             * Validate attributes of an employee payee for the document.
1762:             * 
1763:             * @param document submitted disbursement voucher document
1764:             */
1765:            public void validateEmployeeInformation(
1766:                    DisbursementVoucherDocument document) {
1767:                DisbursementVoucherPayeeDetail payeeDetail = document
1768:                        .getDvPayeeDetail();
1769:
1770:                if (StringUtils.isBlank(payeeDetail.getDisbVchrPayeeIdNumber())) {
1771:                    return;
1772:                }
1773:
1774:                ErrorMap errors = GlobalVariables.getErrorMap();
1775:
1776:                /* check existence of employee */
1777:                UniversalUser employee = retrieveEmployee(payeeDetail
1778:                        .getDisbVchrPayeeIdNumber());
1779:                if (employee == null) {
1780:                    errors.putError(DV_PAYEE_ID_NUMBER_PROPERTY_PATH,
1781:                            KFSKeyConstants.ERROR_EXISTENCE, "Payee ID ");
1782:                    errors
1783:                            .removeFromErrorPath(KFSPropertyConstants.DV_PAYEE_DETAIL);
1784:                    return;
1785:                }
1786:
1787:                /* check payment reason is allowed for employee type */
1788:                ParameterEvaluator paymentReasonsForPayeeTypeEvaluator = getParameterService()
1789:                        .getParameterEvaluator(
1790:                                DisbursementVoucherDocument.class,
1791:                                DisbursementVoucherRuleConstants.VALID_PAYMENT_REASONS_BY_PAYEE_TYPE_PARM,
1792:                                DisbursementVoucherRuleConstants.INVALID_PAYMENT_REASONS_BY_PAYEE_TYPE_PARM,
1793:                                DisbursementVoucherRuleConstants.DV_PAYEE_TYPE_EMPLOYEE,
1794:                                document.getDvPayeeDetail()
1795:                                        .getDisbVchrPaymentReasonCode());
1796:                paymentReasonsForPayeeTypeEvaluator.evaluateAndAddError(
1797:                        document.getClass(), DV_PAYMENT_REASON_PROPERTY_PATH);
1798:            }
1799:
1800:            /**
1801:             * Validates that there is at least one source accounting line
1802:             * 
1803:             * @param document submitted disbursement voucher document
1804:             */
1805:            private void validateAccountingLineCounts(
1806:                    DisbursementVoucherDocument dvDocument) {
1807:                ErrorMap errors = GlobalVariables.getErrorMap();
1808:
1809:                if (dvDocument.getSourceAccountingLines().size() < 1) {
1810:                    errors.putErrorWithoutFullErrorPath(
1811:                            KFSConstants.ACCOUNTING_LINE_ERRORS,
1812:                            KFSKeyConstants.ERROR_NO_ACCOUNTING_LINES);
1813:                }
1814:            }
1815:
1816:            /**
1817:             * Checks the amounts on the document for reconciliation.
1818:             * 
1819:             * @param document submitted disbursement voucher document
1820:             */
1821:            public void validateDocumentAmounts(
1822:                    DisbursementVoucherDocument document) {
1823:                ErrorMap errors = GlobalVariables.getErrorMap();
1824:
1825:                /* check total cannot be negative or zero */
1826:                if (!document.getDisbVchrCheckTotalAmount().isPositive()) {
1827:                    errors.putError(
1828:                            KFSPropertyConstants.DISB_VCHR_CHECK_TOTAL_AMOUNT,
1829:                            KFSKeyConstants.ERROR_NEGATIVE_OR_ZERO_CHECK_TOTAL);
1830:                }
1831:
1832:                /* total accounting lines cannot be negative */
1833:                if (KFSConstants.ZERO.compareTo(document.getSourceTotal()) == 1) {
1834:                    errors.putErrorWithoutFullErrorPath(
1835:                            KFSConstants.ACCOUNTING_LINE_ERRORS,
1836:                            KFSKeyConstants.ERROR_NEGATIVE_ACCOUNTING_TOTAL);
1837:                }
1838:
1839:                /* total of accounting lines must match check total */
1840:                if (document.getDisbVchrCheckTotalAmount().compareTo(
1841:                        document.getSourceTotal()) != 0) {
1842:                    errors.putErrorWithoutFullErrorPath(
1843:                            KFSConstants.ACCOUNTING_LINE_ERRORS,
1844:                            KFSKeyConstants.ERROR_CHECK_ACCOUNTING_TOTAL);
1845:                }
1846:            }
1847:
1848:            /**
1849:             * Checks object codes restrictions, including restrictions in parameters table.
1850:             * 
1851:             * @param FinancialDocument submitted accounting document
1852:             * @param accountingLine accounting line in accounting document
1853:             * @return true if object code exists, is active, and object level and code exist for a provided payment reason
1854:             */
1855:            public boolean validateObjectCode(
1856:                    AccountingDocument financialDocument,
1857:                    AccountingLine accountingLine) {
1858:                DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) financialDocument;
1859:                ErrorMap errors = GlobalVariables.getErrorMap();
1860:
1861:                String errorKey = KFSPropertyConstants.FINANCIAL_OBJECT_CODE;
1862:                boolean objectCodeAllowed = true;
1863:
1864:                /* object code exist done in super, check we have a valid object */
1865:                if (ObjectUtils.isNull(accountingLine.getObjectCode())) {
1866:                    return false;
1867:                }
1868:
1869:                /* make sure object code is active */
1870:                if (!accountingLine.getObjectCode()
1871:                        .isFinancialObjectActiveCode()) {
1872:                    errors.putError(errorKey, KFSKeyConstants.ERROR_INACTIVE,
1873:                            "object code");
1874:                    objectCodeAllowed = false;
1875:                }
1876:
1877:                String documentPaymentReason = dvDocument.getDvPayeeDetail()
1878:                        .getDisbVchrPaymentReasonCode();
1879:                if (StringUtils.isBlank(documentPaymentReason)) {
1880:                    return objectCodeAllowed;
1881:                }
1882:
1883:                /* check object level is in permitted list for payment reason */
1884:                objectCodeAllowed = objectCodeAllowed
1885:                        && getParameterService()
1886:                                .getParameterEvaluator(
1887:                                        financialDocument.getClass(),
1888:                                        DisbursementVoucherRuleConstants.VALID_OBJ_LEVEL_BY_PAYMENT_REASON_PARM,
1889:                                        DisbursementVoucherRuleConstants.INVALID_OBJ_LEVEL_BY_PAYMENT_REASON_PARM,
1890:                                        documentPaymentReason,
1891:                                        accountingLine.getObjectCode()
1892:                                                .getFinancialObjectLevelCode())
1893:                                .evaluateAndAddError(
1894:                                        SourceAccountingLine.class,
1895:                                        "objectCode.financialObjectLevelCode",
1896:                                        KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
1897:
1898:                /* check object code is in permitted list for payment reason */
1899:                objectCodeAllowed = objectCodeAllowed
1900:                        && getParameterService()
1901:                                .getParameterEvaluator(
1902:                                        financialDocument.getClass(),
1903:                                        DisbursementVoucherRuleConstants.VALID_OBJ_CODE_BY_PAYMENT_REASON_PARM,
1904:                                        DisbursementVoucherRuleConstants.INVALID_OBJ_CODE_BY_PAYMENT_REASON_PARM,
1905:                                        documentPaymentReason,
1906:                                        accountingLine.getFinancialObjectCode())
1907:                                .evaluateAndAddError(
1908:                                        SourceAccountingLine.class,
1909:                                        KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
1910:
1911:                objectCodeAllowed = objectCodeAllowed
1912:                        && getParameterService()
1913:                                .getParameterEvaluator(
1914:                                        financialDocument.getClass(),
1915:                                        DisbursementVoucherRuleConstants.VALID_OBJECT_SUB_TYPES_BY_SUB_FUND_GROUP_PARM,
1916:                                        DisbursementVoucherRuleConstants.INVALID_OBJECT_SUB_TYPES_BY_SUB_FUND_GROUP_PARM,
1917:                                        accountingLine.getAccount()
1918:                                                .getSubFundGroupCode(),
1919:                                        accountingLine
1920:                                                .getObjectCode()
1921:                                                .getFinancialObjectSubTypeCode())
1922:                                .evaluateAndAddError(
1923:                                        SourceAccountingLine.class,
1924:                                        "objectCode.financialObjectSubTypeCode",
1925:                                        KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
1926:                return objectCodeAllowed;
1927:            }
1928:
1929:            /**
1930:             * Checks account number restrictions, including restrictions in parameters table.
1931:             * 
1932:             * @param FinancialDocument submitted financial document
1933:             * @param accountingLine accounting line in submitted accounting document
1934:             * @return true if account exists, falls withing global function code restrictions, and account's sub fund 
1935:             * is in permitted list for payment reason
1936:             */
1937:            public boolean validateAccountNumber(
1938:                    AccountingDocument financialDocument,
1939:                    AccountingLine accountingLine) {
1940:                DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) financialDocument;
1941:                ErrorMap errors = GlobalVariables.getErrorMap();
1942:
1943:                String errorKey = KFSPropertyConstants.ACCOUNT_NUMBER;
1944:                boolean accountNumberAllowed = true;
1945:
1946:                /* account exist and object exist done in super, check we have a valid object */
1947:                if (ObjectUtils.isNull(accountingLine.getAccount())
1948:                        || ObjectUtils.isNull(accountingLine.getObjectCode())) {
1949:                    return false;
1950:                }
1951:
1952:                /* global function code restrictions */
1953:                if (accountNumberAllowed) {
1954:                    ParameterEvaluator evaluator = getParameterService()
1955:                            .getParameterEvaluator(
1956:                                    DisbursementVoucherDocument.class,
1957:                                    FUNCTION_CODE_GLOBAL_RESTRICTION_PARM_NM,
1958:                                    accountingLine.getAccount()
1959:                                            .getFinancialHigherEdFunctionCd());
1960:                    // accountNumberAllowed is true now
1961:                    accountNumberAllowed = evaluator.evaluateAndAddError(
1962:                            SourceAccountingLine.class,
1963:                            "account.financialHigherEdFunctionCd",
1964:                            KFSPropertyConstants.ACCOUNT_NUMBER);
1965:                }
1966:
1967:                String documentPaymentReason = dvDocument.getDvPayeeDetail()
1968:                        .getDisbVchrPaymentReasonCode();
1969:                if (StringUtils.isBlank(documentPaymentReason)) {
1970:                    return accountNumberAllowed;
1971:                }
1972:
1973:                /* check sub fund is in permitted list for payment reason */
1974:                accountNumberAllowed = accountNumberAllowed
1975:                        && getParameterService()
1976:                                .getParameterEvaluator(
1977:                                        financialDocument.getClass(),
1978:                                        DisbursementVoucherRuleConstants.VALID_SUB_FUND_GROUPS_BY_PAYMENT_REASON_PARM,
1979:                                        DisbursementVoucherRuleConstants.INVALID_SUB_FUND_GROUPS_BY_PAYMENT_REASON_PARM,
1980:                                        documentPaymentReason,
1981:                                        accountingLine.getAccount()
1982:                                                .getSubFundGroupCode())
1983:                                .evaluateAndAddError(
1984:                                        SourceAccountingLine.class,
1985:                                        "account.subFundGroupCode",
1986:                                        KFSPropertyConstants.ACCOUNT_NUMBER);
1987:
1988:                return accountNumberAllowed;
1989:            }
1990:
1991:            /**
1992:             * Overrides the parent to return true, because Disbursement Voucher documents only use the SourceAccountingLines data
1993:             * structures. The list that holds TargetAccountingLines should be empty. This will be checked when the document is "routed" or
1994:             * submitted to post - it's called automatically by the parent's processRouteDocument method.
1995:             * 
1996:             * @param financialDocument submitted accounting document
1997:             * @return true
1998:             * 
1999:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isTargetAccountingLinesRequiredNumberForRoutingMet(org.kuali.core.document.FinancialDocument)
2000:             */
2001:            @Override
2002:            protected boolean isTargetAccountingLinesRequiredNumberForRoutingMet(
2003:                    AccountingDocument financialDocument) {
2004:                return true;
2005:            }
2006:
2007:            /**
2008:             * Overrides the parent to return true, because Disbursement Voucher documents do not have to balance in order to be submitted
2009:             * for routing.
2010:             * 
2011:             * @param financialDocument submitted financial document
2012:             * @return true
2013:             */
2014:            @Override
2015:            protected boolean isDocumentBalanceValid(
2016:                    AccountingDocument financialDocument) {
2017:                return true;
2018:            }
2019:
2020:            /**
2021:             * Override to check for tax accounting lines. These lines can have negative amounts which the super will reject.
2022:             * 
2023:             * @param document submitted document
2024:             * @param accountingLine accounting line document
2025:             * @return true if there is no non-resident alien tax provided parent class call to isAmountValid(document, accountingLine) returns true OR
2026:             * if there is a non-resident alien tax provided if accounting line sequence number is included in tax line numbers
2027:             * @see org.kuali.core.rule.AccountingLineRule#isAmountValid(org.kuali.core.document.FinancialDocument,
2028:             *      org.kuali.core.bo.AccountingLine)
2029:             */
2030:            @Override
2031:            public boolean isAmountValid(AccountingDocument document,
2032:                    AccountingLine accountingLine) {
2033:                if (((DisbursementVoucherDocument) document)
2034:                        .getDvNonResidentAlienTax() != null) {
2035:                    List taxLineNumbers = SpringContext
2036:                            .getBean(DisbursementVoucherTaxService.class)
2037:                            .getNRATaxLineNumbers(
2038:                                    ((DisbursementVoucherDocument) document)
2039:                                            .getDvNonResidentAlienTax()
2040:                                            .getFinancialDocumentAccountingLineText());
2041:                    if (taxLineNumbers.contains(accountingLine
2042:                            .getSequenceNumber())) {
2043:                        return true;
2044:                    }
2045:                }
2046:                return super .isAmountValid(document, accountingLine);
2047:            }
2048:
2049:            /**
2050:             * Checks if the current user is a member of the dv tax workgroup.
2051:             * 
2052:             * @return true if user is in group
2053:             */
2054:            private boolean isUserInTaxGroup() {
2055:                if (taxGroupName == null) {
2056:                    taxGroupName = getParameterService().getParameterValue(
2057:                            DisbursementVoucherDocument.class,
2058:                            KFSConstants.FinancialApcParms.DV_TAX_WORKGROUP);
2059:                }
2060:                return GlobalVariables.getUserSession().getUniversalUser()
2061:                        .isMember(taxGroupName);
2062:            }
2063:
2064:            /**
2065:             * Checks if the current user is a member of the dv travel workgroup.
2066:             * 
2067:             * @return true if user is in group
2068:             */
2069:            private boolean isUserInTravelGroup() {
2070:                if (travelGroupName == null) {
2071:                    travelGroupName = getParameterService().getParameterValue(
2072:                            DisbursementVoucherDocument.class,
2073:                            KFSConstants.FinancialApcParms.DV_TRAVEL_WORKGROUP);
2074:                }
2075:                return GlobalVariables.getUserSession().getUniversalUser()
2076:                        .isMember(travelGroupName);
2077:            }
2078:
2079:            /**
2080:             * Checks if the current user is a member of the dv frn workgroup.
2081:             * 
2082:             * @return true if user is in group
2083:             */
2084:            private boolean isUserInFRNGroup() {
2085:                if (frnGroupName == null) {
2086:                    frnGroupName = getParameterService()
2087:                            .getParameterValue(
2088:                                    DisbursementVoucherDocument.class,
2089:                                    KFSConstants.FinancialApcParms.DV_FOREIGNDRAFT_WORKGROUP);
2090:                }
2091:                return GlobalVariables.getUserSession().getUniversalUser()
2092:                        .isMember(frnGroupName);
2093:            }
2094:
2095:            /**
2096:             * Checks if the current user is a member of the dv wire workgroup.
2097:             * 
2098:             * @return true if user is in group
2099:             */
2100:            private boolean isUserInWireGroup() {
2101:                if (wireTransferGroupName == null) {
2102:                    wireTransferGroupName = getParameterService()
2103:                            .getParameterValue(
2104:                                    DisbursementVoucherDocument.class,
2105:                                    KFSConstants.FinancialApcParms.DV_WIRETRANSFER_WORKGROUP);
2106:                }
2107:                return GlobalVariables.getUserSession().getUniversalUser()
2108:                        .isMember(wireTransferGroupName);
2109:            }
2110:
2111:            /**
2112:             * This method checks to see whether the user is in the dv admin group or not.
2113:             * 
2114:             * @return true if user is in group, false otherwise
2115:             */
2116:            private boolean isUserInDvAdminGroup() {
2117:                if (adminGroupName == null) {
2118:                    adminGroupName = getParameterService().getParameterValue(
2119:                            DisbursementVoucherDocument.class,
2120:                            KFSConstants.FinancialApcParms.DV_ADMIN_WORKGROUP);
2121:                }
2122:                return GlobalVariables.getUserSession().getUniversalUser()
2123:                        .isMember(adminGroupName);
2124:            }
2125:
2126:            /**
2127:             * Returns the initiator of the document as a KualiUser
2128:             * 
2129:             * @param document submitted document
2130:             * @return <code>KualiUser</code>
2131:             */
2132:            private UniversalUser getInitiator(AccountingDocument document) {
2133:                UniversalUser initUser = null;
2134:                try {
2135:
2136:                    initUser = SpringContext
2137:                            .getBean(UniversalUserService.class)
2138:                            .getUniversalUser(
2139:                                    new AuthenticationUserId(document
2140:                                            .getDocumentHeader()
2141:                                            .getWorkflowDocument()
2142:                                            .getInitiatorNetworkId()));
2143:                } catch (UserNotFoundException e) {
2144:                    throw new RuntimeException("Document Initiator not found "
2145:                            + e.getMessage());
2146:                }
2147:
2148:                return initUser;
2149:            }
2150:
2151:            /**
2152:             * Retrieves the wire transfer information for the current fiscal year.
2153:             * 
2154:             * @return <code>WireCharge</code>
2155:             */
2156:            private WireCharge retrieveWireCharge() {
2157:                WireCharge wireCharge = new WireCharge();
2158:                wireCharge.setUniversityFiscalYear(SpringContext.getBean(
2159:                        UniversityDateService.class).getCurrentFiscalYear());
2160:
2161:                wireCharge = (WireCharge) SpringContext.getBean(
2162:                        BusinessObjectService.class).retrieve(wireCharge);
2163:                if (wireCharge == null) {
2164:                    LOG
2165:                            .error("Wire charge information not found for current fiscal year.");
2166:                    throw new RuntimeException(
2167:                            "Wire charge information not found for current fiscal year.");
2168:                }
2169:
2170:                return wireCharge;
2171:            }
2172:
2173:            /**
2174:             * Retrieves the Company object from the company name.
2175:             * 
2176:             * @param companyCode company code
2177:             * @param companyName company name
2178:             * @return <code>Payee</code>
2179:             */
2180:            private TravelCompanyCode retrieveCompany(String companyCode,
2181:                    String companyName) {
2182:                TravelCompanyCode travelCompanyCode = new TravelCompanyCode();
2183:                travelCompanyCode.setCode(companyCode);
2184:                travelCompanyCode.setName(companyName);
2185:                return (TravelCompanyCode) SpringContext.getBean(
2186:                        BusinessObjectService.class)
2187:                        .retrieve(travelCompanyCode);
2188:            }
2189:
2190:            /**
2191:             * Retrieves the Payee object from the payee id number.
2192:             * 
2193:             * @param payeeIdNumber payee ID number
2194:             * @return <code>Payee</code>
2195:             */
2196:            private Payee retrievePayee(String payeeIdNumber) {
2197:                Payee payee = new Payee();
2198:                payee.setPayeeIdNumber(payeeIdNumber);
2199:                return (Payee) SpringContext.getBean(
2200:                        BusinessObjectService.class).retrieve(payee);
2201:            }
2202:
2203:            /**
2204:             * Retrieves the UniversalUser object from the uuid.
2205:             * 
2206:             * @param uuid universal user identifier
2207:             * @return <code>UniversalUser</code>
2208:             */
2209:            private UniversalUser retrieveEmployee(String uuid) {
2210:                UniversalUser employee = new UniversalUser();
2211:                employee.setPersonUniversalIdentifier(uuid);
2212:                return (UniversalUser) SpringContext.getBean(
2213:                        BusinessObjectService.class).retrieve(employee);
2214:            }
2215:
2216:            /**
2217:             * Retrieves UniversalUser from SSN
2218:             * @param ssnNumber social security number
2219:             * @return <code>UniversalUser</code>
2220:             */
2221:            private UniversalUser getUniversalUser(String ssnNumber) {
2222:                PersonTaxId personTaxId = new PersonTaxId(ssnNumber);
2223:                UniversalUser user = null;
2224:                try {
2225:                    user = SpringContext.getBean(UniversalUserService.class)
2226:                            .getUniversalUser(personTaxId);
2227:                } catch (UserNotFoundException e) {
2228:                }
2229:                return user;
2230:            }
2231:
2232:            /**
2233:             * Performs a lookup on universal users for the given ssn number.
2234:             * 
2235:             * @param ssnNumber  social security number
2236:             * @return true if the ssn number is a valid employee ssn
2237:             */
2238:            private boolean isEmployeeSSN(String ssnNumber) {
2239:                boolean isEmployee = false;
2240:
2241:                UniversalUser employee = getUniversalUser(ssnNumber);
2242:                if (employee != null) {
2243:                    isEmployee = true;
2244:                }
2245:
2246:                return isEmployee;
2247:            }
2248:
2249:            /**
2250:             * Performs a lookup on universal users for the given ssn number.
2251:             * 
2252:             * @param ssnNumber social security number
2253:             * @return true if the ssn number is a valid employee ssn and the employee is active
2254:             */
2255:            private boolean isActiveEmployeeSSN(String ssnNumber) {
2256:                boolean isActiveEmployee = false;
2257:
2258:                UniversalUser employee = getUniversalUser(ssnNumber);
2259:
2260:                if (employee != null
2261:                        && KFSConstants.EMPLOYEE_ACTIVE_STATUS.equals(employee
2262:                                .getEmployeeStatusCode())) {
2263:                    isActiveEmployee = true;
2264:                }
2265:
2266:                return isActiveEmployee;
2267:            }
2268:
2269:            /**
2270:             * checks the status of the document to see if the coversheet is printable
2271:             * 
2272:             * @param document submitted document
2273:             * @return true if document is not cancelled, initiated, disapproved, exception, or saved
2274:             */
2275:
2276:            public boolean isCoverSheetPrintable(Document document) {
2277:                KualiWorkflowDocument workflowDocument = document
2278:                        .getDocumentHeader().getWorkflowDocument();
2279:
2280:                return !(workflowDocument.stateIsCanceled()
2281:                        || workflowDocument.stateIsInitiated()
2282:                        || workflowDocument.stateIsDisapproved()
2283:                        || workflowDocument.stateIsException()
2284:                        || workflowDocument.stateIsDisapproved() || workflowDocument
2285:                        .stateIsSaved());
2286:
2287:            }
2288:
2289:            /**
2290:             * Rerturns true if accounting line debit
2291:             * 
2292:             * @param financialDocument submitted accounting document
2293:             * @param accountingLine accounting line in accounting document
2294:             * @return true if document is debit
2295:             * @see IsDebitUtils#isDebitConsideringNothingPositiveOnly(FinancialDocumentRuleBase, FinancialDocument, AccountingLine)
2296:             * @see org.kuali.core.rule.AccountingLineRule#isDebit(org.kuali.core.document.FinancialDocument,
2297:             *      org.kuali.core.bo.AccountingLine)
2298:             */
2299:            public boolean isDebit(AccountingDocument financialDocument,
2300:                    AccountingLine accountingLine) {
2301:                // disallow error corrections
2302:                IsDebitUtils.disallowErrorCorrectionDocumentCheck(this ,
2303:                        financialDocument);
2304:                if (financialDocument instanceof  DisbursementVoucherDocument) {
2305:                    // special case - dv NRA tax accounts can be negative, and are debits if positive
2306:                    DisbursementVoucherDocument dvDoc = (DisbursementVoucherDocument) financialDocument;
2307:
2308:                    if (dvDoc.getDvNonResidentAlienTax() != null
2309:                            && dvDoc.getDvNonResidentAlienTax()
2310:                                    .getFinancialDocumentAccountingLineText() != null
2311:                            && dvDoc.getDvNonResidentAlienTax()
2312:                                    .getFinancialDocumentAccountingLineText()
2313:                                    .contains(
2314:                                            accountingLine.getSequenceNumber()
2315:                                                    .toString())) {
2316:                        return accountingLine.getAmount().isPositive();
2317:                    }
2318:                }
2319:
2320:                return IsDebitUtils.isDebitConsideringNothingPositiveOnly(this,
2321:                        financialDocument, accountingLine);
2322:            }
2323:
2324:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.