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.kfs.KFSPropertyConstants.REFERENCE_NUMBER;
019: import static org.kuali.kfs.KFSPropertyConstants.REFERENCE_ORIGIN_CODE;
020: import static org.kuali.module.financial.rules.GeneralErrorCorrectionDocumentRuleConstants.TRANSACTION_LEDGER_ENTRY_DESCRIPTION_DELIMITER;
021:
022: import org.apache.commons.lang.StringUtils;
023: import org.kuali.core.datadictionary.BusinessObjectEntry;
024: import org.kuali.core.service.DataDictionaryService;
025: import org.kuali.kfs.KFSPropertyConstants;
026: import org.kuali.kfs.bo.AccountingLine;
027: import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
028: import org.kuali.kfs.bo.SourceAccountingLine;
029: import org.kuali.kfs.bo.TargetAccountingLine;
030: import org.kuali.kfs.context.SpringContext;
031: import org.kuali.kfs.document.AccountingDocument;
032: import org.kuali.kfs.rules.AccountingDocumentRuleBase;
033: import org.kuali.kfs.service.ParameterService;
034: import org.kuali.module.chart.bo.ObjectCode;
035: import org.kuali.module.financial.document.GeneralErrorCorrectionDocument;
036:
037: /**
038: * Business rule(s) applicable to <code>{@link org.kuali.module.financial.document.GeneralErrorCorrectionDocument}</code>
039: * instances.
040: */
041: public class GeneralErrorCorrectionDocumentRule extends
042: AccountingDocumentRuleBase {
043:
044: /**
045: * Convenience method for accessing delimiter for the <code>TransactionLedgerEntryDescription</code> of a
046: * <code>{@link GeneralLedgerPendingEntry}</code>
047: *
048: * @return String delimiter for transaction ledger entry description
049: */
050: protected String getEntryDescriptionDelimiter() {
051: return TRANSACTION_LEDGER_ENTRY_DESCRIPTION_DELIMITER;
052: }
053:
054: /**
055: * Helper method for business rules concerning <code>{@link AccountingLine}</code> instances.
056: *
057: * @param document submitted accounting document
058: * @param accountingLine accounting line of submitted accounting document
059: * @return true if object and object sub type are allowed and if required reference fields are valid
060: */
061: private boolean processGenericAccountingLineBusinessRules(
062: AccountingDocument document, AccountingLine accountingLine) {
063: boolean retval = true;
064:
065: ObjectCode objectCode = accountingLine.getObjectCode();
066:
067: retval = isObjectTypeAndObjectSubTypeAllowed(objectCode);
068:
069: if (retval) {
070: retval = isRequiredReferenceFieldsValid(accountingLine);
071: }
072:
073: return retval;
074: }
075:
076: /**
077: * Returns true if accounting line is debit
078: *
079: * @param transactionalDocument submitted accounting document
080: * @param accountingLine accounting line in account document
081: *
082: *
083: * @see IsDebitUtils#isDebitConsideringSectionAndTypePositiveOnly(FinancialDocumentRuleBase, FinancialDocument, AccountingLine)
084: * @see org.kuali.core.rule.AccountingLineRule#isDebit(org.kuali.core.document.FinancialDocument,
085: * org.kuali.core.bo.AccountingLine)
086: */
087: public boolean isDebit(AccountingDocument transactionalDocument,
088: AccountingLine accountingLine) {
089: return IsDebitUtils
090: .isDebitConsideringSectionAndTypePositiveOnly(this ,
091: transactionalDocument, accountingLine);
092: }
093:
094: /**
095: * The GEC allows one sided documents for correcting - so if one side is empty, the other side must have at least two lines in
096: * it. The balancing rules take care of validation of amounts.
097: *
098: * @param transactionalDocument submitted accounting document
099: * @return true if number of account line required is met
100: *
101: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isAccountingLinesRequiredNumberForRoutingMet(org.kuali.core.document.FinancialDocument)
102: */
103: @Override
104: protected boolean isAccountingLinesRequiredNumberForRoutingMet(
105: AccountingDocument transactionalDocument) {
106: return isOptionalOneSidedDocumentAccountingLinesRequiredNumberForRoutingMet(transactionalDocument);
107: }
108:
109: /**
110: * Overrides to call super and then GEC specific accounting line rules.
111: *
112: * @param document submitted accounting document
113: * @param accountingLine accounting line in accounting document
114: * @return true if accounting line can be added without any problems
115: *
116: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomAddAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
117: * org.kuali.core.bo.AccountingLine)
118: */
119: @Override
120: public boolean processCustomAddAccountingLineBusinessRules(
121: AccountingDocument document, AccountingLine accountingLine) {
122: boolean retval = true;
123: retval = super .processCustomAddAccountingLineBusinessRules(
124: document, accountingLine);
125: if (retval) {
126: retval = processGenericAccountingLineBusinessRules(
127: document, accountingLine);
128: }
129: return retval;
130: }
131:
132: /**
133: * Overrides to call super and then GEC specific accounting line rules.
134: *
135: * @param document submitted accounting document
136: * @param accountingLine accounting line in document
137: * @return true if accounting line can be reviewed without any problems
138: *
139: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomReviewAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
140: * org.kuali.core.bo.AccountingLine)
141: */
142: @Override
143: public boolean processCustomReviewAccountingLineBusinessRules(
144: AccountingDocument document, AccountingLine accountingLine) {
145: boolean retval = true;
146:
147: retval = super .processCustomReviewAccountingLineBusinessRules(
148: document, accountingLine);
149: if (retval) {
150: retval = processGenericAccountingLineBusinessRules(
151: document, accountingLine);
152: }
153:
154: return retval;
155: }
156:
157: /**
158: * Customizes a GLPE by setting financial document number, financial system origination code and document type code to null
159: *
160: * @param transactionalDocument submitted accounting document
161: * @param accountingLine accounting line in document
162: * @param explicitEntry general ledger pending entry
163: *
164: *
165: * @see FinancialDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(FinancialDocument, AccountingLine,
166: * GeneralLedgerPendingEntry)
167: */
168: protected void customizeExplicitGeneralLedgerPendingEntry(
169: AccountingDocument transactionalDocument,
170: AccountingLine accountingLine,
171: GeneralLedgerPendingEntry explicitEntry) {
172: explicitEntry
173: .setTransactionLedgerEntryDescription(buildTransactionLedgerEntryDescriptionUsingRefOriginAndRefDocNumber(
174: transactionalDocument, accountingLine));
175:
176: // Clearing fields that are already handled by the parent algorithm - we don't actually want
177: // these to copy over from the accounting lines b/c they don't belong in the GLPEs
178: // if the aren't nulled, then GECs fail to post
179: explicitEntry.setReferenceFinancialDocumentNumber(null);
180: explicitEntry.setReferenceFinancialSystemOriginationCode(null);
181: explicitEntry.setReferenceFinancialDocumentTypeCode(null);
182: }
183:
184: /**
185: * Builds an appropriately formatted string to be used for the <code>transactionLedgerEntryDescription</code>. It is built
186: * using information from the <code>{@link AccountingLine}</code>. Format is "01-12345: blah blah blah".
187: *
188: * @param line accounting line
189: * @param transactionalDocument submitted accounting document
190: * @return String formatted string to be used for transaction ledger entry description
191: */
192: private String buildTransactionLedgerEntryDescriptionUsingRefOriginAndRefDocNumber(
193: AccountingDocument transactionalDocument,
194: AccountingLine line) {
195: String description = "";
196: description = line.getReferenceOriginCode() + "-"
197: + line.getReferenceNumber();
198:
199: if (StringUtils.isNotBlank(line
200: .getFinancialDocumentLineDescription())) {
201: description += ": "
202: + line.getFinancialDocumentLineDescription();
203: } else {
204: description += ": "
205: + transactionalDocument.getDocumentHeader()
206: .getFinancialDocumentDescription();
207: }
208:
209: if (description.length() > GENERAL_LEDGER_PENDING_ENTRY_CODE.GLPE_DESCRIPTION_MAX_LENGTH) {
210: description = description
211: .substring(
212: 0,
213: GENERAL_LEDGER_PENDING_ENTRY_CODE.GLPE_DESCRIPTION_MAX_LENGTH - 3)
214: + "...";
215: }
216:
217: return description;
218: }
219:
220: /**
221: * Used to determine of object code sub types are valid with the object type code.
222: *
223: * @param code object code
224: * @return true if object type and object sub type for passed in object code are allowed
225: */
226: protected boolean isObjectTypeAndObjectSubTypeAllowed(
227: ObjectCode code) {
228: return SpringContext
229: .getBean(ParameterService.class)
230: .getParameterEvaluator(
231: GeneralErrorCorrectionDocument.class,
232: GeneralErrorCorrectionDocumentRuleConstants.VALID_OBJECT_SUB_TYPES_BY_OBJECT_TYPE,
233: GeneralErrorCorrectionDocumentRuleConstants.INVALID_OBJECT_SUB_TYPES_BY_OBJECT_TYPE,
234: code.getFinancialObjectTypeCode(),
235: code.getFinancialObjectSubTypeCode())
236: .evaluateAndAddError(SourceAccountingLine.class,
237: "objectCode.financialObjectSubTypeCode",
238: KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
239: }
240:
241: /**
242: * This method checks that values exist in the two reference fields ENCUMBRANCE.
243: *
244: * @param accountingLine accounting line
245: * @return true if all of the required external encumbrance reference fields are valid, false otherwise.
246: */
247: private boolean isRequiredReferenceFieldsValid(
248: AccountingLine accountingLine) {
249: boolean valid = true;
250: Class alclass = null;
251: BusinessObjectEntry boe;
252:
253: if (accountingLine instanceof SourceAccountingLine) {
254: alclass = SourceAccountingLine.class;
255: } else if (accountingLine instanceof TargetAccountingLine) {
256: alclass = TargetAccountingLine.class;
257: }
258:
259: boe = SpringContext.getBean(DataDictionaryService.class)
260: .getDataDictionary().getBusinessObjectEntry(
261: alclass.getName());
262: if (StringUtils
263: .isEmpty(accountingLine.getReferenceOriginCode())) {
264: putRequiredPropertyError(boe, REFERENCE_ORIGIN_CODE);
265: valid = false;
266: }
267: if (StringUtils.isEmpty(accountingLine.getReferenceNumber())) {
268: putRequiredPropertyError(boe, REFERENCE_NUMBER);
269: valid = false;
270: }
271: return valid;
272: }
273: }
|