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 }