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 static org.kuali.module.financial.rules.InternalBillingDocumentRuleConstants.CAPITAL_OBJECT_SUB_TYPE_CODES;
019:
020: import org.kuali.core.document.Document;
021: import org.kuali.core.util.ExceptionUtils;
022: import org.kuali.core.util.GlobalVariables;
023: import org.kuali.kfs.KFSConstants;
024: import org.kuali.kfs.KFSKeyConstants;
025: import org.kuali.kfs.KFSPropertyConstants;
026: import org.kuali.kfs.bo.AccountingLine;
027: import org.kuali.kfs.context.SpringContext;
028: import org.kuali.kfs.document.AccountingDocument;
029: import org.kuali.kfs.rules.AccountingDocumentRuleBase;
030: import org.kuali.kfs.service.ParameterEvaluator;
031: import org.kuali.kfs.service.ParameterService;
032: import org.kuali.module.financial.document.InternalBillingDocument;
033:
034: /**
035: * Business rule(s) applicable to InternalBilling document.
036: */
037: public class InternalBillingDocumentRule extends
038: AccountingDocumentRuleBase {
039:
040: /**
041: * This method determines if an accounting line is a debit accounting line by calling IsDebitUtils.isDebitConsideringSection().
042: *
043: * @param transactionalDocument The document containing the accounting line being analyzed.
044: * @param accountingLine The accounting line being reviewed to determine if it is a debit line or not.
045: * @return True if the accounting line is a debit accounting line, false otherwise.
046: *
047: * @see IsDebitUtils#isDebitConsideringSection(FinancialDocumentRuleBase, FinancialDocument, AccountingLine)
048: * @see org.kuali.core.rule.AccountingLineRule#isDebit(org.kuali.core.document.FinancialDocument,
049: * org.kuali.core.bo.AccountingLine)
050: */
051: public boolean isDebit(AccountingDocument transactionalDocument,
052: AccountingLine accountingLine) {
053: return IsDebitUtils.isDebitConsideringSection(this ,
054: transactionalDocument, accountingLine);
055: }
056:
057: /**
058: * Overrides to only disallow zero, allowing negative amounts.
059: *
060: * @param document The document which contains the accounting line being validated.
061: * @param accountingLine The accounting line containing the amount being validated.
062: * @return True if the amount is not zero, false otherwise.
063: *
064: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isAmountValid(FinancialDocument, AccountingLine)
065: */
066: @Override
067: public boolean isAmountValid(AccountingDocument document,
068: AccountingLine accountingLine) {
069: if (accountingLine.getAmount().equals(KFSConstants.ZERO)) {
070: GlobalVariables.getErrorMap().putError(
071: KFSConstants.AMOUNT_PROPERTY_NAME,
072: KFSKeyConstants.ERROR_ZERO_AMOUNT,
073: "an accounting line");
074: LOG.info("failing isAmountValid - zero check");
075: return false;
076: }
077: return true;
078: }
079:
080: /**
081: * @param document
082: * @param accountingLine
083: * @return
084: *
085: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomAddAccountingLineBusinessRules(FinancialDocument,
086: * AccountingLine)
087: */
088: @Override
089: public boolean processCustomAddAccountingLineBusinessRules(
090: AccountingDocument document, AccountingLine accountingLine) {
091: return processCommonCustomAccountingLineRules(accountingLine);
092: }
093:
094: /**
095: * @param document
096: * @param accountingLine
097: * @return
098: *
099: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomReviewAccountingLineBusinessRules(FinancialDocument,
100: * AccountingLine)
101: */
102: @Override
103: public boolean processCustomReviewAccountingLineBusinessRules(
104: AccountingDocument document, AccountingLine accountingLine) {
105: return processCommonCustomAccountingLineRules(accountingLine);
106: }
107:
108: /**
109: * @param document
110: * @param accountingLine
111: * @return
112: *
113: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomUpdateAccountingLineBusinessRules(FinancialDocument,
114: * AccountingLine, AccountingLine)
115: */
116: @Override
117: public boolean processCustomUpdateAccountingLineBusinessRules(
118: AccountingDocument document,
119: AccountingLine originalAccountingLine,
120: AccountingLine updatedAccountingLine) {
121: return processCommonCustomAccountingLineRules(updatedAccountingLine);
122: }
123:
124: /**
125: * Processes rules common to the three custom accounting line rule methods.
126: *
127: * @param accountingLine The accounting line the business rules will be applied to.
128: * @return True if the custom business rule succeed, false otherwise.
129: */
130: private boolean processCommonCustomAccountingLineRules(
131: AccountingLine accountingLine) {
132: return validateCapitalObjectCodes(accountingLine);
133: }
134:
135: /**
136: * Evaluates the object sub type code of the accounting line's object code to determine whether the object code is a capital
137: * object code. If so, and this accounting line is in the income section, then it is not valid. <p/>
138: *
139: * Note: this is an IU specific business rule.
140: *
141: * @param accountingLine The accounting line the object code will be retrieved from.
142: * @return True if the given line is valid with respect to capital object codes.
143: */
144: private boolean validateCapitalObjectCodes(
145: AccountingLine accountingLine) {
146: if (accountingLine.isSourceAccountingLine()
147: && isCapitalObject(accountingLine)) {
148: GlobalVariables
149: .getErrorMap()
150: .putError(
151: KFSPropertyConstants.FINANCIAL_OBJECT_CODE,
152: KFSKeyConstants.ERROR_DOCUMENT_IB_CAPITAL_OBJECT_IN_INCOME_SECTION);
153: LOG.debug("APC rule failure "
154: + ExceptionUtils.describeStackLevel(0));
155: return false;
156: } else {
157: return true;
158: }
159: // TODO phase II
160: // int pendPurchaseCount = 0;
161: // TODO need to do something with this but I have no idea what
162: // if (!SUB_FUND_GROUP_CODE.CODE_EXTAGY.equals(subFundGroupCode) && restrictedCapitalObjectCodes.contains(objectSubTypeCode)
163: // && (pendPurchaseCount <= 0))
164: }
165:
166: /**
167: * Checks whether the given AccountingLine's ObjectCode is a capital one.
168: *
169: * @param accountingLine The accounting line the object code will be retrieved from.
170: * @return True if the given accounting line's object code is a capital code, false otherwise.
171: */
172: private boolean isCapitalObject(AccountingLine accountingLine) {
173: ParameterEvaluator evaluator = SpringContext.getBean(
174: ParameterService.class).getParameterEvaluator(
175: InternalBillingDocument.class,
176: CAPITAL_OBJECT_SUB_TYPE_CODES,
177: accountingLine.getObjectCode()
178: .getFinancialObjectSubTypeCode());
179: return evaluator.evaluationSucceeds();
180: }
181:
182: /**
183: * This method overrides the processCustomRouteDocumentBusinessRules() method in AccountingDocumentRuleBase to
184: * allow for additional rules to be run prior to routing. In addition to calling the parent method to perform the
185: * general business rule checks, this method also performs a validation check on all InternalBillingItems associated
186: * with the given document.
187: *
188: * @param document The document being routed.
189: * @return True if the parent method finds no business rule problems and all associated InternalBillingItems are valid.
190: *
191: * @see FinancialDocumentRuleBase#processCustomRouteDocumentBusinessRules(Document)
192: */
193: @Override
194: public boolean processCustomRouteDocumentBusinessRules(
195: Document document) {
196: // This super method actually does something.
197: boolean success = true;
198: success &= super
199: .processCustomRouteDocumentBusinessRules(document);
200: if (success) {
201: success &= validateItems((InternalBillingDocument) document);
202: }
203: // TODO: for phase II, when capital object codes are allowed on expense accounting lines, check that there are any if and
204: // only if the Capital Assets tab contains information about the associated capital asset.
205: // TODO: for phase II, check that this bills for no more than one capital asset.
206: return success;
207: }
208:
209: /**
210: * Validates all the InternalBillingItems in the given Document, adding global errors for invalid items. It just uses the
211: * DataDictionary validation.
212: *
213: * @param internalBillingDocument The document the InternalBillingItems will be retrieved from to validate.
214: * @return Whether or not any associated items within the given document are invalid.
215: */
216: private boolean validateItems(
217: InternalBillingDocument internalBillingDocument) {
218: boolean retval = true;
219: for (int i = 0; i < internalBillingDocument.getItems().size(); i++) {
220: String propertyName = KFSConstants.DOCUMENT_PROPERTY_NAME
221: + "." + KFSPropertyConstants.ITEM + "[" + i + "]";
222: retval &= getDictionaryValidationService()
223: .isBusinessObjectValid(
224: internalBillingDocument.getItem(i),
225: propertyName);
226: }
227: return retval;
228: }
229: }
|