001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.module.financial.rules;
017:
018: import org.apache.commons.lang.StringUtils;
019: import org.kuali.core.util.GlobalVariables;
020: import org.kuali.kfs.KFSConstants;
021: import org.kuali.kfs.KFSKeyConstants;
022: import org.kuali.kfs.KFSPropertyConstants;
023: import org.kuali.kfs.bo.AccountingLine;
024: import org.kuali.kfs.document.AccountingDocument;
025: import org.kuali.kfs.rules.AccountingDocumentRuleBase;
026:
027: /**
028: * Business rule(s) applicable to IndirectCostAdjustment documents.
029: */
030: public class IndirectCostAdjustmentDocumentRule extends
031: AccountingDocumentRuleBase implements
032: IndirectCostAdjustmentDocumentRuleConstants {
033:
034: /**
035: * Overrides to only disallow zero. Indirect Cost Adjustment documents can contain accounting lines with positive and
036: * negative amounts, but cannot contains lines with amounts of zero.
037: *
038: * @param document The document associated with the accounting line being validated.
039: * @param accountingLine The accounting line whose amount is being validated.
040: * @return True if the amount is non zero, false otherwise.
041: *
042: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isAmountValid(FinancialDocument, AccountingLine)
043: */
044: @Override
045: public boolean isAmountValid(AccountingDocument document,
046: AccountingLine accountingLine) {
047: boolean isValid = accountingLine.getAmount().isNonZero();
048: if (!isValid) {
049: GlobalVariables.getErrorMap().putError(
050: KFSConstants.AMOUNT_PROPERTY_NAME,
051: KFSKeyConstants.ERROR_ZERO_AMOUNT,
052: "an accounting line");
053: LOG.info("failing isAmountValid - zero check");
054: }
055: return isValid;
056: }
057:
058: /**
059: * Same logic as <code>IsDebitUtils#isDebitConsideringType(FinancialDocumentRuleBase, FinancialDocument, AccountingLine)</code>
060: * but has the following accounting line restrictions:
061: *
062: * for grant lines(source):
063: * <ol>
064: * <li>only allow expense object type codes
065: * </ol>
066: * for receipt lines(target):
067: * <ol>
068: * <li>only allow income object type codes
069: * </ol>
070: *
071: * @param transactionDocument The document associated with the accounting line being reviewed to determine if it's a debit.
072: * @param accountingLine The accounting line being reviewed to determine if it's a debit line.
073: * @return True if the accounting line is a debit. See IsDebitUtils.isDebitConsideringType().
074: * @throws IllegalStateException Thrown if the accounting line given is a source accounting line representing an expense
075: * or is a target accounting line representing an income.
076: *
077: * @see IsDebitUtils#isDebitConsideringType(FinancialDocumentRuleBase, FinancialDocument, AccountingLine)
078: * @see org.kuali.core.rule.AccountingLineRule#isDebit(org.kuali.core.document.FinancialDocument,
079: * org.kuali.core.bo.AccountingLine)
080: */
081: public boolean isDebit(AccountingDocument transactionalDocument,
082: AccountingLine accountingLine) throws IllegalStateException {
083:
084: if (!(accountingLine.isSourceAccountingLine() && isExpense(accountingLine))
085: && !(accountingLine.isTargetAccountingLine() && isIncome(accountingLine))) {
086: throw new IllegalStateException(
087: IsDebitUtils.isDebitCalculationIllegalStateExceptionMessage);
088: }
089:
090: return IsDebitUtils.isDebitConsideringType(this ,
091: transactionalDocument, accountingLine);
092: }
093:
094: /**
095: * This method is overridden to modify the order of the business rule checks performed when adding an accounting
096: * line, to influence the order of any corresponding error messages. This is accomplished by calling a custom
097: * accounting line rule method prior to calling the general rule checks in the parent.
098: *
099: * KULEDOCS-1406: show "account not allowed" error message before "account is expired" error message
100: *
101: * @param transactionalDocument The document the new accounting line will be added to.
102: * @param accountingLine The new accounting line to add.
103: * @return True if all the business rules passed, false otherwise.
104: *
105: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processAddAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
106: * org.kuali.core.bo.AccountingLine)
107: * @see #processCommonCustomAccountingLineBusinessRules(AccountingLine)
108: * @see #isChartOfAccountsAllowed(AccountingLine)
109: * @see #isAccountAllowed(AccountingLine)
110: */
111: @Override
112: public boolean processAddAccountingLineBusinessRules(
113: AccountingDocument transactionalDocument,
114: AccountingLine accountingLine) {
115: boolean valid = processCommonCustomAccountingLineBusinessRules(accountingLine);
116: if (valid) {
117: valid = super .processAddAccountingLineBusinessRules(
118: transactionalDocument, accountingLine);
119: }
120: return valid;
121: }
122:
123: /**
124: * This method is overridden to modify the order of the business rule checks performed when reviewing an
125: * accounting line, to influence the order of any corresponding error messages. This is accomplished by
126: * calling a custom accounting line rule method prior to calling the general rule checks in the parent.
127: *
128: * KULEDOCS-1406: show "account not allowed" error message before "account is expired" error message
129: *
130: * @param transactionalDocument The document containing the accounting line to be reviewed.
131: * @param accountingLine The accounting line being reviewed.
132: * @return True if all the business rules passed, false otherwise.
133: *
134: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processReviewAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
135: * org.kuali.core.bo.AccountingLine)
136: * @see #processCommonCustomAccountingLineBusinessRules(AccountingLine)
137: * @see #isChartOfAccountsAllowed(AccountingLine)
138: * @see #isAccountAllowed(AccountingLine)
139: */
140: @Override
141: public boolean processReviewAccountingLineBusinessRules(
142: AccountingDocument transactionalDocument,
143: AccountingLine accountingLine) {
144: boolean valid = processCommonCustomAccountingLineBusinessRules(accountingLine);
145: if (valid) {
146: valid = super .processReviewAccountingLineBusinessRules(
147: transactionalDocument, accountingLine);
148: }
149: return valid;
150: }
151:
152: /**
153: * This method is overridden to modify the order of the business rule checks performed when updating an accounting
154: * line, to influence the order of any corresponding error messages. This is accomplished by calling a custom
155: * accounting line rule method prior to calling the general rule checks in the parent.
156: *
157: * KULEDOCS-1406: show "account not allowed" error message before "account is expired" error message
158: *
159: * @param transactionalDocument The document containing the accounting line to be updated.
160: * @param accountingLine The accounting line being updated.
161: * @return True if all the business rules passed, false otherwise.
162: *
163: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processUpdateAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
164: * org.kuali.core.bo.AccountingLine, org.kuali.core.bo.AccountingLine)
165: * @see #processCommonCustomAccountingLineBusinessRules(AccountingLine)
166: * @see #isChartOfAccountsAllowed(AccountingLine)
167: * @see #isAccountAllowed(AccountingLine)
168: */
169: @Override
170: public boolean processUpdateAccountingLineBusinessRules(
171: AccountingDocument transactionalDocument,
172: AccountingLine accountingLine,
173: AccountingLine updatedAccountingLine) {
174: boolean valid = processCommonCustomAccountingLineBusinessRules(accountingLine);
175: if (valid) {
176: valid = super .processUpdateAccountingLineBusinessRules(
177: transactionalDocument, accountingLine,
178: updatedAccountingLine);
179: }
180: return valid;
181: }
182:
183: /**
184: * This method provides a centralized entry point to perform custom common accounting line validation.
185: *
186: * @param accountingLine The accounting line to run the business rule checks against.
187: * @return True if all the custom business rules pass, false otherwise.
188: */
189: protected boolean processCommonCustomAccountingLineBusinessRules(
190: AccountingLine accountingLine) {
191: // refresh line since this document calls the custom rules first. KULEDOCS-1406
192: accountingLine.refresh();
193: boolean isValid = isChartOfAccountsAllowed(accountingLine);
194: if (isValid) {
195: isValid = isAccountAllowed(accountingLine);
196: }
197: return isValid;
198: }
199:
200: /**
201: * This method checks to see if the account associated with the accounting line given is allowed. This is determined
202: * by checking to see if the source (grant) account references an indirect cost recovery (ICR) account.
203: *
204: * @param accountingLine The accounting line which contains the account to be validated.
205: * @return True if the grant account references an indirect cost recovery account.
206: */
207: private boolean isAccountAllowed(AccountingLine accountingLine) {
208: boolean isValid = true;
209: if (isValid && accountingLine.isSourceAccountingLine()) {
210: String icrAccount = accountingLine.getAccount()
211: .getIndirectCostRecoveryAcctNbr();
212: isValid &= StringUtils.isNotBlank(icrAccount);
213: if (!isValid) {
214: reportError(
215: KFSPropertyConstants.ACCOUNT,
216: KFSKeyConstants.IndirectCostAdjustment.ERROR_DOCUMENT_ICA_GRANT_INVALID_ACCOUNT,
217: accountingLine.getAccountNumber());
218: }
219: }
220: return isValid;
221: }
222:
223: /**
224: * This method ensures that:
225: * <ol>
226: * <li>"GRANT" chart of accounts reference an indirect cost recovery (ICR) expense object
227: * <li>"RECEIPT" chart of accounts reference an indirect cost recovery (ICR) income object
228: * </ol>
229: *
230: * @param accountingLine The accounting line the chard of accounts will be retrieved from.
231: * @return True if the chart of account code is allowed on the indirect cost adjustment (ICA), false otherwise.
232: */
233: private boolean isChartOfAccountsAllowed(
234: AccountingLine accountingLine) {
235: boolean isValid = true;
236:
237: if (accountingLine.isSourceAccountingLine()) {
238: String icrExpense = accountingLine.getChart()
239: .getIcrExpenseFinancialObjectCd();
240: isValid &= StringUtils.isNotBlank(icrExpense);
241: if (!isValid) {
242: reportError(
243: KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE,
244: KFSKeyConstants.IndirectCostAdjustment.ERROR_DOCUMENT_ICA_GRANT_INVALID_CHART_OF_ACCOUNTS,
245: new String[] { accountingLine
246: .getChartOfAccountsCode() });
247: }
248: } else {
249: String icrIncome = accountingLine.getChart()
250: .getIcrIncomeFinancialObjectCode();
251: isValid &= StringUtils.isNotBlank(icrIncome);
252: if (!isValid) {
253: reportError(
254: KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE,
255: KFSKeyConstants.IndirectCostAdjustment.ERROR_DOCUMENT_ICA_RECEIPT_INVALID_CHART_OF_ACCOUNTS,
256: new String[] { accountingLine
257: .getChartOfAccountsCode() });
258: }
259: }
260:
261: return isValid;
262: }
263: }
|