001: /*
002: * Copyright 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.labor.rules;
017:
018: import java.util.HashSet;
019: import java.util.List;
020: import java.util.Set;
021:
022: import org.apache.commons.lang.StringUtils;
023: import org.kuali.core.document.Document;
024: import org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper;
025: import org.kuali.kfs.KFSPropertyConstants;
026: import org.kuali.kfs.bo.AccountingLine;
027: import org.kuali.kfs.document.AccountingDocument;
028: import org.kuali.module.chart.bo.Account;
029: import org.kuali.module.labor.LaborConstants;
030: import org.kuali.module.labor.LaborKeyConstants;
031: import org.kuali.module.labor.bo.ExpenseTransferAccountingLine;
032: import org.kuali.module.labor.bo.ExpenseTransferSourceAccountingLine;
033: import org.kuali.module.labor.bo.LaborLedgerPendingEntry;
034: import org.kuali.module.labor.bo.LaborObject;
035: import org.kuali.module.labor.document.LaborExpenseTransferDocumentBase;
036: import org.kuali.module.labor.document.LaborLedgerPostingDocument;
037: import org.kuali.module.labor.util.LaborPendingEntryGenerator;
038:
039: /**
040: * Business rule(s) applicable to Benefit Expense Transfer documents.
041: */
042: public class BenefitExpenseTransferDocumentRule extends
043: LaborExpenseTransferDocumentRules {
044: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
045: .getLogger(BenefitExpenseTransferDocumentRule.class);
046:
047: /**
048: * Constructs a BenefitExpenseTransferDocumentRule.java.
049: */
050: public BenefitExpenseTransferDocumentRule() {
051: super ();
052: }
053:
054: /**
055: * Overrides the method in class laborExpenseTransferDocumentRules in order validate the object code is a fringe benefit object
056: * code and that the source and target lines have the same account number.
057: *
058: * @param accountingDocument
059: * @param accountingLine
060: * @return boolean false when an error is found in any validation
061: * @see org.kuali.kfs.rules.AccountingDocumentRuleBase#processCustomAddAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
062: * org.kuali.kfs.bo.AccountingLine)
063: */
064: @Override
065: protected boolean processCustomAddAccountingLineBusinessRules(
066: AccountingDocument accountingDocument,
067: AccountingLine accountingLine) {
068: boolean isValid = super
069: .processCustomAddAccountingLineBusinessRules(
070: accountingDocument, accountingLine);
071:
072: // only fringe benefit labor object codes are allowed on the benefit expense transfer document
073: if (!isFringeBenefitObjectCode(accountingLine)) {
074: reportError(KFSPropertyConstants.FINANCIAL_OBJECT_CODE,
075: LaborKeyConstants.INVALID_FRINGE_OBJECT_CODE_ERROR,
076: accountingLine.getAccountNumber());
077: isValid = false;
078: }
079:
080: // Only check this rule for source accounting lines
081: boolean isTargetLine = accountingLine.isTargetAccountingLine();
082: if (!isTargetLine) {
083: // ensure the accounts in source accounting lines are same
084: if (!hasSameAccount(accountingDocument, accountingLine)) {
085: reportError(
086: KFSPropertyConstants.SOURCE_ACCOUNTING_LINES,
087: LaborKeyConstants.ERROR_ACCOUNT_NOT_SAME);
088: isValid = false;
089: }
090: }
091:
092: return isValid;
093: }
094:
095: /**
096: * Validates the target and source lines have the same object code.
097: *
098: * @param document
099: * @return boolean false when the source and target lines have different object codes.
100: * @see org.kuali.module.labor.rules.LaborExpenseTransferDocumentRules#processCustomRouteDocumentBusinessRules(org.kuali.core.document.Document)
101: */
102: @Override
103: protected boolean processCustomRouteDocumentBusinessRules(
104: Document document) {
105: boolean isValid = super
106: .processCustomRouteDocumentBusinessRules(document);
107:
108: LaborExpenseTransferDocumentBase expenseTransferDocument = (LaborExpenseTransferDocumentBase) document;
109:
110: // benefit transfers cannot be made between two different fringe benefit labor object codes.
111: if (isValid) {
112: boolean hasSameFringeBenefitObjectCodes = hasSameFringeBenefitObjectCodes(expenseTransferDocument);
113: if (!hasSameFringeBenefitObjectCodes) {
114: reportError(
115: KFSPropertyConstants.TARGET_ACCOUNTING_LINES,
116: LaborKeyConstants.DISTINCT_OBJECT_CODE_ERROR);
117: isValid = false;
118: }
119: }
120:
121: return isValid;
122: }
123:
124: /**
125: * Generates the expense pending entries.
126: *
127: * @param document LaborLedgerPostingDocument type
128: * @param accountingLine AccountingLine type
129: * @return boolean
130: * @see org.kuali.module.labor.rules.LaborExpenseTransferDocumentRules#processGenerateLaborLedgerPendingEntries(org.kuali.module.labor.document.LaborLedgerPostingDocument,
131: * org.kuali.module.labor.bo.ExpenseTransferAccountingLine, org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper)
132: */
133: @Override
134: public boolean processGenerateLaborLedgerPendingEntries(
135: LaborLedgerPostingDocument document,
136: AccountingLine accountingLine,
137: GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
138: LOG.info("started processGenerateLaborLedgerPendingEntries()");
139:
140: ExpenseTransferAccountingLine expenseTransferAccountingLine = (ExpenseTransferAccountingLine) accountingLine;
141: List<LaborLedgerPendingEntry> expensePendingEntries = LaborPendingEntryGenerator
142: .generateExpensePendingEntries(document,
143: expenseTransferAccountingLine, sequenceHelper);
144: document.getLaborLedgerPendingEntries().addAll(
145: expensePendingEntries);
146:
147: return true;
148: }
149:
150: /**
151: * Determines whether the object code of given accounting line is a fringe benefit labor object code
152: *
153: * @param accountingLine the given accounting line
154: * @return true if the object code of given accounting line is a fringe benefit labor object code; otherwise, false
155: */
156: private boolean isFringeBenefitObjectCode(
157: AccountingLine accountingLine) {
158: LOG.debug("started isFringeBenefitObjectCode");
159: ExpenseTransferAccountingLine expenseTransferAccountingLine = (ExpenseTransferAccountingLine) accountingLine;
160:
161: LaborObject laborObject = expenseTransferAccountingLine
162: .getLaborObject();
163: if (laborObject == null) {
164: return false;
165: }
166:
167: String fringeOrSalaryCode = laborObject
168: .getFinancialObjectFringeOrSalaryCode();
169: return StringUtils
170: .equals(
171: LaborConstants.BenefitExpenseTransfer.LABOR_LEDGER_BENEFIT_CODE,
172: fringeOrSalaryCode);
173: }
174:
175: /**
176: * Determines whether the given accouting line has the same account as the source accounting lines
177: *
178: * @param accountingDocument the given accouting document
179: * @param accountingLine the given accounting line
180: * @return true if the given accouting line has the same account as the source accounting lines; otherwise, false
181: */
182: private boolean hasSameAccount(
183: AccountingDocument accountingDocument,
184: AccountingLine accountingLine) {
185: LOG
186: .debug("started hasSameAccount(AccountingDocument, AccountingLine)");
187:
188: LaborExpenseTransferDocumentBase expenseTransferDocument = (LaborExpenseTransferDocumentBase) accountingDocument;
189: List<ExpenseTransferSourceAccountingLine> sourceAccountingLines = expenseTransferDocument
190: .getSourceAccountingLines();
191:
192: Account cachedAccount = accountingLine.getAccount();
193: for (AccountingLine sourceAccountingLine : sourceAccountingLines) {
194: Account account = sourceAccountingLine.getAccount();
195:
196: // account number was not retrieved correctly, so the two statements are used to populate the fields manually
197: account.setChartOfAccountsCode(sourceAccountingLine
198: .getChartOfAccountsCode());
199: account.setAccountNumber(sourceAccountingLine
200: .getAccountNumber());
201:
202: if (!account.equals(cachedAccount)) {
203: return false;
204: }
205: }
206:
207: return true;
208: }
209:
210: /**
211: * Determines whether target accouting lines have the same fringe benefit object codes as source accounting lines
212: *
213: * @param accountingDocument the given accounting document
214: * @return true if target accouting lines have the same fringe benefit object codes as source accounting lines; otherwise, false
215: */
216: protected boolean hasSameFringeBenefitObjectCodes(
217: AccountingDocument accountingDocument) {
218: LOG
219: .debug("started hasSameFringeBenefitObjectCodes(accountingDocument)");
220: LaborExpenseTransferDocumentBase expenseTransferDocument = (LaborExpenseTransferDocumentBase) accountingDocument;
221:
222: Set<String> objectCodesFromSourceLine = new HashSet<String>();
223: for (Object sourceAccountingLine : expenseTransferDocument
224: .getSourceAccountingLines()) {
225: AccountingLine line = (AccountingLine) sourceAccountingLine;
226: objectCodesFromSourceLine
227: .add(line.getFinancialObjectCode());
228: }
229:
230: Set<String> objectCodesFromTargetLine = new HashSet<String>();
231: for (Object targetAccountingLine : expenseTransferDocument
232: .getTargetAccountingLines()) {
233: AccountingLine line = (AccountingLine) targetAccountingLine;
234: objectCodesFromTargetLine
235: .add(line.getFinancialObjectCode());
236: }
237:
238: if (objectCodesFromSourceLine.size() != objectCodesFromTargetLine
239: .size()) {
240: return false;
241: }
242:
243: return objectCodesFromSourceLine
244: .containsAll(objectCodesFromTargetLine);
245: }
246: }
|