Source Code Cross Referenced for AuxiliaryVoucherDocumentRule.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.ACCOUNTING_LINE_ERRORS;
0019:        import static org.kuali.kfs.KFSConstants.ACCOUNTING_PERIOD_STATUS_CLOSED;
0020:        import static org.kuali.kfs.KFSConstants.ACCOUNTING_PERIOD_STATUS_CODE_FIELD;
0021:        import static org.kuali.kfs.KFSConstants.AUXILIARY_LINE_HELPER_PROPERTY_NAME;
0022:        import static org.kuali.kfs.KFSConstants.CREDIT_AMOUNT_PROPERTY_NAME;
0023:        import static org.kuali.kfs.KFSConstants.DEBIT_AMOUNT_PROPERTY_NAME;
0024:        import static org.kuali.kfs.KFSConstants.DOCUMENT_ERRORS;
0025:        import static org.kuali.kfs.KFSConstants.GL_CREDIT_CODE;
0026:        import static org.kuali.kfs.KFSConstants.GL_DEBIT_CODE;
0027:        import static org.kuali.kfs.KFSConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME;
0028:        import static org.kuali.kfs.KFSConstants.SQUARE_BRACKET_LEFT;
0029:        import static org.kuali.kfs.KFSConstants.SQUARE_BRACKET_RIGHT;
0030:        import static org.kuali.kfs.KFSConstants.VOUCHER_LINE_HELPER_CREDIT_PROPERTY_NAME;
0031:        import static org.kuali.kfs.KFSConstants.VOUCHER_LINE_HELPER_DEBIT_PROPERTY_NAME;
0032:        import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_PERIOD_CLOSED;
0033:        import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_TWO_PERIODS;
0034:        import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_AV_INCORRECT_FISCAL_YEAR_AVRC;
0035:        import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_AV_INCORRECT_POST_PERIOD_AVRC;
0036:        import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_BALANCE;
0037:        import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_BALANCE_CONSIDERING_CREDIT_AND_DEBIT_AMOUNTS;
0038:        import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_INCORRECT_OBJ_CODE_WITH_SUB_TYPE_OBJ_LEVEL_AND_OBJ_TYPE;
0039:        import static org.kuali.kfs.KFSKeyConstants.ERROR_ZERO_OR_NEGATIVE_AMOUNT;
0040:        import static org.kuali.kfs.KFSKeyConstants.AuxiliaryVoucher.ERROR_ACCOUNTING_PERIOD_OUT_OF_RANGE;
0041:        import static org.kuali.kfs.KFSKeyConstants.AuxiliaryVoucher.ERROR_DIFFERENT_CHARTS;
0042:        import static org.kuali.kfs.KFSKeyConstants.AuxiliaryVoucher.ERROR_DIFFERENT_SUB_FUND_GROUPS;
0043:        import static org.kuali.kfs.KFSKeyConstants.AuxiliaryVoucher.ERROR_INVALID_ACCRUAL_REVERSAL_DATE;
0044:        import static org.kuali.kfs.KFSPropertyConstants.REVERSAL_DATE;
0045:        import static org.kuali.kfs.rules.AccountingDocumentRuleBaseConstants.ERROR_PATH.DOCUMENT_ERROR_PREFIX;
0046:        import static org.kuali.module.financial.rules.AuxiliaryVoucherDocumentRuleConstants.AUXILIARY_VOUCHER_ACCOUNTING_PERIOD_GRACE_PERIOD;
0047:        import static org.kuali.module.financial.rules.AuxiliaryVoucherDocumentRuleConstants.GENERAL_LEDGER_PENDING_ENTRY_OFFSET_CODE;
0048:        import static org.kuali.module.financial.rules.AuxiliaryVoucherDocumentRuleConstants.RESTRICTED_COMBINED_CODES;
0049:        import static org.kuali.module.financial.rules.AuxiliaryVoucherDocumentRuleConstants.RESTRICTED_PERIOD_CODES;
0050:
0051:        import java.sql.Date;
0052:        import java.sql.Timestamp;
0053:        import java.util.List;
0054:
0055:        import org.apache.commons.lang.StringUtils;
0056:        import org.apache.commons.logging.Log;
0057:        import org.apache.commons.logging.LogFactory;
0058:        import org.kuali.core.document.Document;
0059:        import org.kuali.core.exceptions.ValidationException;
0060:        import org.kuali.core.service.DateTimeService;
0061:        import org.kuali.core.service.DocumentTypeService;
0062:        import org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper;
0063:        import org.kuali.core.util.GlobalVariables;
0064:        import org.kuali.core.util.KualiDecimal;
0065:        import org.kuali.core.util.ObjectUtils;
0066:        import org.kuali.kfs.KFSKeyConstants;
0067:        import org.kuali.kfs.KFSPropertyConstants;
0068:        import org.kuali.kfs.bo.AccountingLine;
0069:        import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
0070:        import org.kuali.kfs.bo.Options;
0071:        import org.kuali.kfs.context.SpringContext;
0072:        import org.kuali.kfs.document.AccountingDocument;
0073:        import org.kuali.kfs.rules.AccountingDocumentRuleBase;
0074:        import org.kuali.kfs.service.GeneralLedgerPendingEntryService;
0075:        import org.kuali.kfs.service.OptionsService;
0076:        import org.kuali.kfs.service.ParameterEvaluator;
0077:        import org.kuali.kfs.service.ParameterService;
0078:        import org.kuali.module.chart.bo.AccountingPeriod;
0079:        import org.kuali.module.chart.service.AccountingPeriodService;
0080:        import org.kuali.module.financial.document.AuxiliaryVoucherDocument;
0081:        import org.kuali.module.financial.document.DistributionOfIncomeAndExpenseDocument;
0082:        import org.kuali.module.financial.service.UniversityDateService;
0083:        import org.kuali.module.gl.service.SufficientFundsService;
0084:
0085:        /**
0086:         * Business rule(s) applicable to <code>{@link AuxiliaryVoucherDocument}</code>.
0087:         */
0088:        public class AuxiliaryVoucherDocumentRule extends
0089:                AccountingDocumentRuleBase {
0090:            private static Log LOG = LogFactory
0091:                    .getLog(AuxiliaryVoucherDocumentRule.class);
0092:
0093:            /**
0094:             * Get from APC the offset object code that is used for the <code>{@link GeneralLedgerPendingEntry}</code>
0095:             * 
0096:             * @return String returns GLPE parameter name
0097:             */
0098:            protected String getGeneralLedgerPendingEntryOffsetObjectCode() {
0099:                return GENERAL_LEDGER_PENDING_ENTRY_OFFSET_CODE;
0100:            }
0101:
0102:            /**
0103:             * Returns true if an accounting line is a debit or credit The following are credits (return false)
0104:             * <ol>
0105:             * <li> debitCreditCode != 'D'
0106:             * </ol>
0107:             * the following are debits (return true)
0108:             * <ol>
0109:             * <li> debitCreditCode == 'D'
0110:             * </ol>
0111:             * the following are invalid ( throws an <code>IllegalStateException</code>)
0112:             * <ol>
0113:             * <li> debitCreditCode isBlank
0114:             * </ol>
0115:             * 
0116:             * @param financialDocument submitted accounting document
0117:             * @param accounttingLine accounting line being tested if it is a debit or not
0118:             * @see org.kuali.core.rule.AccountingLineRule#isDebit(org.kuali.core.document.FinancialDocument,
0119:             *      org.kuali.core.bo.AccountingLine)
0120:             */
0121:            public boolean isDebit(AccountingDocument FinancialDocument,
0122:                    AccountingLine accountingLine) throws IllegalStateException {
0123:                String debitCreditCode = accountingLine.getDebitCreditCode();
0124:                if (StringUtils.isBlank(debitCreditCode)) {
0125:                    throw new IllegalStateException(
0126:                            IsDebitUtils.isDebitCalculationIllegalStateExceptionMessage);
0127:                }
0128:                return IsDebitUtils.isDebitCode(debitCreditCode);
0129:            }
0130:
0131:            /**
0132:             * Overrides the parent to display correct error message for a single sided document
0133:             * 
0134:             * @param financialDocument submitted accounting document
0135:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isSourceAccountingLinesRequiredNumberForRoutingMet(org.kuali.core.document.FinancialDocument)
0136:             */
0137:            @Override
0138:            protected boolean isSourceAccountingLinesRequiredNumberForRoutingMet(
0139:                    AccountingDocument financialDocument) {
0140:                if (0 == financialDocument.getSourceAccountingLines().size()) {
0141:                    GlobalVariables
0142:                            .getErrorMap()
0143:                            .putError(
0144:                                    DOCUMENT_ERROR_PREFIX
0145:                                            + KFSPropertyConstants.SOURCE_ACCOUNTING_LINES,
0146:                                    KFSKeyConstants.ERROR_DOCUMENT_SINGLE_SECTION_NO_ACCOUNTING_LINES);
0147:                    return false;
0148:                } else {
0149:                    return true;
0150:                }
0151:            }
0152:
0153:            /**
0154:             * Overrides the parent to return true, because Auxiliary Voucher documents only use the SourceAccountingLines data structures.
0155:             * The list that holds TargetAccountingLines should be empty. This will be checked when the document is "routed" or submitted to
0156:             * post - it's called automatically by the parent's processRouteDocument method.
0157:             * 
0158:             * @param financialDocument submitted accounting document
0159:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isTargetAccountingLinesRequiredNumberForRoutingMet(org.kuali.core.document.FinancialDocument)
0160:             */
0161:            @Override
0162:            protected boolean isTargetAccountingLinesRequiredNumberForRoutingMet(
0163:                    AccountingDocument financialDocument) {
0164:                return true;
0165:            }
0166:
0167:            /**
0168:             * Overrides the parent to return true, because Auxiliary Voucher documents aren't restricted from using any object code. This
0169:             * is part of the "save" check that gets done. This method is called automatically by the parent's processSaveDocument method.
0170:             * 
0171:             * @param documentClass submitted document class (not used in overriden method)
0172:             * @param accountingLine accountingLine where object code is being checked (not used in overriden method)
0173:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isObjectCodeAllowed(org.kuali.core.bo.AccountingLine)
0174:             */
0175:            @Override
0176:            public boolean isObjectCodeAllowed(Class documentClass,
0177:                    AccountingLine accountingLine) {
0178:                return true;
0179:            }
0180:
0181:            /**
0182:             * Accounting lines for Auxiliary Vouchers can only be positive non-zero numbers
0183:             * 
0184:             * @param document submitted AccountingDocument
0185:             * @param accountingLine accountingLine where amount is being validated
0186:             * @return true if amount is NOT 0 or negative
0187:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isAmountValid(org.kuali.core.document.FinancialDocument,
0188:             *      org.kuali.core.bo.AccountingLine)
0189:             */
0190:            @Override
0191:            public boolean isAmountValid(AccountingDocument document,
0192:                    AccountingLine accountingLine) {
0193:                boolean retval = true;
0194:                KualiDecimal amount = accountingLine.getAmount();
0195:
0196:                AuxiliaryVoucherDocument avDoc = (AuxiliaryVoucherDocument) document;
0197:
0198:                // check for negative or zero amounts
0199:                if (KualiDecimal.ZERO.equals(amount)) { // if 0
0200:                    GlobalVariables
0201:                            .getErrorMap()
0202:                            .putErrorWithoutFullErrorPath(
0203:                                    buildErrorMapKeyPathForDebitCreditAmount(true),
0204:                                    ERROR_ZERO_OR_NEGATIVE_AMOUNT,
0205:                                    "an accounting line");
0206:                    GlobalVariables
0207:                            .getErrorMap()
0208:                            .putErrorWithoutFullErrorPath(
0209:                                    buildErrorMapKeyPathForDebitCreditAmount(false),
0210:                                    ERROR_ZERO_OR_NEGATIVE_AMOUNT,
0211:                                    "an accounting line");
0212:
0213:                    retval = false;
0214:                } else if (amount.isNegative()) { // entered a negative number
0215:                    String debitCreditCode = accountingLine
0216:                            .getDebitCreditCode();
0217:                    if (StringUtils.isNotBlank(debitCreditCode)
0218:                            && GL_DEBIT_CODE.equals(debitCreditCode)) {
0219:                        GlobalVariables
0220:                                .getErrorMap()
0221:                                .putErrorWithoutFullErrorPath(
0222:                                        buildErrorMapKeyPathForDebitCreditAmount(true),
0223:                                        ERROR_ZERO_OR_NEGATIVE_AMOUNT,
0224:                                        "an accounting line");
0225:                    } else {
0226:                        GlobalVariables
0227:                                .getErrorMap()
0228:                                .putErrorWithoutFullErrorPath(
0229:                                        buildErrorMapKeyPathForDebitCreditAmount(false),
0230:                                        ERROR_ZERO_OR_NEGATIVE_AMOUNT,
0231:                                        "an accounting line");
0232:                    }
0233:
0234:                    retval = false;
0235:                }
0236:
0237:                return retval;
0238:            }
0239:
0240:            /**
0241:             * This method looks at the current full key path that exists in the ErrorMap structure to determine how to build the error map
0242:             * for the special journal voucher credit and debit fields since they don't conform to the standard pattern of accounting lines.
0243:             * 
0244:             * @param isDebit boolean to determine whether or not value isDebit or not
0245:             * @return String represents error map key to use
0246:             */
0247:            private String buildErrorMapKeyPathForDebitCreditAmount(
0248:                    boolean isDebit) {
0249:                // determine if we are looking at a new line add or an update
0250:                boolean isNewLineAdd = GlobalVariables.getErrorMap()
0251:                        .getErrorPath().contains(
0252:                                NEW_SOURCE_ACCT_LINE_PROPERTY_NAME);
0253:                isNewLineAdd |= GlobalVariables.getErrorMap().getErrorPath()
0254:                        .contains(NEW_SOURCE_ACCT_LINE_PROPERTY_NAME);
0255:
0256:                if (isNewLineAdd) {
0257:                    if (isDebit) {
0258:                        return DEBIT_AMOUNT_PROPERTY_NAME;
0259:                    } else {
0260:                        return CREDIT_AMOUNT_PROPERTY_NAME;
0261:                    }
0262:                } else {
0263:                    String index = StringUtils.substringBetween(GlobalVariables
0264:                            .getErrorMap().getKeyPath("", true),
0265:                            SQUARE_BRACKET_LEFT, SQUARE_BRACKET_RIGHT);
0266:                    String indexWithParams = SQUARE_BRACKET_LEFT + index
0267:                            + SQUARE_BRACKET_RIGHT;
0268:                    if (isDebit) {
0269:                        return AUXILIARY_LINE_HELPER_PROPERTY_NAME
0270:                                + indexWithParams
0271:                                + VOUCHER_LINE_HELPER_DEBIT_PROPERTY_NAME;
0272:                    } else {
0273:                        return AUXILIARY_LINE_HELPER_PROPERTY_NAME
0274:                                + indexWithParams
0275:                                + VOUCHER_LINE_HELPER_CREDIT_PROPERTY_NAME;
0276:                    }
0277:                }
0278:            }
0279:
0280:            /**
0281:             * This method sets the appropriate document type and object type codes into the GLPEs based on the type of AV document chosen.
0282:             * 
0283:             * @param document submitted AccountingDocument
0284:             * @param accountingLine represents accounting line where object type code is retrieved from
0285:             * @param explicitEntry GeneralPendingLedgerEntry object that has its document type, object type, period code, and fiscal year
0286:             *        set
0287:             * @see FinancialDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(FinancialDocument, AccountingLine,
0288:             *      GeneralLedgerPendingEntry)
0289:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processExplicitGeneralLedgerPendingEntry(org.kuali.core.document.FinancialDocument,
0290:             *      org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper, org.kuali.core.bo.AccountingLine,
0291:             *      org.kuali.module.gl.bo.GeneralLedgerPendingEntry)
0292:             */
0293:            protected void customizeExplicitGeneralLedgerPendingEntry(
0294:                    AccountingDocument document, AccountingLine accountingLine,
0295:                    GeneralLedgerPendingEntry explicitEntry) {
0296:                AuxiliaryVoucherDocument auxVoucher = (AuxiliaryVoucherDocument) document;
0297:
0298:                java.sql.Date reversalDate = auxVoucher.getReversalDate();
0299:                if (reversalDate != null) {
0300:                    explicitEntry
0301:                            .setFinancialDocumentReversalDate(reversalDate);
0302:                } else {
0303:                    explicitEntry.setFinancialDocumentReversalDate(null);
0304:                }
0305:                explicitEntry.setFinancialDocumentTypeCode(auxVoucher
0306:                        .getTypeCode()); // make sure to use the accrual type as the document
0307:                // type
0308:                explicitEntry
0309:                        .setFinancialObjectTypeCode(getObjectTypeCode(accountingLine));
0310:                explicitEntry.setUniversityFiscalPeriodCode(auxVoucher
0311:                        .getPostingPeriodCode()); // use chosen posting period code
0312:                explicitEntry.setUniversityFiscalYear(auxVoucher
0313:                        .getPostingYear()); // use chosen posting year
0314:            }
0315:
0316:            /**
0317:             * An Accrual Voucher only generates offsets if it is a recode (AVRC). So this method overrides to do nothing more than return
0318:             * true if it's not a recode. If it is a recode, then it is responsible for generating two offsets with a document type of DI.
0319:             * 
0320:             * @param financialDocument submitted accounting document
0321:             * @param sequenceHelper helper class which will allows us to increment a reference without using an Integer
0322:             * @param accountingLineCopy accounting line from accounting document
0323:             * @param explicitEntry represents explicit entry
0324:             * @param offsetEntry represents offset entry
0325:             * @return true if general ledger pending entry is processed successfully for accurals, adjustments, and recodes
0326:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processOffsetGeneralLedgerPendingEntry(org.kuali.core.document.FinancialDocument,
0327:             *      org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper, org.kuali.core.bo.AccountingLine,
0328:             *      org.kuali.module.gl.bo.GeneralLedgerPendingEntry, org.kuali.module.gl.bo.GeneralLedgerPendingEntry)
0329:             */
0330:            @Override
0331:            protected boolean processOffsetGeneralLedgerPendingEntry(
0332:                    AccountingDocument financialDocument,
0333:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper,
0334:                    AccountingLine accountingLineCopy,
0335:                    GeneralLedgerPendingEntry explicitEntry,
0336:                    GeneralLedgerPendingEntry offsetEntry) {
0337:                AuxiliaryVoucherDocument auxVoucher = (AuxiliaryVoucherDocument) financialDocument;
0338:
0339:                // do not generate an offset entry if this is a normal or adjustment AV type
0340:                if (auxVoucher.isAccrualType() || auxVoucher.isAdjustmentType()) {
0341:                    return processOffsetGeneralLedgerPendingEntryForAccrualsAndAdjustments(
0342:                            financialDocument, sequenceHelper,
0343:                            accountingLineCopy, explicitEntry, offsetEntry);
0344:                } else if (auxVoucher.isRecodeType()) { // recodes generate offsets
0345:                    return processOffsetGeneralLedgerPendingEntryForRecodes(
0346:                            financialDocument, sequenceHelper,
0347:                            accountingLineCopy, explicitEntry, offsetEntry);
0348:                } else {
0349:                    throw new IllegalStateException(
0350:                            "Illegal auxiliary voucher type: "
0351:                                    + auxVoucher.getTypeCode());
0352:                }
0353:            }
0354:
0355:            /**
0356:             * This method handles generating or not generating the appropriate offsets if the AV type is a recode.
0357:             * 
0358:             * @param financialDocument submitted accounting document
0359:             * @param sequenceHelper helper class which will allows us to increment a reference without using an Integer
0360:             * @param accountingLineCopy accounting line from accounting document
0361:             * @param explicitEntry represents explicit entry
0362:             * @param offsetEntry represents offset entry
0363:             * @return true if offset general ledger pending entry is processed
0364:             */
0365:            private boolean processOffsetGeneralLedgerPendingEntryForRecodes(
0366:                    AccountingDocument financialDocument,
0367:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper,
0368:                    AccountingLine accountingLineCopy,
0369:                    GeneralLedgerPendingEntry explicitEntry,
0370:                    GeneralLedgerPendingEntry offsetEntry) {
0371:                // the explicit entry has already been generated and added to the list, so to get the right offset, we have to set the value
0372:                // of the document type code on the explicit
0373:                // to the type code for a DI document so that it gets passed into the next call and we retrieve the right offset definition
0374:                // since these offsets are
0375:                // specific to Distrib. of Income and Expense documents - we need to do a deep copy though so we don't do this by reference
0376:                GeneralLedgerPendingEntry explicitEntryDeepCopy = (GeneralLedgerPendingEntry) ObjectUtils
0377:                        .deepCopy(explicitEntry);
0378:                explicitEntryDeepCopy
0379:                        .setFinancialDocumentTypeCode(SpringContext
0380:                                .getBean(DocumentTypeService.class)
0381:                                .getDocumentTypeCodeByClass(
0382:                                        DistributionOfIncomeAndExpenseDocument.class));
0383:
0384:                // set the posting period to current, because DI GLPEs for recodes should post to the current period
0385:                java.sql.Date today = SpringContext.getBean(
0386:                        DateTimeService.class).getCurrentSqlDateMidnight();
0387:                explicitEntryDeepCopy
0388:                        .setUniversityFiscalPeriodCode(SpringContext.getBean(
0389:                                AccountingPeriodService.class).getByDate(today)
0390:                                .getUniversityFiscalPeriodCode()); // use
0391:                // current
0392:                // period
0393:                // code
0394:
0395:                // call the super to process an offset entry; see the customize method below for AVRC specific attribute values
0396:                // pass in the explicit deep copy
0397:                boolean success = super .processOffsetGeneralLedgerPendingEntry(
0398:                        financialDocument, sequenceHelper, accountingLineCopy,
0399:                        explicitEntryDeepCopy, offsetEntry);
0400:
0401:                // increment the sequence appropriately
0402:                sequenceHelper.increment();
0403:
0404:                // now generate the AVRC DI entry
0405:                // pass in the explicit deep copy
0406:                success &= processAuxiliaryVoucherRecodeDistributionOfIncomeAndExpenseGeneralLedgerPendingEntry(
0407:                        financialDocument, sequenceHelper,
0408:                        explicitEntryDeepCopy);
0409:
0410:                return success;
0411:            }
0412:
0413:            /**
0414:             * This method handles generating or not generating the appropriate offsets if the AV type is accrual or adjustment.
0415:             * 
0416:             * @param financialDocument submitted accounting document
0417:             * @param sequenceHelper helper class which will allows us to increment a reference without using an Integer
0418:             * @param accountingLineCopy accounting line from accounting document
0419:             * @param explicitEntry represents explicit entry
0420:             * @param offsetEntry represents offset entry
0421:             * @return true if offset general ledger pending entry is processed successfully
0422:             */
0423:            private boolean processOffsetGeneralLedgerPendingEntryForAccrualsAndAdjustments(
0424:                    AccountingDocument financialDocument,
0425:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper,
0426:                    AccountingLine accountingLineCopy,
0427:                    GeneralLedgerPendingEntry explicitEntry,
0428:                    GeneralLedgerPendingEntry offsetEntry) {
0429:                boolean success = true;
0430:
0431:                if (isDocumentForMultipleAccounts(financialDocument)) {
0432:                    success &= super .processOffsetGeneralLedgerPendingEntry(
0433:                            financialDocument, sequenceHelper,
0434:                            accountingLineCopy, explicitEntry, offsetEntry);
0435:                } else {
0436:                    sequenceHelper.decrement(); // the parent already increments; b/c it assumes that all documents have offset entries all
0437:                    // of the time
0438:                }
0439:
0440:                return success;
0441:            }
0442:
0443:            /**
0444:             * This method is responsible for iterating through all of the accounting lines in the document (source only) and checking to
0445:             * see if they are all for the same account or not. It recognizes the first account element as the base, and then it iterates
0446:             * through the rest. If it comes across one that doesn't match, then we know it's for multiple accounts.
0447:             * 
0448:             * @param financialDocument submitted accounting document
0449:             * @return true if multiple accounts are being used
0450:             */
0451:            private boolean isDocumentForMultipleAccounts(
0452:                    AccountingDocument financialDocument) {
0453:                String baseAccountNumber = "";
0454:
0455:                int index = 0;
0456:                List<AccountingLine> lines = financialDocument
0457:                        .getSourceAccountingLines();
0458:                for (AccountingLine line : lines) {
0459:                    if (index == 0) {
0460:                        baseAccountNumber = line.getAccountNumber();
0461:                    } else if (!baseAccountNumber.equals(line
0462:                            .getAccountNumber())) {
0463:                        return true;
0464:                    }
0465:                    index++;
0466:                }
0467:
0468:                return false;
0469:            }
0470:
0471:            /**
0472:             * Offset entries are created for recodes (AVRC) always, so this method is one of 2 offsets that get created for an AVRC. Its
0473:             * document type is set to DI. This uses the explicit entry as its model. In addition, an offset is generated for accruals
0474:             * (AVAE) and adjustments (AVAD), but only if the document contains accounting lines for more than one account.
0475:             * 
0476:             * @param financialDocument submitted accounting document
0477:             * @param accountingLine accounting line from accounting document
0478:             * @param explicitEntry represents explicit entry
0479:             * @param offsetEntry represents offset entry
0480:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#customizeOffsetGeneralLedgerPendingEntry(org.kuali.core.document.FinancialDocument,
0481:             *      org.kuali.core.bo.AccountingLine, org.kuali.module.gl.bo.GeneralLedgerPendingEntry,
0482:             *      org.kuali.module.gl.bo.GeneralLedgerPendingEntry)
0483:             */
0484:            protected boolean customizeOffsetGeneralLedgerPendingEntry(
0485:                    AccountingDocument financialDocument,
0486:                    AccountingLine accountingLine,
0487:                    GeneralLedgerPendingEntry explicitEntry,
0488:                    GeneralLedgerPendingEntry offsetEntry) {
0489:                AuxiliaryVoucherDocument auxDoc = (AuxiliaryVoucherDocument) financialDocument;
0490:
0491:                // set the document type to that of a Distrib. Of Income and Expense if it's a recode
0492:                if (auxDoc.isRecodeType()) {
0493:                    offsetEntry
0494:                            .setFinancialDocumentTypeCode(SpringContext
0495:                                    .getBean(DocumentTypeService.class)
0496:                                    .getDocumentTypeCodeByClass(
0497:                                            DistributionOfIncomeAndExpenseDocument.class));
0498:
0499:                    // set the posting period
0500:                    java.sql.Date today = SpringContext.getBean(
0501:                            DateTimeService.class).getCurrentSqlDateMidnight();
0502:                    offsetEntry.setUniversityFiscalPeriodCode(SpringContext
0503:                            .getBean(AccountingPeriodService.class).getByDate(
0504:                                    today).getUniversityFiscalPeriodCode()); // use
0505:                    // current
0506:                    // period
0507:                    // code
0508:                }
0509:
0510:                // now set the offset entry to the specific offset object code for the AV generated offset fund balance; only if it's an
0511:                // accrual or adjustment
0512:                if (auxDoc.isAccrualType() || auxDoc.isAdjustmentType()) {
0513:                    String glpeOffsetObjectCode = SpringContext.getBean(
0514:                            ParameterService.class).getParameterValue(
0515:                            AuxiliaryVoucherDocument.class,
0516:                            getGeneralLedgerPendingEntryOffsetObjectCode());
0517:                    offsetEntry.setFinancialObjectCode(glpeOffsetObjectCode);
0518:
0519:                    // set the posting period
0520:                    offsetEntry.setUniversityFiscalPeriodCode(auxDoc
0521:                            .getPostingPeriodCode()); // use chosen posting period code
0522:                }
0523:
0524:                // set the reversal date to null
0525:                offsetEntry.setFinancialDocumentReversalDate(null);
0526:
0527:                // set the year to current
0528:                offsetEntry.setUniversityFiscalYear(auxDoc.getPostingYear()); // use chosen posting year
0529:
0530:                // although they are offsets, we need to set the offset indicator to false
0531:                offsetEntry.setTransactionEntryOffsetIndicator(false);
0532:
0533:                offsetEntry.refresh(); // may have changed foreign keys here; need accurate object code and account BOs at least
0534:                offsetEntry.setAcctSufficientFundsFinObjCd(SpringContext
0535:                        .getBean(SufficientFundsService.class)
0536:                        .getSufficientFundsObjectCode(
0537:                                offsetEntry.getFinancialObject(),
0538:                                offsetEntry.getAccount()
0539:                                        .getAccountSufficientFundsCode()));
0540:
0541:                return true;
0542:            }
0543:
0544:            /**
0545:             * This method creates an AV recode specific GLPE with a document type of DI. The sequence is managed outside of this method. It
0546:             * uses the explicit entry as its model and then tweaks values appropriately.
0547:             * 
0548:             * @param financialDocument submitted accounting document
0549:             * @param sequenceHelper helper class which will allows us to increment a reference without using an Integer
0550:             * @param explicitEntry represents explicit entry
0551:             * @return true if recode GLPE is added to the financial document successfully
0552:             */
0553:            private boolean processAuxiliaryVoucherRecodeDistributionOfIncomeAndExpenseGeneralLedgerPendingEntry(
0554:                    AccountingDocument financialDocument,
0555:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper,
0556:                    GeneralLedgerPendingEntry explicitEntry) {
0557:                // create a new instance based off of the explicit entry
0558:                GeneralLedgerPendingEntry recodeGlpe = (GeneralLedgerPendingEntry) ObjectUtils
0559:                        .deepCopy(explicitEntry);
0560:
0561:                // set the sequence number according to what was passed in - this is managed external to this method
0562:                recodeGlpe.setTransactionLedgerEntrySequenceNumber(new Integer(
0563:                        sequenceHelper.getSequenceCounter()));
0564:
0565:                // set the document type to that of a Distrib. Of Income and Expense
0566:                recodeGlpe.setFinancialDocumentTypeCode(SpringContext.getBean(
0567:                        DocumentTypeService.class).getDocumentTypeCodeByClass(
0568:                        DistributionOfIncomeAndExpenseDocument.class));
0569:
0570:                // set the object type code base on the value of the explicit entry
0571:                recodeGlpe
0572:                        .setFinancialObjectTypeCode(getObjectTypeCodeForRecodeDistributionOfIncomeAndExpenseEntry(explicitEntry));
0573:
0574:                // set the reversal date to null
0575:                recodeGlpe.setFinancialDocumentReversalDate(null);
0576:
0577:                // although this is an offsets, we need to set the offset indicator to false
0578:                recodeGlpe.setTransactionEntryOffsetIndicator(false);
0579:
0580:                // add the new recode offset entry to the document now
0581:                financialDocument.getGeneralLedgerPendingEntries().add(
0582:                        recodeGlpe);
0583:
0584:                return true;
0585:            }
0586:
0587:            /**
0588:             * This method examines the accounting line passed in and returns the appropriate object type code. This rule converts specific
0589:             * objects types from an object code on an accounting line to more general values. This is specific to the AV document.
0590:             * 
0591:             * @param line accounting line where object type code is retrieved from
0592:             * @return object type from a accounting line ((either financial object type code, financial object type not expenditure code,
0593:             *         or financial object type income not cash code))
0594:             */
0595:            protected String getObjectTypeCode(AccountingLine line) {
0596:                Options options = SpringContext.getBean(OptionsService.class)
0597:                        .getCurrentYearOptions();
0598:                String objectTypeCode = line.getObjectCode()
0599:                        .getFinancialObjectTypeCode();
0600:
0601:                if (options.getFinObjTypeExpenditureexpCd().equals(
0602:                        objectTypeCode)
0603:                        || options.getFinObjTypeExpendNotExpCode().equals(
0604:                                objectTypeCode)) {
0605:                    objectTypeCode = options.getFinObjTypeExpNotExpendCode();
0606:                } else if (options.getFinObjectTypeIncomecashCode().equals(
0607:                        objectTypeCode)
0608:                        || options.getFinObjTypeExpendNotExpCode().equals(
0609:                                objectTypeCode)) {
0610:                    objectTypeCode = options.getFinObjTypeIncomeNotCashCd();
0611:                }
0612:
0613:                return objectTypeCode;
0614:            }
0615:
0616:            /**
0617:             * This method examines the explicit entry's object type and returns the appropriate object type code. This is specific to AV
0618:             * recodes (AVRCs).
0619:             * 
0620:             * @param explicitEntry
0621:             * @return object type code from explicit entry (either financial object type code, financial object type expenditure code, or
0622:             *         financial object type income cash code)
0623:             */
0624:            protected String getObjectTypeCodeForRecodeDistributionOfIncomeAndExpenseEntry(
0625:                    GeneralLedgerPendingEntry explicitEntry) {
0626:                Options options = SpringContext.getBean(OptionsService.class)
0627:                        .getCurrentYearOptions();
0628:                String objectTypeCode = explicitEntry
0629:                        .getFinancialObjectTypeCode();
0630:
0631:                if (options.getFinObjTypeExpNotExpendCode().equals(
0632:                        objectTypeCode)) {
0633:                    objectTypeCode = options.getFinObjTypeExpenditureexpCd();
0634:                } else if (options.getFinObjTypeIncomeNotCashCd().equals(
0635:                        objectTypeCode)) {
0636:                    objectTypeCode = options.getFinObjectTypeIncomecashCode();
0637:                }
0638:
0639:                return objectTypeCode;
0640:            }
0641:
0642:            /**
0643:             * Validates added accounting line. Override calls parent method and also checks whether or not the document and line have a
0644:             * valid sub object and object level
0645:             * 
0646:             * @param document submitted accounting document
0647:             * @param accountingLine validated accounting line from accounting document
0648:             * @return return true if accounting line is valid
0649:             * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomAddAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
0650:             *      org.kuali.core.bo.AccountingLine)
0651:             */
0652:            @Override
0653:            public boolean processCustomAddAccountingLineBusinessRules(
0654:                    AccountingDocument document, AccountingLine accountingLine) {
0655:                boolean valid = super 
0656:                        .processCustomAddAccountingLineBusinessRules(document,
0657:                                accountingLine);
0658:
0659:                if (valid) {
0660:                    buildAccountingLineObjectType(accountingLine);
0661:                    valid &= isValidDocWithSubAndLevel(document, accountingLine);
0662:                }
0663:
0664:                return valid;
0665:            }
0666:
0667:            /**
0668:             * Validates reviewed accounting line. Override calls parent method and also checks whether or not the document and line have a
0669:             * valid sub object and object level
0670:             * 
0671:             * @param document submitted accounting document
0672:             * @param accountingLine validated accounting line from accounting document
0673:             * @return return true if accounting line is valid
0674:             * @see FinancialDocumentRuleBase#processCustomReviewAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
0675:             *      org.kuali.core.bo.AccountingLine)
0676:             */
0677:            @Override
0678:            public boolean processCustomReviewAccountingLineBusinessRules(
0679:                    AccountingDocument document, AccountingLine accountingLine) {
0680:                boolean valid = true;
0681:                valid &= super .processCustomReviewAccountingLineBusinessRules(
0682:                        document, accountingLine);
0683:                if (valid) {
0684:                    buildAccountingLineObjectType(accountingLine);
0685:                    valid &= isValidDocWithSubAndLevel(document, accountingLine);
0686:                }
0687:                return valid;
0688:            }
0689:
0690:            /**
0691:             * This method performs common validation for Transactional Document routes. Note the rule framework will handle validating all
0692:             * of the accounting lines and also those checks that would normally be done on a save, automatically for us.<br/> <br/>
0693:             * <code>{@link AuxiliaryVoucherDocument}</code> is different from other <code>{@link Document}</code> instances because it
0694:             * requires all <code>{@link AccountingLine}</code> instances belong to the same Fund Group. That's done here by iterating
0695:             * through the <code>{@link AccountingLine}</code> instances.
0696:             * 
0697:             * @param document submitted document
0698:             * @see FinancialDocumentRuleBase#processCustomRouteDocumentBusinessRules(Document)
0699:             */
0700:            @Override
0701:            protected boolean processCustomRouteDocumentBusinessRules(
0702:                    Document document) {
0703:                boolean valid = super 
0704:                        .processCustomRouteDocumentBusinessRules(document);
0705:                AuxiliaryVoucherDocument avDoc = (AuxiliaryVoucherDocument) document;
0706:
0707:                if (valid) {
0708:                    valid = isPeriodAllowed(avDoc);
0709:                }
0710:
0711:                // make sure that a single chart is used for all accounting lines in the document
0712:                if (valid) {
0713:                    valid = isSingleChartUsed((AccountingDocument) document);
0714:                }
0715:
0716:                // make sure that a single sub fund group is used for all accounting lines in the document
0717:                if (valid) {
0718:                    valid = isSingleSubFundGroupUsed((AccountingDocument) document);
0719:                }
0720:
0721:                // make sure that a reversal date is entered for accruals
0722:                if (valid) {
0723:                    valid = isValidReversalDate((AuxiliaryVoucherDocument) document);
0724:                }
0725:
0726:                return valid;
0727:            }
0728:
0729:            /**
0730:             * Iterates <code>{@link AccountingLine}</code> instances in a given <code>{@link FinancialDocument}</code> instance and
0731:             * compares them to see if they are all in the same Chart.
0732:             * 
0733:             * @param document submitted document
0734:             * @return true if only one chart of accounts code is used in a document's source accounting lines
0735:             */
0736:            protected boolean isSingleChartUsed(AccountingDocument document) {
0737:                boolean valid = true;
0738:
0739:                String baseChartCode = null;
0740:                int index = 0;
0741:
0742:                List<AccountingLine> lines = document
0743:                        .getSourceAccountingLines();
0744:                for (AccountingLine line : lines) {
0745:                    if (index == 0) {
0746:                        baseChartCode = line.getChartOfAccountsCode();
0747:                    } else {
0748:                        String currentChartCode = line.getChartOfAccountsCode();
0749:                        if (!currentChartCode.equals(baseChartCode)) {
0750:                            reportError(ACCOUNTING_LINE_ERRORS,
0751:                                    ERROR_DIFFERENT_CHARTS);
0752:                            return false;
0753:                        }
0754:                    }
0755:                    index++;
0756:                }
0757:                return true;
0758:            }
0759:
0760:            /**
0761:             * Iterates <code>{@link AccountingLine}</code> instances in a given <code>{@link FinancialDocument}</code> instance and
0762:             * compares them to see if they are all in the same Sub-Fund Group.
0763:             * 
0764:             * @param document submitted document
0765:             * @return true if only one sub fund group code is used in a document's source accounting lines
0766:             */
0767:            protected boolean isSingleSubFundGroupUsed(
0768:                    AccountingDocument document) {
0769:                boolean valid = true;
0770:
0771:                String baseSubFundGroupCode = null;
0772:                int index = 0;
0773:
0774:                List<AccountingLine> lines = document
0775:                        .getSourceAccountingLines();
0776:                for (AccountingLine line : lines) {
0777:                    if (index == 0) {
0778:                        baseSubFundGroupCode = line.getAccount()
0779:                                .getSubFundGroupCode();
0780:                    } else {
0781:                        String currentSubFundGroup = line.getAccount()
0782:                                .getSubFundGroupCode();
0783:                        if (!currentSubFundGroup.equals(baseSubFundGroupCode)) {
0784:                            reportError(ACCOUNTING_LINE_ERRORS,
0785:                                    ERROR_DIFFERENT_SUB_FUND_GROUPS);
0786:                            return false;
0787:                        }
0788:                    }
0789:                    index++;
0790:                }
0791:                return true;
0792:            }
0793:
0794:            /**
0795:             * This method verifies that the user entered a reversal date, but only if it's an accrual.
0796:             * 
0797:             * @param document submitted document
0798:             * @return returns true if document is NOT an accrual type OR has a reversal date
0799:             */
0800:            protected boolean isValidReversalDate(
0801:                    AuxiliaryVoucherDocument document) {
0802:                if (document.isAccrualType()
0803:                        && document.getReversalDate() == null) {
0804:                    reportError(REVERSAL_DATE,
0805:                            ERROR_INVALID_ACCRUAL_REVERSAL_DATE);
0806:                    return false;
0807:                }
0808:
0809:                return true;
0810:            }
0811:
0812:            /**
0813:             * Overrides the parent implementation to sum all of the debit GLPEs up and sum all of the credit GLPEs up and then compare the
0814:             * totals to each other, returning true if they are equal and false if they are not. The difference is that we ignore any DI
0815:             * specific entries because while these are offsets, their offset indicators do not show this, so they would be counted in the
0816:             * balancing and we don't want that. Added a check for simple balance between credit and debit values as entered on the
0817:             * accountingLines, since that is also a requirement.
0818:             * 
0819:             * @param financialDocument submitted accounting document
0820:             * @return true if a document's accounting lines credit/debit lines are in balance and a document's non-DI credit and debit
0821:             *         GLPEs are also in balance
0822:             */
0823:            @Override
0824:            protected boolean isDocumentBalanceValidConsideringDebitsAndCredits(
0825:                    AccountingDocument finanacialDocument) {
0826:                AuxiliaryVoucherDocument avDoc = (AuxiliaryVoucherDocument) finanacialDocument;
0827:
0828:                return accountingLinesBalance(avDoc) && glpesBalance(avDoc);
0829:            }
0830:
0831:            /**
0832:             * Returns true if credit/debit entries are in balance
0833:             * 
0834:             * @param avDoc submitted AuxiliaryVoucherDocument
0835:             * @return true if the credit and debit entries from all accountingLines for the given document are in balance
0836:             */
0837:            private boolean accountingLinesBalance(
0838:                    AuxiliaryVoucherDocument avDoc) {
0839:                KualiDecimal creditAmount = avDoc.getCreditTotal();
0840:                KualiDecimal debitAmount = avDoc.getDebitTotal();
0841:
0842:                boolean balanced = debitAmount.equals(creditAmount);
0843:                if (!balanced) {
0844:                    String errorParams[] = { creditAmount.toString(),
0845:                            debitAmount.toString() };
0846:                    reportError(
0847:                            ACCOUNTING_LINE_ERRORS,
0848:                            ERROR_DOCUMENT_BALANCE_CONSIDERING_CREDIT_AND_DEBIT_AMOUNTS,
0849:                            errorParams);
0850:                }
0851:                return balanced;
0852:            }
0853:
0854:            /**
0855:             * Returns true if the explicit, non-DI credit and debit GLPEs derived from the document's accountingLines are in balance
0856:             * 
0857:             * @param avDoc submitted AuxiliaryVoucherDocument
0858:             * @return true if the explicit, non-DI credit and debit GLPEs derived from the document's accountingLines are in balance
0859:             */
0860:            private boolean glpesBalance(AuxiliaryVoucherDocument avDoc) {
0861:                // generate GLPEs specifically here so that we can compare debits to credits
0862:                if (!SpringContext.getBean(
0863:                        GeneralLedgerPendingEntryService.class)
0864:                        .generateGeneralLedgerPendingEntries(avDoc)) {
0865:                    throw new ValidationException(
0866:                            "general ledger GLPE generation failed");
0867:                }
0868:
0869:                // now loop through all of the GLPEs and calculate buckets for debits and credits
0870:                KualiDecimal creditAmount = new KualiDecimal(0);
0871:                KualiDecimal debitAmount = new KualiDecimal(0);
0872:
0873:                for (GeneralLedgerPendingEntry glpe : avDoc
0874:                        .getGeneralLedgerPendingEntries()) {
0875:                    // make sure we are looking at only the explicit entries that aren't DI types
0876:                    if (!glpe.isTransactionEntryOffsetIndicator()
0877:                            && !glpe
0878:                                    .getFinancialDocumentTypeCode()
0879:                                    .equals(
0880:                                            SpringContext
0881:                                                    .getBean(
0882:                                                            DocumentTypeService.class)
0883:                                                    .getDocumentTypeCodeByClass(
0884:                                                            DistributionOfIncomeAndExpenseDocument.class))) {
0885:                        if (GL_CREDIT_CODE.equals(glpe
0886:                                .getTransactionDebitCreditCode())) {
0887:                            creditAmount = creditAmount.add(glpe
0888:                                    .getTransactionLedgerEntryAmount());
0889:                        } else { // DEBIT
0890:                            debitAmount = debitAmount.add(glpe
0891:                                    .getTransactionLedgerEntryAmount());
0892:                        }
0893:                    }
0894:                }
0895:
0896:                boolean balanced = debitAmount.equals(creditAmount);
0897:                if (!balanced) {
0898:                    String errorParams[] = { creditAmount.toString(),
0899:                            debitAmount.toString() };
0900:                    reportError(ACCOUNTING_LINE_ERRORS, ERROR_DOCUMENT_BALANCE,
0901:                            errorParams);
0902:                }
0903:                return balanced;
0904:            }
0905:
0906:            /**
0907:             * Fixes <code>{@link ObjectType}</code> for the given <code>{@link AccountingLine}</code> instance
0908:             * 
0909:             * @param line accounting line
0910:             */
0911:            private void buildAccountingLineObjectType(AccountingLine line) {
0912:                String objectTypeCode = line.getObjectCode()
0913:                        .getFinancialObjectTypeCode();
0914:                line.setObjectTypeCode(objectTypeCode);
0915:                line.refresh();
0916:            }
0917:
0918:            /**
0919:             * This method checks to see if there is a valid combination of sub type and object level
0920:             * 
0921:             * @param document submitted accounting document
0922:             * @param accountingLine validated accounting line
0923:             * @return return true if line contains a valid combination of object sub type and object level
0924:             */
0925:            private boolean isValidDocWithSubAndLevel(
0926:                    AccountingDocument document, AccountingLine accountingLine) {
0927:                boolean retval = true;
0928:
0929:                StringBuffer combinedCodes = new StringBuffer(accountingLine
0930:                        .getObjectType().getCode()).append(',').append(
0931:                        accountingLine.getObjectCode()
0932:                                .getFinancialObjectSubType().getCode()).append(
0933:                        ',').append(
0934:                        accountingLine.getObjectCode()
0935:                                .getFinancialObjectLevel()
0936:                                .getFinancialObjectLevelCode());
0937:                ParameterEvaluator evalutator = SpringContext.getBean(
0938:                        ParameterService.class).getParameterEvaluator(
0939:                        AuxiliaryVoucherDocument.class,
0940:                        RESTRICTED_COMBINED_CODES);
0941:
0942:                retval = !evalutator.equals(combinedCodes.toString());
0943:
0944:                if (!retval) {
0945:                    String errorObjects[] = {
0946:                            accountingLine.getObjectCode()
0947:                                    .getFinancialObjectCode(),
0948:                            accountingLine.getObjectCode()
0949:                                    .getFinancialObjectLevel()
0950:                                    .getFinancialObjectLevelCode(),
0951:                            accountingLine.getObjectCode()
0952:                                    .getFinancialObjectSubType().getCode(),
0953:                            accountingLine.getObjectType().getCode() };
0954:                    reportError(
0955:                            ACCOUNTING_LINE_ERRORS,
0956:                            ERROR_DOCUMENT_INCORRECT_OBJ_CODE_WITH_SUB_TYPE_OBJ_LEVEL_AND_OBJ_TYPE,
0957:                            errorObjects);
0958:                }
0959:
0960:                return retval;
0961:            }
0962:
0963:            /**
0964:             * This method determines if the posting period is valid for the document type.
0965:             * 
0966:             * @param document submitted AuxiliaryVoucherDocument
0967:             * @return true if it is a valid period for posting into
0968:             */
0969:            protected boolean isPeriodAllowed(AuxiliaryVoucherDocument document) {
0970:                /*
0971:                 * Nota bene: a full summarization of these rules can be found in the comments to KULRNE-4634
0972:                 */
0973:                // first we need to get the period itself to check these things
0974:                boolean valid = true;
0975:                AccountingPeriod acctPeriod = SpringContext.getBean(
0976:                        AccountingPeriodService.class).getByPeriod(
0977:                        document.getPostingPeriodCode(),
0978:                        document.getPostingYear());
0979:
0980:                valid = SpringContext.getBean(ParameterService.class)
0981:                        .getParameterEvaluator(AuxiliaryVoucherDocument.class,
0982:                                RESTRICTED_PERIOD_CODES,
0983:                                document.getPostingPeriodCode())
0984:                        .evaluationSucceeds();
0985:                if (!valid) {
0986:                    reportError(ACCOUNTING_PERIOD_STATUS_CODE_FIELD,
0987:                            ERROR_ACCOUNTING_PERIOD_OUT_OF_RANGE);
0988:                }
0989:
0990:                // can't post into a closed period
0991:                if (acctPeriod == null
0992:                        || acctPeriod.getUniversityFiscalPeriodStatusCode()
0993:                                .equalsIgnoreCase(
0994:                                        ACCOUNTING_PERIOD_STATUS_CLOSED)) {
0995:                    reportError(DOCUMENT_ERRORS,
0996:                            ERROR_DOCUMENT_ACCOUNTING_PERIOD_CLOSED);
0997:                    return false;
0998:                }
0999:
1000:                Timestamp ts = new Timestamp(new java.util.Date().getTime());
1001:                AccountingPeriod currPeriod = SpringContext.getBean(
1002:                        AccountingPeriodService.class).getByDate(
1003:                        new Date(ts.getTime()));
1004:
1005:                if (acctPeriod.getUniversityFiscalYear().equals(
1006:                        SpringContext.getBean(UniversityDateService.class)
1007:                                .getCurrentFiscalYear())) {
1008:                    if (SpringContext.getBean(AccountingPeriodService.class)
1009:                            .compareAccountingPeriodsByDate(acctPeriod,
1010:                                    currPeriod) < 0) {
1011:                        // we've only got problems if the av's accounting period is earlier than now
1012:
1013:                        // are we in the grace period for this accounting period?
1014:                        if (!AuxiliaryVoucherDocumentRule
1015:                                .calculateIfWithinGracePeriod(new Date(ts
1016:                                        .getTime()), acctPeriod)) {
1017:                            reportError(DOCUMENT_ERRORS,
1018:                                    ERROR_DOCUMENT_ACCOUNTING_TWO_PERIODS);
1019:                            return false;
1020:                        }
1021:                    }
1022:                } else {
1023:                    // it's not the same fiscal year, so we need to test whether we are currently
1024:                    // in the grace period of the acctPeriod
1025:                    if (!AuxiliaryVoucherDocumentRule
1026:                            .calculateIfWithinGracePeriod(
1027:                                    new Date(ts.getTime()), acctPeriod)
1028:                            && AuxiliaryVoucherDocumentRule
1029:                                    .isEndOfPreviousFiscalYear(acctPeriod)) {
1030:                        reportError(DOCUMENT_ERRORS,
1031:                                ERROR_DOCUMENT_ACCOUNTING_TWO_PERIODS);
1032:                        return false;
1033:                    }
1034:                }
1035:
1036:                boolean numericPeriod = true;
1037:                Integer period = null;
1038:                try {
1039:                    period = new Integer(document.getPostingPeriodCode());
1040:                } catch (NumberFormatException nfe) {
1041:                    numericPeriod = false;
1042:                }
1043:                Integer year = document.getPostingYear();
1044:
1045:                // check for specific posting issues
1046:                if (document.isRecodeType()) {
1047:                    // can't post into a previous fiscal year
1048:                    Integer currFiscalYear = currPeriod
1049:                            .getUniversityFiscalYear();
1050:                    if (currFiscalYear > year) {
1051:                        reportError(DOCUMENT_ERRORS,
1052:                                ERROR_DOCUMENT_AV_INCORRECT_FISCAL_YEAR_AVRC);
1053:                        return false;
1054:                    }
1055:                    if (numericPeriod) {
1056:                        // check the posting period, throw out if period 13
1057:                        if (period > 12) {
1058:                            reportError(DOCUMENT_ERRORS,
1059:                                    ERROR_DOCUMENT_AV_INCORRECT_POST_PERIOD_AVRC);
1060:                            return false;
1061:                        } else if (period < 1) {
1062:                            reportError(DOCUMENT_ERRORS,
1063:                                    ERROR_ACCOUNTING_PERIOD_OUT_OF_RANGE);
1064:                            return false;
1065:                        }
1066:                    } else {
1067:                        // not a numeric period and this is a recode? Then we won't allow it; ref KULRNE-6001
1068:                        reportError(DOCUMENT_ERRORS,
1069:                                ERROR_DOCUMENT_AV_INCORRECT_POST_PERIOD_AVRC);
1070:                        return false;
1071:                    }
1072:                }
1073:                return valid;
1074:            }
1075:
1076:            /**
1077:             * This method checks if a given moment of time is within an accounting period, or its auxiliary voucher grace period.
1078:             * 
1079:             * @param today a date to check if it is within the period
1080:             * @param periodToCheck the account period to check against
1081:             * @return true if a given moment in time is within an accounting period or an auxiliary voucher grace period
1082:             */
1083:            public static boolean calculateIfWithinGracePeriod(Date today,
1084:                    AccountingPeriod periodToCheck) {
1085:                boolean result = false;
1086:                int todayAsComparableDate = AuxiliaryVoucherDocumentRule
1087:                        .comparableDateForm(today);
1088:                int periodClose = new Integer(AuxiliaryVoucherDocumentRule
1089:                        .comparableDateForm(periodToCheck
1090:                                .getUniversityFiscalPeriodEndDate()));
1091:                int periodBegin = AuxiliaryVoucherDocumentRule
1092:                        .comparableDateForm(AuxiliaryVoucherDocumentRule
1093:                                .calculateFirstDayOfMonth(periodToCheck
1094:                                        .getUniversityFiscalPeriodEndDate()));
1095:                int gracePeriodClose = periodClose
1096:                        + new Integer(
1097:                                SpringContext
1098:                                        .getBean(ParameterService.class)
1099:                                        .getParameterValue(
1100:                                                AuxiliaryVoucherDocument.class,
1101:                                                AUXILIARY_VOUCHER_ACCOUNTING_PERIOD_GRACE_PERIOD))
1102:                                .intValue();
1103:                return (todayAsComparableDate >= periodBegin && todayAsComparableDate <= gracePeriodClose);
1104:            }
1105:
1106:            /**
1107:             * This method returns a date as an approximate count of days since the BCE epoch.
1108:             * 
1109:             * @param d the date to convert
1110:             * @return an integer count of days, very approximate
1111:             */
1112:            public static int comparableDateForm(Date d) {
1113:                java.util.Calendar cal = new java.util.GregorianCalendar();
1114:                cal.setTime(d);
1115:                return cal.get(java.util.Calendar.YEAR) * 365
1116:                        + cal.get(java.util.Calendar.DAY_OF_YEAR);
1117:            }
1118:
1119:            /**
1120:             * Given a day, this method calculates what the first day of that month was.
1121:             * 
1122:             * @param d date to find first of month for
1123:             * @return date of the first day of the month
1124:             */
1125:            public static Date calculateFirstDayOfMonth(Date d) {
1126:                java.util.Calendar cal = new java.util.GregorianCalendar();
1127:                cal.setTime(d);
1128:                int dayOfMonth = cal.get(java.util.Calendar.DAY_OF_MONTH) - 1;
1129:                cal.add(java.util.Calendar.DAY_OF_YEAR, -1 * dayOfMonth);
1130:                return new Date(cal.getTimeInMillis());
1131:            }
1132:
1133:            /**
1134:             * This method checks if the given accounting period ends on the last day of the previous fiscal year
1135:             * 
1136:             * @param acctPeriod accounting period to check
1137:             * @return true if the accounting period ends with the fiscal year, false if otherwise
1138:             */
1139:            public static boolean isEndOfPreviousFiscalYear(
1140:                    AccountingPeriod acctPeriod) {
1141:                UniversityDateService dateService = SpringContext
1142:                        .getBean(UniversityDateService.class);
1143:                Date firstDayOfCurrFiscalYear = new Date(dateService
1144:                        .getFirstDateOfFiscalYear(
1145:                                dateService.getCurrentFiscalYear()).getTime());
1146:                Date periodClose = acctPeriod
1147:                        .getUniversityFiscalPeriodEndDate();
1148:                java.util.Calendar cal = new java.util.GregorianCalendar();
1149:                cal.setTime(periodClose);
1150:                cal.add(java.util.Calendar.DATE, 1);
1151:                return (firstDayOfCurrFiscalYear.equals(new Date(cal
1152:                        .getTimeInMillis())));
1153:            }
1154:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.