001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.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/ecl2.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    
017    package org.kuali.kfs.fp.document;
018    
019    import java.util.ArrayList;
020    import java.util.HashMap;
021    import java.util.Iterator;
022    import java.util.LinkedHashMap;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.apache.commons.lang.StringUtils;
027    import org.kuali.kfs.coa.businessobject.Account;
028    import org.kuali.kfs.coa.service.AccountService;
029    import org.kuali.kfs.fp.businessobject.BudgetAdjustmentAccountingLine;
030    import org.kuali.kfs.fp.businessobject.BudgetAdjustmentAccountingLineParser;
031    import org.kuali.kfs.fp.businessobject.BudgetAdjustmentSourceAccountingLine;
032    import org.kuali.kfs.fp.businessobject.BudgetAdjustmentTargetAccountingLine;
033    import org.kuali.kfs.fp.businessobject.FiscalYearFunctionControl;
034    import org.kuali.kfs.fp.document.validation.impl.BudgetAdjustmentDocumentRuleConstants;
035    import org.kuali.kfs.fp.document.validation.impl.TransferOfFundsDocumentRuleConstants;
036    import org.kuali.kfs.fp.service.FiscalYearFunctionControlService;
037    import org.kuali.kfs.sys.KFSConstants;
038    import org.kuali.kfs.sys.KFSPropertyConstants;
039    import org.kuali.kfs.sys.businessobject.AccountResponsibility;
040    import org.kuali.kfs.sys.businessobject.AccountingLine;
041    import org.kuali.kfs.sys.businessobject.AccountingLineParser;
042    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
043    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
044    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
045    import org.kuali.kfs.sys.businessobject.SystemOptions;
046    import org.kuali.kfs.sys.businessobject.SourceAccountingLine;
047    import org.kuali.kfs.sys.context.SpringContext;
048    import org.kuali.kfs.sys.document.AccountingDocumentBase;
049    import org.kuali.kfs.sys.document.AmountTotaling;
050    import org.kuali.kfs.sys.document.Correctable;
051    import org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService;
052    import org.kuali.kfs.sys.document.service.DebitDeterminerService;
053    import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
054    import org.kuali.kfs.sys.service.OptionsService;
055    import org.kuali.kfs.sys.service.UniversityDateService;
056    import org.kuali.rice.kew.engine.node.SplitResult;
057    import org.kuali.rice.kew.exception.WorkflowException;
058    import org.kuali.rice.kim.bo.Person;
059    import org.kuali.rice.kns.document.Copyable;
060    import org.kuali.rice.kns.exception.InfrastructureException;
061    import org.kuali.rice.kns.service.DocumentService;
062    import org.kuali.rice.kns.service.ParameterService;
063    import org.kuali.rice.kns.util.KualiDecimal;
064    import org.kuali.rice.kns.util.KualiInteger;
065    import org.kuali.rice.kns.util.ObjectUtils;
066    import org.kuali.rice.kns.web.format.CurrencyFormatter;
067    
068    /**
069     * This is the business object that represents the BudgetAdjustment document in Kuali.
070     */
071    public class BudgetAdjustmentDocument extends AccountingDocumentBase implements Copyable, Correctable, AmountTotaling {
072        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BudgetAdjustmentDocument.class);
073        
074        protected static final String REQUIRES_FULL_APPROVAL_SPLIT_NODE_NAME = "RequiresFullApproval";
075    
076        protected Integer nextPositionSourceLineNumber;
077        protected Integer nextPositionTargetLineNumber;
078    
079        /**
080         * Default constructor.
081         */
082        public BudgetAdjustmentDocument() {
083            super();
084        }
085    
086    
087        /*******************************************************************************************************************************
088         * BA Documents should only do SF checking on PLEs with a Balance Type of 'CB' - not 'BB' or 'MB'.
089         * 
090         * @Override
091         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getPendingLedgerEntriesForSufficientFundsChecking()
092         */
093        public List<GeneralLedgerPendingEntry> getPendingLedgerEntriesForSufficientFundsChecking() {
094            List<GeneralLedgerPendingEntry> pendingLedgerEntries = new ArrayList();
095    
096            GeneralLedgerPendingEntrySequenceHelper glpeSequenceHelper = new GeneralLedgerPendingEntrySequenceHelper();
097    
098            BudgetAdjustmentDocument copiedBa = (BudgetAdjustmentDocument) ObjectUtils.deepCopy(this);
099            copiedBa.getGeneralLedgerPendingEntries().clear();
100            for (BudgetAdjustmentAccountingLine fromLine : (List<BudgetAdjustmentAccountingLine>) copiedBa.getSourceAccountingLines()) {
101                copiedBa.generateGeneralLedgerPendingEntries(fromLine, glpeSequenceHelper);
102            }
103    
104            for (GeneralLedgerPendingEntry ple : copiedBa.getGeneralLedgerPendingEntries()) {
105                if (!KFSConstants.BALANCE_TYPE_BASE_BUDGET.equals(ple.getFinancialBalanceTypeCode()) && !KFSConstants.BALANCE_TYPE_MONTHLY_BUDGET.equals(ple.getFinancialBalanceTypeCode())) {
106                    pendingLedgerEntries.add(ple);
107                }
108            }
109            return pendingLedgerEntries;
110        }
111    
112        /**
113         * generic, shared logic used to iniate a ba document
114         */
115        public void initiateDocument() {
116            // setting default posting year. Trying to set currentYear first if it's allowed, if it isn't,
117            // just set first allowed year. Note: allowedYears will never be empty because then
118            // BudgetAdjustmentDocumentAuthorizer.canInitiate would have failed.
119            List allowedYears = SpringContext.getBean(FiscalYearFunctionControlService.class).getBudgetAdjustmentAllowedYears();
120            Integer currentYearParam = SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
121    
122            FiscalYearFunctionControl fiscalYearFunctionControl = new FiscalYearFunctionControl();
123            fiscalYearFunctionControl.setUniversityFiscalYear(currentYearParam);
124    
125            // use 'this.postingYear =' because setPostingYear has logic we want to circumvent on initiateDocument
126            if (allowedYears.contains(fiscalYearFunctionControl)) {
127                this.postingYear = currentYearParam;
128            }
129            else {
130                this.postingYear = ((FiscalYearFunctionControl) allowedYears.get(0)).getUniversityFiscalYear();
131            }
132        }
133    
134        /**
135         * @return Integer
136         */
137        public Integer getNextPositionSourceLineNumber() {
138            return nextPositionSourceLineNumber;
139        }
140    
141        /**
142         * @param nextPositionSourceLineNumber
143         */
144        public void setNextPositionSourceLineNumber(Integer nextPositionSourceLineNumber) {
145            this.nextPositionSourceLineNumber = nextPositionSourceLineNumber;
146        }
147    
148        /**
149         * @return Integer
150         */
151        public Integer getNextPositionTargetLineNumber() {
152            return nextPositionTargetLineNumber;
153        }
154    
155        /**
156         * @param nextPositionTargetLineNumber
157         */
158        public void setNextPositionTargetLineNumber(Integer nextPositionTargetLineNumber) {
159            this.nextPositionTargetLineNumber = nextPositionTargetLineNumber;
160        }
161    
162        /**
163         * Returns the total current budget amount from the source lines.
164         * 
165         * @return KualiDecimal
166         */
167        public KualiDecimal getSourceCurrentBudgetTotal() {
168            KualiDecimal currentBudgetTotal = KualiDecimal.ZERO;
169    
170            for (Iterator iter = sourceAccountingLines.iterator(); iter.hasNext();) {
171                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
172                currentBudgetTotal = currentBudgetTotal.add(line.getCurrentBudgetAdjustmentAmount());
173            }
174    
175            return currentBudgetTotal;
176        }
177    
178        /**
179         * This method retrieves the total current budget amount formatted as currency.
180         * 
181         * @return String
182         */
183        public String getCurrencyFormattedSourceCurrentBudgetTotal() {
184            return (String) new CurrencyFormatter().format(getSourceCurrentBudgetTotal());
185        }
186    
187        /**
188         * Returns the total current budget income amount from the source lines.
189         * 
190         * @return KualiDecimal
191         */
192        public KualiDecimal getSourceCurrentBudgetIncomeTotal() {
193            KualiDecimal total = KualiDecimal.ZERO;
194    
195            for (Iterator iter = sourceAccountingLines.iterator(); iter.hasNext();) {
196                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
197                AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
198                if (accountingDocumentRuleUtil.isIncome(line)) {
199                    total = total.add(line.getCurrentBudgetAdjustmentAmount());
200                }
201            }
202    
203            return total;
204        }
205    
206        /**
207         * Returns the total current budget expense amount from the source lines.
208         * 
209         * @return KualiDecimal
210         */
211        public KualiDecimal getSourceCurrentBudgetExpenseTotal() {
212            KualiDecimal total = KualiDecimal.ZERO;
213    
214            for (Iterator iter = sourceAccountingLines.iterator(); iter.hasNext();) {
215                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
216                AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
217                if (accountingDocumentRuleUtil.isExpense(line)) {
218                    total = total.add(line.getCurrentBudgetAdjustmentAmount());
219                }
220            }
221    
222            return total;
223        }
224    
225        /**
226         * Returns the total current budget amount from the target lines.
227         * 
228         * @return KualiDecimal
229         */
230        public KualiDecimal getTargetCurrentBudgetTotal() {
231            KualiDecimal currentBudgetTotal = KualiDecimal.ZERO;
232    
233            for (Iterator iter = targetAccountingLines.iterator(); iter.hasNext();) {
234                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
235                currentBudgetTotal = currentBudgetTotal.add(line.getCurrentBudgetAdjustmentAmount());
236            }
237    
238            return currentBudgetTotal;
239        }
240    
241        /**
242         * This method retrieves the total current budget amount formatted as currency.
243         * 
244         * @return String
245         */
246        public String getCurrencyFormattedTargetCurrentBudgetTotal() {
247            return (String) new CurrencyFormatter().format(getTargetCurrentBudgetTotal());
248        }
249    
250        /**
251         * Returns the total current budget income amount from the target lines.
252         * 
253         * @return KualiDecimal
254         */
255        public KualiDecimal getTargetCurrentBudgetIncomeTotal() {
256            KualiDecimal total = KualiDecimal.ZERO;
257    
258            AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
259            for (Iterator iter = targetAccountingLines.iterator(); iter.hasNext();) {
260                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
261                if (accountingDocumentRuleUtil.isIncome(line)) {
262                    total = total.add(line.getCurrentBudgetAdjustmentAmount());
263                }
264            }
265    
266            return total;
267        }
268    
269        /**
270         * Returns the total current budget expense amount from the target lines.
271         * 
272         * @return KualiDecimal
273         */
274        public KualiDecimal getTargetCurrentBudgetExpenseTotal() {
275            KualiDecimal total = KualiDecimal.ZERO;
276    
277            AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
278            for (Iterator iter = targetAccountingLines.iterator(); iter.hasNext();) {
279                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
280                if (accountingDocumentRuleUtil.isExpense(line)) {
281                    total = total.add(line.getCurrentBudgetAdjustmentAmount());
282                }
283            }
284    
285            return total;
286        }
287    
288        /**
289         * Returns the total base budget amount from the source lines.
290         * 
291         * @return KualiDecimal
292         */
293        public KualiInteger getSourceBaseBudgetTotal() {
294            KualiInteger baseBudgetTotal = KualiInteger.ZERO;
295    
296            for (Iterator iter = sourceAccountingLines.iterator(); iter.hasNext();) {
297                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
298                baseBudgetTotal = baseBudgetTotal.add(line.getBaseBudgetAdjustmentAmount());
299            }
300    
301            return baseBudgetTotal;
302        }
303    
304    
305        /**
306         * This method retrieves the total base budget amount formatted as currency.
307         * 
308         * @return String
309         */
310        public String getCurrencyFormattedSourceBaseBudgetTotal() {
311            return (String) new CurrencyFormatter().format(getSourceBaseBudgetTotal());
312        }
313    
314        /**
315         * Returns the total base budget income amount from the source lines.
316         * 
317         * @return KualiDecimal
318         */
319        public KualiInteger getSourceBaseBudgetIncomeTotal() {
320            KualiInteger total = KualiInteger.ZERO;
321    
322            AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
323            for (Iterator iter = sourceAccountingLines.iterator(); iter.hasNext();) {
324                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
325                if (accountingDocumentRuleUtil.isIncome(line)) {
326                    total = total.add(line.getBaseBudgetAdjustmentAmount());
327                }
328            }
329    
330            return total;
331        }
332    
333        /**
334         * Returns the total base budget expense amount from the source lines.
335         * 
336         * @return KualiDecimal
337         */
338        public KualiInteger getSourceBaseBudgetExpenseTotal() {
339            KualiInteger total = KualiInteger.ZERO;
340    
341            AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
342            for (Iterator iter = sourceAccountingLines.iterator(); iter.hasNext();) {
343                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
344                if (accountingDocumentRuleUtil.isExpense(line)) {
345                    total = total.add(line.getBaseBudgetAdjustmentAmount());
346                }
347            }
348    
349            return total;
350        }
351    
352        /**
353         * Returns the total base budget amount from the target lines.
354         * 
355         * @return KualiDecimal
356         */
357        public KualiInteger getTargetBaseBudgetTotal() {
358            KualiInteger baseBudgetTotal = KualiInteger.ZERO;
359    
360            for (Iterator iter = targetAccountingLines.iterator(); iter.hasNext();) {
361                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
362                baseBudgetTotal = baseBudgetTotal.add(line.getBaseBudgetAdjustmentAmount());
363            }
364    
365            return baseBudgetTotal;
366        }
367    
368        /**
369         * This method retrieves the total base budget amount formatted as currency.
370         * 
371         * @return String
372         */
373        public String getCurrencyFormattedTargetBaseBudgetTotal() {
374            return (String) new CurrencyFormatter().format(getTargetBaseBudgetTotal());
375        }
376    
377        /**
378         * Returns the total base budget income amount from the target lines.
379         * 
380         * @return KualiDecimal
381         */
382        public KualiInteger getTargetBaseBudgetIncomeTotal() {
383            KualiInteger total = KualiInteger.ZERO;
384    
385            AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
386            for (Iterator iter = targetAccountingLines.iterator(); iter.hasNext();) {
387                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
388                if (accountingDocumentRuleUtil.isIncome(line)) {
389                    total = total.add(line.getBaseBudgetAdjustmentAmount());
390                }
391            }
392    
393            return total;
394        }
395    
396        /**
397         * Returns the total base budget expense amount from the target lines.
398         * 
399         * @return KualiDecimal
400         */
401        public KualiInteger getTargetBaseBudgetExpenseTotal() {
402            KualiInteger total = KualiInteger.ZERO;
403    
404            AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
405            for (Iterator iter = targetAccountingLines.iterator(); iter.hasNext();) {
406                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
407                if (accountingDocumentRuleUtil.isExpense(line)) {
408                    total = total.add(line.getBaseBudgetAdjustmentAmount());
409                }
410            }
411    
412            return total;
413        }
414    
415        /**
416         * Same as default implementation but uses getTargetCurrentBudgetTotal and getSourceCurrentBudgetTotal instead.
417         * 
418         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getTotalDollarAmount()
419         * @return KualiDecimal
420         */
421        @Override
422        public KualiDecimal getTotalDollarAmount() {
423            return getTargetCurrentBudgetTotal().equals(KualiDecimal.ZERO) ? getSourceCurrentBudgetTotal() : getTargetCurrentBudgetTotal();
424        }
425    
426        /**
427         * Negate accounting line budget amounts.
428         * 
429         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#toErrorCorrection()
430         */
431        @Override
432        public void toErrorCorrection() throws WorkflowException {
433            super.toErrorCorrection();
434    
435            if (this.getSourceAccountingLines() != null) {
436                for (Iterator iter = this.getSourceAccountingLines().iterator(); iter.hasNext();) {
437                    BudgetAdjustmentAccountingLine sourceLine = (BudgetAdjustmentAccountingLine) iter.next();
438                    sourceLine.setBaseBudgetAdjustmentAmount(sourceLine.getBaseBudgetAdjustmentAmount().negated());
439                    sourceLine.setCurrentBudgetAdjustmentAmount(sourceLine.getCurrentBudgetAdjustmentAmount().negated());
440                    sourceLine.setFinancialDocumentMonth1LineAmount(sourceLine.getFinancialDocumentMonth1LineAmount().negated());
441                    sourceLine.setFinancialDocumentMonth2LineAmount(sourceLine.getFinancialDocumentMonth2LineAmount().negated());
442                    sourceLine.setFinancialDocumentMonth3LineAmount(sourceLine.getFinancialDocumentMonth3LineAmount().negated());
443                    sourceLine.setFinancialDocumentMonth4LineAmount(sourceLine.getFinancialDocumentMonth4LineAmount().negated());
444                    sourceLine.setFinancialDocumentMonth5LineAmount(sourceLine.getFinancialDocumentMonth5LineAmount().negated());
445                    sourceLine.setFinancialDocumentMonth6LineAmount(sourceLine.getFinancialDocumentMonth6LineAmount().negated());
446                    sourceLine.setFinancialDocumentMonth7LineAmount(sourceLine.getFinancialDocumentMonth7LineAmount().negated());
447                    sourceLine.setFinancialDocumentMonth8LineAmount(sourceLine.getFinancialDocumentMonth8LineAmount().negated());
448                    sourceLine.setFinancialDocumentMonth9LineAmount(sourceLine.getFinancialDocumentMonth9LineAmount().negated());
449                    sourceLine.setFinancialDocumentMonth10LineAmount(sourceLine.getFinancialDocumentMonth10LineAmount().negated());
450                    sourceLine.setFinancialDocumentMonth11LineAmount(sourceLine.getFinancialDocumentMonth11LineAmount().negated());
451                    sourceLine.setFinancialDocumentMonth12LineAmount(sourceLine.getFinancialDocumentMonth12LineAmount().negated());
452                }
453            }
454    
455            if (this.getTargetAccountingLines() != null) {
456                for (Iterator iter = this.getTargetAccountingLines().iterator(); iter.hasNext();) {
457                    BudgetAdjustmentAccountingLine targetLine = (BudgetAdjustmentAccountingLine) iter.next();
458                    targetLine.setBaseBudgetAdjustmentAmount(targetLine.getBaseBudgetAdjustmentAmount().negated());
459                    targetLine.setCurrentBudgetAdjustmentAmount(targetLine.getCurrentBudgetAdjustmentAmount().negated());
460                    targetLine.setFinancialDocumentMonth1LineAmount(targetLine.getFinancialDocumentMonth1LineAmount().negated());
461                    targetLine.setFinancialDocumentMonth2LineAmount(targetLine.getFinancialDocumentMonth2LineAmount().negated());
462                    targetLine.setFinancialDocumentMonth3LineAmount(targetLine.getFinancialDocumentMonth3LineAmount().negated());
463                    targetLine.setFinancialDocumentMonth4LineAmount(targetLine.getFinancialDocumentMonth4LineAmount().negated());
464                    targetLine.setFinancialDocumentMonth5LineAmount(targetLine.getFinancialDocumentMonth5LineAmount().negated());
465                    targetLine.setFinancialDocumentMonth6LineAmount(targetLine.getFinancialDocumentMonth6LineAmount().negated());
466                    targetLine.setFinancialDocumentMonth7LineAmount(targetLine.getFinancialDocumentMonth7LineAmount().negated());
467                    targetLine.setFinancialDocumentMonth8LineAmount(targetLine.getFinancialDocumentMonth8LineAmount().negated());
468                    targetLine.setFinancialDocumentMonth9LineAmount(targetLine.getFinancialDocumentMonth9LineAmount().negated());
469                    targetLine.setFinancialDocumentMonth10LineAmount(targetLine.getFinancialDocumentMonth10LineAmount().negated());
470                    targetLine.setFinancialDocumentMonth11LineAmount(targetLine.getFinancialDocumentMonth11LineAmount().negated());
471                    targetLine.setFinancialDocumentMonth12LineAmount(targetLine.getFinancialDocumentMonth12LineAmount().negated());
472                }
473            }
474        }
475    
476        /**
477         * @see org.kuali.rice.kns.document.DocumentBase#toStringMapper()
478         */
479        @Override
480        protected LinkedHashMap toStringMapper() {
481            LinkedHashMap m = new LinkedHashMap();
482            m.put(KFSPropertyConstants.DOCUMENT_NUMBER, this.documentNumber);
483            return m;
484        }
485    
486        /**
487         * The base checks that the posting year is the current year, not a requirement for the ba document.
488         * 
489         * @see org.kuali.rice.kns.document.TransactionalDocumentBase#getAllowsCopy()
490         */
491        @Override
492        public boolean getAllowsCopy() {
493            return true;
494        }
495    
496        /**
497         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getSourceAccountingLinesSectionTitle()
498         */
499        @Override
500        public String getSourceAccountingLinesSectionTitle() {
501            return KFSConstants.BudgetAdjustmentDocumentConstants.SOURCE_BA;
502        }
503    
504        /**
505         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getTargetAccountingLinesSectionTitle()
506         */
507        @Override
508        public String getTargetAccountingLinesSectionTitle() {
509            return KFSConstants.BudgetAdjustmentDocumentConstants.TARGET_BA;
510        }
511    
512        /**
513         * @see org.kuali.rice.kns.document.DocumentBase#populateDocumentForRouting()
514         */
515        @Override
516        public void populateDocumentForRouting() {
517            super.populateDocumentForRouting();
518    
519            // set amount fields of line for routing to current amount field
520            for (Iterator iter = this.getSourceAccountingLines().iterator(); iter.hasNext();) {
521                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
522                line.setAmount(line.getCurrentBudgetAdjustmentAmount());
523            }
524    
525            for (Iterator iter = this.getTargetAccountingLines().iterator(); iter.hasNext();) {
526                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
527                line.setAmount(line.getCurrentBudgetAdjustmentAmount());
528            }
529        }
530    
531        /**
532         * Returns true if accounting line is debit
533         * 
534         * @param financialDocument submitted financial document
535         * @param accountingLine accounting line being evaluated as a debit or not
536         * @see org.kuali.rice.kns.rule.AccountingLineRule#isDebit(org.kuali.rice.kns.document.FinancialDocument,
537         *      org.kuali.rice.kns.bo.AccountingLine)
538         */
539        @Override
540        public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) {
541            try {
542                DebitDeterminerService isDebitUtils = SpringContext.getBean(DebitDeterminerService.class);
543                return isDebitUtils.isDebitConsideringType(this, (AccountingLine) postable);
544            }
545            catch (IllegalStateException e) {
546                // for all accounting lines except the transfer lines, the line amount will be 0 and this exception will be thrown
547                return false;
548            }
549        }
550    
551        /**
552         * The budget adjustment document creates GL pending entries much differently that common tp-edocs. The glpes are created for
553         * BB, CB, and MB balance types. Up to 14 entries per line can be created. Along with this, the BA will create TOF entries if
554         * needed to move funding.
555         * 
556         * @param financialDocument submitted accounting document
557         * @param accountingLine validated accounting line
558         * @param sequenceHelper helper class for keeping track of sequence number
559         * @return true if GLPE entries are successfully created.
560         * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processGenerateGeneralLedgerPendingEntries(org.kuali.rice.kns.document.FinancialDocument,
561         *      org.kuali.rice.kns.bo.AccountingLine, org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
562         */
563        @Override
564        public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
565            AccountingLine accountingLine = (AccountingLine) glpeSourceDetail;
566    
567            // determine if we are on increase or decrease side
568            KualiDecimal amountSign = null;
569            if (accountingLine instanceof SourceAccountingLine) {
570                amountSign = new KualiDecimal(-1);
571            }
572            else {
573                amountSign = new KualiDecimal(1);
574            }
575    
576            BudgetAdjustmentAccountingLine budgetAccountingLine = (BudgetAdjustmentAccountingLine) glpeSourceDetail;
577            Integer currentFiscalYear = SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
578            /* Create Base Budget GLPE if base amount != 0 */
579            if (budgetAccountingLine.getBaseBudgetAdjustmentAmount().isNonZero()) {
580                GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
581                getGeneralLedgerPendingEntryService().populateExplicitGeneralLedgerPendingEntry(this, accountingLine, sequenceHelper, explicitEntry);
582    
583                /* D/C code is empty for BA, set correct balance type, correct amount */
584                explicitEntry.setTransactionDebitCreditCode("");
585                explicitEntry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_BASE_BUDGET);
586                explicitEntry.setTransactionLedgerEntryAmount(budgetAccountingLine.getBaseBudgetAdjustmentAmount().multiply(amountSign).kualiDecimalValue());
587                // set fiscal period, if next fiscal year set to 01, else leave to current period
588                if (currentFiscalYear.equals(getPostingYear() - 1)) {
589                    explicitEntry.setUniversityFiscalPeriodCode(BudgetAdjustmentDocumentRuleConstants.MONTH_1_PERIOD_CODE);
590                }
591    
592                customizeExplicitGeneralLedgerPendingEntry(accountingLine, explicitEntry);
593    
594                addPendingEntry(explicitEntry);
595    
596                // increment the sequence counter
597                sequenceHelper.increment();
598            }
599    
600            /* Create Current Budget GLPE if current amount != 0 */
601            if (budgetAccountingLine.getCurrentBudgetAdjustmentAmount().isNonZero()) {
602                GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
603                getGeneralLedgerPendingEntryService().populateExplicitGeneralLedgerPendingEntry(this, accountingLine, sequenceHelper, explicitEntry);
604    
605                /* D/C code is empty for BA, set correct balance type, correct amount */
606                explicitEntry.setTransactionDebitCreditCode("");
607                explicitEntry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
608                explicitEntry.setTransactionLedgerEntryAmount(budgetAccountingLine.getCurrentBudgetAdjustmentAmount().multiply(amountSign));
609                // set fiscal period, if next fiscal year set to 01, else leave to current period
610                if (currentFiscalYear.equals(getPostingYear() - 1)) {
611                    explicitEntry.setUniversityFiscalPeriodCode("01");
612                }
613    
614                customizeExplicitGeneralLedgerPendingEntry(accountingLine, explicitEntry);
615    
616                addPendingEntry(explicitEntry);
617    
618                // create monthly lines (MB)
619                if (budgetAccountingLine.getFinancialDocumentMonth1LineAmount().isNonZero()) {
620                    sequenceHelper.increment();
621                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_1_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth1LineAmount().multiply(amountSign));
622                }
623                if (budgetAccountingLine.getFinancialDocumentMonth2LineAmount().isNonZero()) {
624                    sequenceHelper.increment();
625                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_2_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth2LineAmount().multiply(amountSign));
626                }
627                if (budgetAccountingLine.getFinancialDocumentMonth3LineAmount().isNonZero()) {
628                    sequenceHelper.increment();
629                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_3_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth3LineAmount().multiply(amountSign));
630                }
631                if (budgetAccountingLine.getFinancialDocumentMonth4LineAmount().isNonZero()) {
632                    sequenceHelper.increment();
633                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_4_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth4LineAmount().multiply(amountSign));
634                }
635                if (budgetAccountingLine.getFinancialDocumentMonth5LineAmount().isNonZero()) {
636                    sequenceHelper.increment();
637                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_5_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth5LineAmount().multiply(amountSign));
638                }
639                if (budgetAccountingLine.getFinancialDocumentMonth6LineAmount().isNonZero()) {
640                    sequenceHelper.increment();
641                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_6_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth6LineAmount().multiply(amountSign));
642                }
643                if (budgetAccountingLine.getFinancialDocumentMonth7LineAmount().isNonZero()) {
644                    sequenceHelper.increment();
645                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_7_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth7LineAmount().multiply(amountSign));
646                }
647                if (budgetAccountingLine.getFinancialDocumentMonth8LineAmount().isNonZero()) {
648                    sequenceHelper.increment();
649                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_8_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth8LineAmount().multiply(amountSign));
650                }
651                if (budgetAccountingLine.getFinancialDocumentMonth9LineAmount().isNonZero()) {
652                    sequenceHelper.increment();
653                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_9_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth9LineAmount().multiply(amountSign));
654                }
655                if (budgetAccountingLine.getFinancialDocumentMonth10LineAmount().isNonZero()) {
656                    sequenceHelper.increment();
657                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_10_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth10LineAmount().multiply(amountSign));
658                }
659                if (budgetAccountingLine.getFinancialDocumentMonth11LineAmount().isNonZero()) {
660                    sequenceHelper.increment();
661                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_11_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth11LineAmount().multiply(amountSign));
662                }
663                if (budgetAccountingLine.getFinancialDocumentMonth12LineAmount().isNonZero()) {
664                    sequenceHelper.increment();
665                    createMonthlyBudgetGLPE(accountingLine, sequenceHelper, BudgetAdjustmentDocumentRuleConstants.MONTH_12_PERIOD_CODE, budgetAccountingLine.getFinancialDocumentMonth12LineAmount().multiply(amountSign));
666                }
667            }
668            return true;
669        }
670    
671        /**
672         * Helper method for creating monthly budget pending entry lines.
673         * 
674         * @param financialDocument submitted accounting document
675         * @param accountingLine validated accounting line
676         * @param sequenceHelper helper class for keeping track of sequence number
677         * @param fiscalPeriod fiscal year period code
678         * @param monthAmount ledger entry amount for the month
679         */
680        protected void createMonthlyBudgetGLPE(AccountingLine accountingLine, GeneralLedgerPendingEntrySequenceHelper sequenceHelper, String fiscalPeriod, KualiDecimal monthAmount) {
681            GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
682            getGeneralLedgerPendingEntryService().populateExplicitGeneralLedgerPendingEntry(this, accountingLine, sequenceHelper, explicitEntry);
683    
684            /* D/C code is empty for BA, set correct balance type, correct amount */
685            explicitEntry.setTransactionDebitCreditCode("");
686            explicitEntry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_MONTHLY_BUDGET);
687            explicitEntry.setTransactionLedgerEntryAmount(monthAmount);
688            explicitEntry.setUniversityFiscalPeriodCode(fiscalPeriod);
689    
690            customizeExplicitGeneralLedgerPendingEntry(accountingLine, explicitEntry);
691    
692            addPendingEntry(explicitEntry);
693        }
694    
695        /**
696         * Returns an implementation of the GeneralLedgerPendingEntryService
697         * 
698         * @return an implementation of the GeneralLedgerPendingEntryService
699         */
700        public GeneralLedgerPendingEntryService getGeneralLedgerPendingEntryService() {
701            return SpringContext.getBean(GeneralLedgerPendingEntryService.class);
702        }
703    
704        /**
705         * Generates any necessary tof entries to transfer funds needed to make the budget adjustments. Based on income chart and
706         * accounts. If there is a difference in funds between an income chart and account, a tof entry needs to be created, along with
707         * a budget adjustment entry. Object code used is retrieved by a parameter.
708         * 
709         * @param sequenceHelper helper class for keeping track of sequence number
710         * @return true general ledger pending entries are generated without any problems
711         * @see org.kuali.rice.kns.rule.GenerateGeneralLedgerDocumentPendingEntriesRule#processGenerateDocumentGeneralLedgerPendingEntries(org.kuali.rice.kns.document.FinancialDocument,
712         *      org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
713         */
714        @Override
715        public boolean generateDocumentGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
716            boolean success = true;
717    
718            // check on-off tof flag
719            boolean generateTransfer = SpringContext.getBean(ParameterService.class).getIndicatorParameter(BudgetAdjustmentDocument.class, BudgetAdjustmentDocumentRuleConstants.GENERATE_TOF_GLPE_ENTRIES_PARM_NM);
720            String transferObjectCode = SpringContext.getBean(ParameterService.class).getParameterValue(BudgetAdjustmentDocument.class, BudgetAdjustmentDocumentRuleConstants.TRANSFER_OBJECT_CODE_PARM_NM);
721            Integer currentFiscalYear = SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
722    
723            if (generateTransfer) {
724                // map of income chart/accounts with balance as value
725                Map<String, KualiDecimal> incomeStreamMap = buildIncomeStreamBalanceMapForTransferOfFundsGeneration();
726                GeneralLedgerPendingEntryService glpeService = SpringContext.getBean(GeneralLedgerPendingEntryService.class);
727                for (Iterator iter = incomeStreamMap.keySet().iterator(); iter.hasNext();) {
728                    String chartAccount = (String) iter.next();
729                    KualiDecimal streamAmount = (KualiDecimal) incomeStreamMap.get(chartAccount);
730                    if (streamAmount.isNonZero()) {
731                        // build dummy accounting line for gl population
732                        AccountingLine accountingLine = null;
733                        try {
734                            accountingLine = (SourceAccountingLine) getSourceAccountingLineClass().newInstance();
735                        }
736                        catch (IllegalAccessException e) {
737                            throw new InfrastructureException("unable to access sourceAccountingLineClass", e);
738                        }
739                        catch (InstantiationException e) {
740                            throw new InfrastructureException("unable to instantiate sourceAccountingLineClass", e);
741                        }
742    
743                        // set income chart and account in line
744                        String[] incomeString = StringUtils.split(chartAccount, BudgetAdjustmentDocumentRuleConstants.INCOME_STREAM_CHART_ACCOUNT_DELIMITER);
745                        accountingLine.setChartOfAccountsCode(incomeString[0]);
746                        accountingLine.setAccountNumber(incomeString[1]);
747                        accountingLine.setFinancialObjectCode(transferObjectCode);
748    
749                        // ////////////////// first create current budget entry/////////////////////////////////////////
750                        GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
751                        glpeService.populateExplicitGeneralLedgerPendingEntry(this, accountingLine, sequenceHelper, explicitEntry);
752    
753                        /* override and set object type to income */
754                        SystemOptions options = SpringContext.getBean(OptionsService.class).getCurrentYearOptions();
755                        explicitEntry.setFinancialObjectTypeCode(options.getFinObjectTypeIncomecashCode());
756    
757                        /* D/C code is empty for BA, set correct balance type, correct amount */
758                        explicitEntry.setTransactionDebitCreditCode("");
759                        explicitEntry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
760                        explicitEntry.setTransactionLedgerEntryAmount(streamAmount);
761    
762                        // set fiscal period, if next fiscal year set to 01, else leave to current period
763                        if (currentFiscalYear.equals(getPostingYear() - 1)) {
764                            explicitEntry.setUniversityFiscalPeriodCode(BudgetAdjustmentDocumentRuleConstants.MONTH_1_PERIOD_CODE);
765                        }
766    
767                        customizeExplicitGeneralLedgerPendingEntry(accountingLine, explicitEntry);
768    
769                        // add the new explicit entry to the document now
770                        addPendingEntry(explicitEntry);
771    
772                        // increment the sequence counter
773                        sequenceHelper.increment();
774    
775    
776                        // ////////////////// now create actual TOF entry //////////////////////////////////////////////
777                        /* set amount in line so Debit/Credit code can be set correctly */
778                        accountingLine.setAmount(streamAmount);
779                        explicitEntry = new GeneralLedgerPendingEntry();
780                        glpeService.populateExplicitGeneralLedgerPendingEntry(this, accountingLine, sequenceHelper, explicitEntry);
781    
782                        /* override and set object type to transfer */
783                        explicitEntry.setFinancialObjectTypeCode(options.getFinancialObjectTypeTransferIncomeCd());
784    
785                        /* set document type to tof */
786                        explicitEntry.setFinancialDocumentTypeCode(getTransferDocumentType());
787    
788                        // set fiscal period, if next fiscal year set to 01, else leave to current period
789                        if (currentFiscalYear.equals(getPostingYear() - 1)) {
790                            explicitEntry.setUniversityFiscalPeriodCode(BudgetAdjustmentDocumentRuleConstants.MONTH_1_PERIOD_CODE);
791                        }
792    
793                        // add the new explicit entry to the document now
794                        addPendingEntry(explicitEntry);
795    
796                        customizeExplicitGeneralLedgerPendingEntry(accountingLine, explicitEntry);
797    
798                        // increment the sequence counter
799                        sequenceHelper.increment();
800    
801                        // ////////////////// now create actual TOF offset //////////////////////////////////////////////
802                        GeneralLedgerPendingEntry offsetEntry = new GeneralLedgerPendingEntry(explicitEntry);
803                        success &= glpeService.populateOffsetGeneralLedgerPendingEntry(getPostingYear(), explicitEntry, sequenceHelper, offsetEntry);
804                        customizeOffsetGeneralLedgerPendingEntry(accountingLine, explicitEntry, offsetEntry);
805                        addPendingEntry(offsetEntry);
806    
807                        // increment the sequence counter
808                        sequenceHelper.increment();
809                    }
810                }
811            }
812            return success;
813        }
814    
815        /**
816         * Builds a map used for balancing current adjustment amounts. The map contains income chart and accounts contained on the
817         * document as the keys, and transfer amounts as the values.  The transfer amount is calculated from (curr_frm_inc - curr_frm_exp) - (curr_to_inc - curr_to_exp)
818         * 
819         * @param baDocument budget adjustment document
820         * @return Map used to balance current amounts
821         */
822        public Map buildIncomeStreamBalanceMapForTransferOfFundsGeneration() {
823            Map<String, KualiDecimal> incomeStreamBalance = new HashMap<String, KualiDecimal>();
824    
825            List<BudgetAdjustmentAccountingLine> accountingLines = new ArrayList<BudgetAdjustmentAccountingLine>();
826            accountingLines.addAll(getSourceAccountingLines());
827            accountingLines.addAll(getTargetAccountingLines());
828            for (BudgetAdjustmentAccountingLine budgetAccountingLine : accountingLines) {
829                
830                Account baAccount = budgetAccountingLine.getAccount();
831                
832                ParameterService paramService = SpringContext.getBean(ParameterService.class);
833                
834                if(paramService.getParameterEvaluator(BudgetAdjustmentDocument.class, KFSConstants.BudgetAdjustmentDocumentConstants.CROSS_INCOME_STREAM_GLPE_TRANSFER_GENERATING_FUND_GROUPS, baAccount.getSubFundGroup().getFundGroupCode()).evaluationSucceeds() &&
835                   paramService.getParameterEvaluator(BudgetAdjustmentDocument.class, KFSConstants.BudgetAdjustmentDocumentConstants.CROSS_INCOME_STREAM_GLPE_TRANSFER_GENERATING_SUB_FUND_GROUPS, baAccount.getSubFundGroupCode()).evaluationSucceeds()) {
836                    
837                    String incomeStreamKey = baAccount.getIncomeStreamFinancialCoaCode() + BudgetAdjustmentDocumentRuleConstants.INCOME_STREAM_CHART_ACCOUNT_DELIMITER + baAccount.getIncomeStreamAccountNumber();
838        
839                    // place record in balance map
840                    incomeStreamBalance.put(incomeStreamKey, getIncomeStreamAmount(budgetAccountingLine, incomeStreamBalance.get(incomeStreamKey)));
841                }
842            }
843    
844            return incomeStreamBalance;
845        }
846    
847        /**
848         * Builds a map used for balancing current adjustment amounts. The map contains income chart and accounts contained on the
849         * document as the keys, and transfer amounts as the values. The transfer amount is calculated from (curr_frm_inc - curr_frm_exp) - (curr_to_inc - curr_to_exp)
850         * 
851         * @param baDocument budget adjustment document
852         * @return Map used to balance current amounts
853         */
854        public Map buildIncomeStreamBalanceMapForDocumentBalance() {
855            Map<String, KualiDecimal> incomeStreamBalance = new HashMap<String, KualiDecimal>();
856    
857            List<BudgetAdjustmentAccountingLine> accountingLines = new ArrayList<BudgetAdjustmentAccountingLine>();
858            accountingLines.addAll(getSourceAccountingLines());
859            accountingLines.addAll(getTargetAccountingLines());
860            for (BudgetAdjustmentAccountingLine budgetAccountingLine : accountingLines) {
861                
862                String incomeStreamKey = budgetAccountingLine.getAccount().getIncomeStreamFinancialCoaCode() + BudgetAdjustmentDocumentRuleConstants.INCOME_STREAM_CHART_ACCOUNT_DELIMITER + budgetAccountingLine.getAccount().getIncomeStreamAccountNumber();
863    
864                // place record in balance map
865                incomeStreamBalance.put(incomeStreamKey, getIncomeStreamAmount(budgetAccountingLine, incomeStreamBalance.get(incomeStreamKey)));
866            }
867    
868            return incomeStreamBalance;
869        }
870    
871        /**
872         * 
873         * This method calculates the appropriate income stream amount for an account using the value provided and the provided accounting line.
874         * 
875         * @param budgetAccountingLine
876         * @param incomeStreamAmount
877         * @return
878         */
879        protected KualiDecimal getIncomeStreamAmount(BudgetAdjustmentAccountingLine budgetAccountingLine, KualiDecimal incomeStreamAmount) {
880            if(incomeStreamAmount == null) {
881                incomeStreamAmount = new KualiDecimal(0);
882            }
883    
884            // amounts need to be reversed for source expense lines and target income lines
885            DebitDeterminerService isDebitUtils = SpringContext.getBean(DebitDeterminerService.class);
886            if ((budgetAccountingLine instanceof BudgetAdjustmentSourceAccountingLine && isDebitUtils.isExpense((AccountingLine) budgetAccountingLine)) || (budgetAccountingLine instanceof BudgetAdjustmentTargetAccountingLine && isDebitUtils.isIncome((AccountingLine) budgetAccountingLine))) {
887                incomeStreamAmount = incomeStreamAmount.subtract(budgetAccountingLine.getCurrentBudgetAdjustmentAmount());
888            }
889            else {
890                incomeStreamAmount = incomeStreamAmount.add(budgetAccountingLine.getCurrentBudgetAdjustmentAmount());
891            }
892    
893            return incomeStreamAmount;
894        }
895        
896        /**
897         * Returns the document type code for the Transfer of Funds document
898         * 
899         * @return the document type name to be used for the income stream transfer glpe
900         */
901        protected String getTransferDocumentType() {
902            return TransferOfFundsDocumentRuleConstants.TRANSFER_OF_FUNDS_DOC_TYPE_CODE;
903        }
904    
905    
906        /**
907         * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
908         */
909        @Override
910        public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
911            if (nodeName.equals(BudgetAdjustmentDocument.REQUIRES_FULL_APPROVAL_SPLIT_NODE_NAME)) return requiresFullApproval();
912            throw new UnsupportedOperationException("No split node logic defined for split node "+nodeName+" on the Budget Adjustment document");
913        }
914    
915        /**
916         * Determines if this document can be auto-approved or not. The conditions for auto-approval are: 1) Single account used on document 2) Initiator is
917         * fiscal officer or primary delegate for the account 3) Only current adjustments are being made 4) The fund group for the account
918         * is not contract and grants 5) current income/expense decrease amount must equal increase amount
919         * @return false if auto-approval can occur (and therefore, full approval is not required); true if a full approval is required
920         */
921        protected boolean requiresFullApproval() {
922            boolean fullApprovalRequired = false;
923    
924            // new list so that sourceAccountingLines isn't modified by addAll statement. Important for
925            // total calculations below.
926            List accountingLines = new ArrayList();
927            accountingLines.addAll(getSourceAccountingLines());
928            accountingLines.addAll(getTargetAccountingLines());
929    
930            /* only one account can be present on document and only current adjustments allowed */
931            String chart = "";
932            String accountNumber = "";
933            for (Iterator iter = accountingLines.iterator(); iter.hasNext();) {
934                BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter.next();
935                if (StringUtils.isNotBlank(accountNumber)) {
936                    if (!accountNumber.equals(line.getAccountNumber()) && !chart.equals(line.getChartOfAccountsCode())) {
937                        fullApprovalRequired = true;
938                        break;
939                    }
940                }
941    
942                if (line.getBaseBudgetAdjustmentAmount().isNonZero()) {
943                    fullApprovalRequired = true;
944                    break;
945                }
946                chart = line.getChartOfAccountsCode();
947                accountNumber = line.getAccountNumber();
948            }
949    
950            // check remaining conditions
951            if (!fullApprovalRequired) {
952                // initiator should be fiscal officer or primary delegate for account
953                Person initiator = SpringContext.getBean(org.kuali.rice.kim.service.PersonService.class).getPersonByPrincipalName(getDocumentHeader().getWorkflowDocument().getInitiatorNetworkId());
954                List userAccounts = SpringContext.getBean(AccountService.class).getAccountsThatUserIsResponsibleFor(initiator);
955                Account userAccount = null;
956                for (Iterator iter = userAccounts.iterator(); iter.hasNext();) {
957                    AccountResponsibility account = (AccountResponsibility) iter.next();
958                    if (accountNumber.equals(account.getAccount().getAccountNumber()) && chart.equals(account.getAccount().getChartOfAccountsCode())) {
959                        userAccount = account.getAccount();
960                        break;
961                    }
962                }
963    
964                if (userAccount == null) {
965                    fullApprovalRequired = true;
966                }
967                else {
968                    // fund group should not be CG
969                    if (userAccount.isForContractsAndGrants()) {
970                        fullApprovalRequired = true;
971                    }
972    
973                    // current income/expense decrease amount must equal increase amount
974                    if (!getSourceCurrentBudgetIncomeTotal().equals(getTargetCurrentBudgetIncomeTotal()) || !getSourceCurrentBudgetExpenseTotal().equals(getTargetCurrentBudgetExpenseTotal())) {
975                        fullApprovalRequired = true;
976                    }
977                }
978            }
979            
980            return fullApprovalRequired;
981        }
982    }