0001: /*
0002: * Copyright 2006-2007 The Kuali Foundation.
0003: *
0004: * Licensed under the Educational Community License, Version 1.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.opensource.org/licenses/ecl1.php
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.kuali.module.financial.rules;
0017:
0018: import static org.kuali.kfs.KFSConstants.SOURCE_ACCOUNTING_LINE_ERRORS;
0019: import static org.kuali.kfs.KFSConstants.TARGET_ACCOUNTING_LINE_ERRORS;
0020: import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_TOTAL_CHANGED;
0021: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.GENERATE_TOF_GLPE_ENTRIES_PARM_NM;
0022: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_10_PERIOD_CODE;
0023: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_11_PERIOD_CODE;
0024: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_12_PERIOD_CODE;
0025: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_1_PERIOD_CODE;
0026: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_2_PERIOD_CODE;
0027: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_3_PERIOD_CODE;
0028: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_4_PERIOD_CODE;
0029: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_5_PERIOD_CODE;
0030: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_6_PERIOD_CODE;
0031: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_7_PERIOD_CODE;
0032: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_8_PERIOD_CODE;
0033: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.MONTH_9_PERIOD_CODE;
0034: import static org.kuali.module.financial.rules.BudgetAdjustmentDocumentRuleConstants.TRANSFER_OBJECT_CODE_PARM_NM;
0035: import static org.kuali.module.financial.rules.TransferOfFundsDocumentRuleConstants.TRANSFER_OF_FUNDS_DOC_TYPE_CODE;
0036:
0037: import java.util.ArrayList;
0038: import java.util.HashMap;
0039: import java.util.Iterator;
0040: import java.util.List;
0041: import java.util.Map;
0042:
0043: import org.apache.commons.lang.StringUtils;
0044: import org.kuali.core.document.Document;
0045: import org.kuali.core.exceptions.InfrastructureException;
0046: import org.kuali.core.util.ErrorMap;
0047: import org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper;
0048: import org.kuali.core.util.GlobalVariables;
0049: import org.kuali.core.util.KualiDecimal;
0050: import org.kuali.core.util.KualiInteger;
0051: import org.kuali.core.util.ObjectUtils;
0052: import org.kuali.core.web.format.CurrencyFormatter;
0053: import org.kuali.kfs.KFSConstants;
0054: import org.kuali.kfs.KFSKeyConstants;
0055: import org.kuali.kfs.KFSPropertyConstants;
0056: import org.kuali.kfs.bo.AccountingLine;
0057: import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
0058: import org.kuali.kfs.bo.Options;
0059: import org.kuali.kfs.bo.SourceAccountingLine;
0060: import org.kuali.kfs.context.SpringContext;
0061: import org.kuali.kfs.document.AccountingDocument;
0062: import org.kuali.kfs.rule.GenerateGeneralLedgerDocumentPendingEntriesRule;
0063: import org.kuali.kfs.rules.AccountingDocumentRuleBase;
0064: import org.kuali.kfs.rules.AccountingLineRuleUtil;
0065: import org.kuali.kfs.service.OptionsService;
0066: import org.kuali.kfs.service.ParameterService;
0067: import org.kuali.module.chart.bo.SubFundGroup;
0068: import org.kuali.module.financial.bo.BudgetAdjustmentAccountingLine;
0069: import org.kuali.module.financial.bo.BudgetAdjustmentSourceAccountingLine;
0070: import org.kuali.module.financial.bo.BudgetAdjustmentTargetAccountingLine;
0071: import org.kuali.module.financial.document.BudgetAdjustmentDocument;
0072: import org.kuali.module.financial.service.FiscalYearFunctionControlService;
0073: import org.kuali.module.financial.service.UniversityDateService;
0074:
0075: /**
0076: * Business rule(s) applicable to Budget Adjustment Card document.
0077: */
0078: public class BudgetAdjustmentDocumentRule extends
0079: AccountingDocumentRuleBase
0080: implements
0081: GenerateGeneralLedgerDocumentPendingEntriesRule<AccountingDocument> {
0082:
0083: private static final String INCOME_STREAM_CHART_ACCOUNT_DELIMITER = "|";
0084:
0085: /**
0086: * Validates when an accounting line is added to a budget adjustment document. Accounting line's budget adjustment amount must
0087: * be non zero and a budget adjustment must be allowed. In addition, the monthly amount fields must equal the current budget
0088: * amount and the accounting line's account must have a budget recording level and if current adjustment amount is non zero,
0089: * account must have an associated income stream chart and account.
0090: *
0091: * @param financialDocument submitted document
0092: * @param accountingLine validated accouting line
0093: * @return true if validation criteria listed above is true
0094: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomAddAccountingLineBusinessRules(org.kuali.core.document.FinancialDocument,
0095: * org.kuali.core.bo.AccountingLine)
0096: */
0097: @Override
0098: protected boolean processCustomAddAccountingLineBusinessRules(
0099: AccountingDocument financialDocument,
0100: AccountingLine accountingLine) {
0101: boolean allow = true;
0102: BudgetAdjustmentAccountingLine budgetAccountingLine = (BudgetAdjustmentAccountingLine) accountingLine;
0103:
0104: LOG.debug("validating accounting line # "
0105: + accountingLine.getSequenceNumber());
0106:
0107: /* if they have entered a base amount for line, verify it can be adjusted for the posting year */
0108: if (budgetAccountingLine.getBaseBudgetAdjustmentAmount()
0109: .isNonZero()
0110: && !SpringContext
0111: .getBean(FiscalYearFunctionControlService.class)
0112: .isBaseAmountChangeAllowed(
0113: ((BudgetAdjustmentDocument) financialDocument)
0114: .getPostingYear())) {
0115: GlobalVariables
0116: .getErrorMap()
0117: .putError(
0118: KFSPropertyConstants.BASE_BUDGET_ADJUSTMENT_AMOUNT,
0119: KFSKeyConstants.ERROR_DOCUMENT_BA_BASE_AMOUNT_CHANGE_NOT_ALLOWED);
0120: allow = false;
0121: }
0122:
0123: LOG.debug("beginning monthly lines validation ");
0124: allow = allow
0125: && validateMonthlyLines(financialDocument,
0126: accountingLine);
0127:
0128: LOG.debug("beginning account number validation ");
0129: allow = allow
0130: && validateAccountNumber(financialDocument,
0131: accountingLine);
0132:
0133: LOG.debug("end validating accounting line, has errors: "
0134: + allow);
0135:
0136: return allow;
0137: }
0138:
0139: /**
0140: * Calls FinancialDocumentRuleBase.processCustomRouteDocumentBusinessRules() and also validates whether the document's
0141: * accounting lines' fund group and sub fund group codes associate with the 'Budget Adjustment Restriction Code'
0142: *
0143: * @param document submitted document
0144: * @return true if criteria above is met
0145: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.core.document.Document)
0146: */
0147: @Override
0148: protected boolean processCustomRouteDocumentBusinessRules(
0149: Document document) {
0150: boolean isValid = super
0151: .processCustomRouteDocumentBusinessRules(document);
0152: BudgetAdjustmentDocument baDocument = (BudgetAdjustmentDocument) document;
0153:
0154: if (isValid) {
0155: isValid = isValid
0156: && validateFundGroupAdjustmentRestrictions(baDocument);
0157: }
0158:
0159: return isValid;
0160: }
0161:
0162: /**
0163: * The budget adjustment document creates GL pending entries much differently that common tp-edocs. The glpes are created for
0164: * 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
0165: * needed to move funding.
0166: *
0167: * @param financialDocument submitted accounting document
0168: * @param accountingLine validated accounting line
0169: * @param sequenceHelper helper class for keeping track of sequence number
0170: * @return true if GLPE entries are successfully created.
0171: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#processGenerateGeneralLedgerPendingEntries(org.kuali.core.document.FinancialDocument,
0172: * org.kuali.core.bo.AccountingLine, org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper)
0173: */
0174: @Override
0175: public boolean processGenerateGeneralLedgerPendingEntries(
0176: AccountingDocument financialDocument,
0177: AccountingLine accountingLine,
0178: GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
0179: boolean success = true;
0180:
0181: // determine if we are on increase or decrease side
0182: KualiDecimal amountSign = null;
0183: if (accountingLine instanceof SourceAccountingLine) {
0184: amountSign = new KualiDecimal(-1);
0185: } else {
0186: amountSign = new KualiDecimal(1);
0187: }
0188:
0189: BudgetAdjustmentAccountingLine budgetAccountingLine = (BudgetAdjustmentAccountingLine) accountingLine;
0190: Integer currentFiscalYear = SpringContext.getBean(
0191: UniversityDateService.class).getCurrentFiscalYear();
0192: /* Create Base Budget GLPE if base amount != 0 */
0193: if (budgetAccountingLine.getBaseBudgetAdjustmentAmount()
0194: .isNonZero()) {
0195: GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
0196: populateExplicitGeneralLedgerPendingEntry(
0197: financialDocument, accountingLine, sequenceHelper,
0198: explicitEntry);
0199:
0200: /* D/C code is empty for BA, set correct balance type, correct amount */
0201: explicitEntry.setTransactionDebitCreditCode("");
0202: explicitEntry
0203: .setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_BASE_BUDGET);
0204: explicitEntry
0205: .setTransactionLedgerEntryAmount(budgetAccountingLine
0206: .getBaseBudgetAdjustmentAmount().multiply(
0207: amountSign).kualiDecimalValue());
0208: // set fiscal period, if next fiscal year set to 01, else leave to current period
0209: if (currentFiscalYear.equals(financialDocument
0210: .getPostingYear() - 1)) {
0211: explicitEntry
0212: .setUniversityFiscalPeriodCode(MONTH_1_PERIOD_CODE);
0213: }
0214:
0215: customizeExplicitGeneralLedgerPendingEntry(
0216: financialDocument, accountingLine, explicitEntry);
0217:
0218: // add the new explicit entry to the document now
0219: financialDocument.getGeneralLedgerPendingEntries().add(
0220: explicitEntry);
0221:
0222: // increment the sequence counter
0223: sequenceHelper.increment();
0224: }
0225:
0226: /* Create Current Budget GLPE if current amount != 0 */
0227: if (budgetAccountingLine.getCurrentBudgetAdjustmentAmount()
0228: .isNonZero()) {
0229: GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
0230: populateExplicitGeneralLedgerPendingEntry(
0231: financialDocument, accountingLine, sequenceHelper,
0232: explicitEntry);
0233:
0234: /* D/C code is empty for BA, set correct balance type, correct amount */
0235: explicitEntry.setTransactionDebitCreditCode("");
0236: explicitEntry
0237: .setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
0238: explicitEntry
0239: .setTransactionLedgerEntryAmount(budgetAccountingLine
0240: .getCurrentBudgetAdjustmentAmount()
0241: .multiply(amountSign));
0242: // set fiscal period, if next fiscal year set to 01, else leave to current period
0243: if (currentFiscalYear.equals(financialDocument
0244: .getPostingYear() - 1)) {
0245: explicitEntry.setUniversityFiscalPeriodCode("01");
0246: }
0247:
0248: customizeExplicitGeneralLedgerPendingEntry(
0249: financialDocument, accountingLine, explicitEntry);
0250:
0251: // add the new explicit entry to the document now
0252: financialDocument.getGeneralLedgerPendingEntries().add(
0253: explicitEntry);
0254:
0255: // create montly lines (MB)
0256: if (budgetAccountingLine
0257: .getFinancialDocumentMonth1LineAmount().isNonZero()) {
0258: sequenceHelper.increment();
0259: createMonthlyBudgetGLPE(financialDocument,
0260: accountingLine, sequenceHelper,
0261: MONTH_1_PERIOD_CODE, budgetAccountingLine
0262: .getFinancialDocumentMonth1LineAmount()
0263: .multiply(amountSign));
0264: }
0265: if (budgetAccountingLine
0266: .getFinancialDocumentMonth2LineAmount().isNonZero()) {
0267: sequenceHelper.increment();
0268: createMonthlyBudgetGLPE(financialDocument,
0269: accountingLine, sequenceHelper,
0270: MONTH_2_PERIOD_CODE, budgetAccountingLine
0271: .getFinancialDocumentMonth2LineAmount()
0272: .multiply(amountSign));
0273: }
0274: if (budgetAccountingLine
0275: .getFinancialDocumentMonth3LineAmount().isNonZero()) {
0276: sequenceHelper.increment();
0277: createMonthlyBudgetGLPE(financialDocument,
0278: accountingLine, sequenceHelper,
0279: MONTH_3_PERIOD_CODE, budgetAccountingLine
0280: .getFinancialDocumentMonth3LineAmount()
0281: .multiply(amountSign));
0282: }
0283: if (budgetAccountingLine
0284: .getFinancialDocumentMonth4LineAmount().isNonZero()) {
0285: sequenceHelper.increment();
0286: createMonthlyBudgetGLPE(financialDocument,
0287: accountingLine, sequenceHelper,
0288: MONTH_4_PERIOD_CODE, budgetAccountingLine
0289: .getFinancialDocumentMonth4LineAmount()
0290: .multiply(amountSign));
0291: }
0292: if (budgetAccountingLine
0293: .getFinancialDocumentMonth5LineAmount().isNonZero()) {
0294: sequenceHelper.increment();
0295: createMonthlyBudgetGLPE(financialDocument,
0296: accountingLine, sequenceHelper,
0297: MONTH_5_PERIOD_CODE, budgetAccountingLine
0298: .getFinancialDocumentMonth5LineAmount()
0299: .multiply(amountSign));
0300: }
0301: if (budgetAccountingLine
0302: .getFinancialDocumentMonth6LineAmount().isNonZero()) {
0303: sequenceHelper.increment();
0304: createMonthlyBudgetGLPE(financialDocument,
0305: accountingLine, sequenceHelper,
0306: MONTH_6_PERIOD_CODE, budgetAccountingLine
0307: .getFinancialDocumentMonth6LineAmount()
0308: .multiply(amountSign));
0309: }
0310: if (budgetAccountingLine
0311: .getFinancialDocumentMonth7LineAmount().isNonZero()) {
0312: sequenceHelper.increment();
0313: createMonthlyBudgetGLPE(financialDocument,
0314: accountingLine, sequenceHelper,
0315: MONTH_7_PERIOD_CODE, budgetAccountingLine
0316: .getFinancialDocumentMonth7LineAmount()
0317: .multiply(amountSign));
0318: }
0319: if (budgetAccountingLine
0320: .getFinancialDocumentMonth8LineAmount().isNonZero()) {
0321: sequenceHelper.increment();
0322: createMonthlyBudgetGLPE(financialDocument,
0323: accountingLine, sequenceHelper,
0324: MONTH_8_PERIOD_CODE, budgetAccountingLine
0325: .getFinancialDocumentMonth8LineAmount()
0326: .multiply(amountSign));
0327: }
0328: if (budgetAccountingLine
0329: .getFinancialDocumentMonth9LineAmount().isNonZero()) {
0330: sequenceHelper.increment();
0331: createMonthlyBudgetGLPE(financialDocument,
0332: accountingLine, sequenceHelper,
0333: MONTH_9_PERIOD_CODE, budgetAccountingLine
0334: .getFinancialDocumentMonth9LineAmount()
0335: .multiply(amountSign));
0336: }
0337: if (budgetAccountingLine
0338: .getFinancialDocumentMonth10LineAmount()
0339: .isNonZero()) {
0340: sequenceHelper.increment();
0341: createMonthlyBudgetGLPE(
0342: financialDocument,
0343: accountingLine,
0344: sequenceHelper,
0345: MONTH_10_PERIOD_CODE,
0346: budgetAccountingLine
0347: .getFinancialDocumentMonth10LineAmount()
0348: .multiply(amountSign));
0349: }
0350: if (budgetAccountingLine
0351: .getFinancialDocumentMonth11LineAmount()
0352: .isNonZero()) {
0353: sequenceHelper.increment();
0354: createMonthlyBudgetGLPE(
0355: financialDocument,
0356: accountingLine,
0357: sequenceHelper,
0358: MONTH_11_PERIOD_CODE,
0359: budgetAccountingLine
0360: .getFinancialDocumentMonth11LineAmount()
0361: .multiply(amountSign));
0362: }
0363: if (budgetAccountingLine
0364: .getFinancialDocumentMonth12LineAmount()
0365: .isNonZero()) {
0366: sequenceHelper.increment();
0367: createMonthlyBudgetGLPE(
0368: financialDocument,
0369: accountingLine,
0370: sequenceHelper,
0371: MONTH_12_PERIOD_CODE,
0372: budgetAccountingLine
0373: .getFinancialDocumentMonth12LineAmount()
0374: .multiply(amountSign));
0375: }
0376: }
0377:
0378: return success;
0379: }
0380:
0381: /**
0382: * Helper method for creating monthly budget pending entry lines.
0383: *
0384: * @param financialDocument submitted accounting document
0385: * @param accountingLine validated accounting line
0386: * @param sequenceHelper helper class for keeping track of sequence number
0387: * @param fiscalPeriod fiscal year period code
0388: * @param monthAmount ledger entry amount for the month
0389: */
0390: private void createMonthlyBudgetGLPE(
0391: AccountingDocument financialDocument,
0392: AccountingLine accountingLine,
0393: GeneralLedgerPendingEntrySequenceHelper sequenceHelper,
0394: String fiscalPeriod, KualiDecimal monthAmount) {
0395: GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
0396: populateExplicitGeneralLedgerPendingEntry(financialDocument,
0397: accountingLine, sequenceHelper, explicitEntry);
0398:
0399: /* D/C code is empty for BA, set correct balance type, correct amount */
0400: explicitEntry.setTransactionDebitCreditCode("");
0401: explicitEntry
0402: .setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_MONTHLY_BUDGET);
0403: explicitEntry.setTransactionLedgerEntryAmount(monthAmount);
0404: explicitEntry.setUniversityFiscalPeriodCode(fiscalPeriod);
0405:
0406: customizeExplicitGeneralLedgerPendingEntry(financialDocument,
0407: accountingLine, explicitEntry);
0408:
0409: // add the new explicit entry to the document now
0410: financialDocument.getGeneralLedgerPendingEntries().add(
0411: explicitEntry);
0412: }
0413:
0414: /**
0415: * Generates any necessary tof entries to transfer funds needed to make the budget adjustments. Based on income chart and
0416: * accounts. If there is a difference in funds between an income chart and account, a tof entry needs to be created, along with
0417: * a budget adjustment entry. Object code used is retrieved by a parameter.
0418: *
0419: * @param financialDocument submitted accounting document
0420: * @param sequenceHelper helper class for keeping track of sequence number
0421: * @return true general ledger pending entries are generated without any problems
0422: * @see org.kuali.core.rule.GenerateGeneralLedgerDocumentPendingEntriesRule#processGenerateDocumentGeneralLedgerPendingEntries(org.kuali.core.document.FinancialDocument,
0423: * org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper)
0424: */
0425: public boolean processGenerateDocumentGeneralLedgerPendingEntries(
0426: AccountingDocument financialDocument,
0427: GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
0428: AccountingDocument FinancialDocument = (AccountingDocument) financialDocument;
0429: BudgetAdjustmentDocument baDocument = (BudgetAdjustmentDocument) FinancialDocument;
0430:
0431: boolean success = true;
0432:
0433: // check on-off tof flag
0434: boolean generateTransfer = SpringContext.getBean(
0435: ParameterService.class).getIndicatorParameter(
0436: BudgetAdjustmentDocument.class,
0437: GENERATE_TOF_GLPE_ENTRIES_PARM_NM);
0438: String transferObjectCode = SpringContext.getBean(
0439: ParameterService.class).getParameterValue(
0440: BudgetAdjustmentDocument.class,
0441: TRANSFER_OBJECT_CODE_PARM_NM);
0442: Integer currentFiscalYear = SpringContext.getBean(
0443: UniversityDateService.class).getCurrentFiscalYear();
0444:
0445: if (generateTransfer) {
0446: // map of income chart/accounts with balance as value
0447: Map incomeStreamMap = buildIncomeStreamBalanceMap(baDocument);
0448: for (Iterator iter = incomeStreamMap.keySet().iterator(); iter
0449: .hasNext();) {
0450: String chartAccount = (String) iter.next();
0451: KualiDecimal streamAmount = (KualiDecimal) incomeStreamMap
0452: .get(chartAccount);
0453: if (streamAmount.isNonZero()) {
0454: // build dummy accounting line for gl population
0455: AccountingLine accountingLine = null;
0456: try {
0457: accountingLine = (SourceAccountingLine) baDocument
0458: .getSourceAccountingLineClass()
0459: .newInstance();
0460: } catch (IllegalAccessException e) {
0461: throw new InfrastructureException(
0462: "unable to access sourceAccountingLineClass",
0463: e);
0464: } catch (InstantiationException e) {
0465: throw new InfrastructureException(
0466: "unable to instantiate sourceAccountingLineClass",
0467: e);
0468: }
0469:
0470: // set income chart and account in line
0471: String[] incomeString = StringUtils.split(
0472: chartAccount,
0473: INCOME_STREAM_CHART_ACCOUNT_DELIMITER);
0474: accountingLine
0475: .setChartOfAccountsCode(incomeString[0]);
0476: accountingLine.setAccountNumber(incomeString[1]);
0477: accountingLine
0478: .setFinancialObjectCode(transferObjectCode);
0479:
0480: // ////////////////// first create current budget entry/////////////////////////////////////////
0481: GeneralLedgerPendingEntry explicitEntry = new GeneralLedgerPendingEntry();
0482: populateExplicitGeneralLedgerPendingEntry(
0483: FinancialDocument, accountingLine,
0484: sequenceHelper, explicitEntry);
0485:
0486: /* override and set object type to income */
0487: Options options = SpringContext.getBean(
0488: OptionsService.class)
0489: .getCurrentYearOptions();
0490: explicitEntry.setFinancialObjectTypeCode(options
0491: .getFinObjectTypeIncomecashCode());
0492:
0493: /* D/C code is empty for BA, set correct balance type, correct amount */
0494: explicitEntry.setTransactionDebitCreditCode("");
0495: explicitEntry
0496: .setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
0497: explicitEntry
0498: .setTransactionLedgerEntryAmount(streamAmount);
0499:
0500: // set fiscal period, if next fiscal year set to 01, else leave to current period
0501: if (currentFiscalYear.equals(FinancialDocument
0502: .getPostingYear() - 1)) {
0503: explicitEntry
0504: .setUniversityFiscalPeriodCode(MONTH_1_PERIOD_CODE);
0505: }
0506:
0507: customizeExplicitGeneralLedgerPendingEntry(
0508: FinancialDocument, accountingLine,
0509: explicitEntry);
0510:
0511: // add the new explicit entry to the document now
0512: FinancialDocument.getGeneralLedgerPendingEntries()
0513: .add(explicitEntry);
0514:
0515: // increment the sequence counter
0516: sequenceHelper.increment();
0517:
0518: // ////////////////// now create actual TOF entry //////////////////////////////////////////////
0519: /* set amount in line so Debit/Credit code can be set correctly */
0520: accountingLine.setAmount(streamAmount);
0521: explicitEntry = new GeneralLedgerPendingEntry();
0522: populateExplicitGeneralLedgerPendingEntry(
0523: FinancialDocument, accountingLine,
0524: sequenceHelper, explicitEntry);
0525:
0526: /* override and set object type to transfer */
0527: explicitEntry.setFinancialObjectTypeCode(options
0528: .getFinancialObjectTypeTransferIncomeCd());
0529:
0530: /* set document type to tof */
0531: explicitEntry
0532: .setFinancialDocumentTypeCode(getTransferDocumentType());
0533:
0534: // set fiscal period, if next fiscal year set to 01, else leave to current period
0535: if (currentFiscalYear.equals(FinancialDocument
0536: .getPostingYear() - 1)) {
0537: explicitEntry
0538: .setUniversityFiscalPeriodCode(MONTH_1_PERIOD_CODE);
0539: }
0540:
0541: // add the new explicit entry to the document now
0542: FinancialDocument.getGeneralLedgerPendingEntries()
0543: .add(explicitEntry);
0544:
0545: customizeExplicitGeneralLedgerPendingEntry(
0546: FinancialDocument, accountingLine,
0547: explicitEntry);
0548:
0549: // increment the sequence counter
0550: sequenceHelper.increment();
0551:
0552: // ////////////////// now create actual TOF offset //////////////////////////////////////////////
0553: GeneralLedgerPendingEntry offsetEntry = (GeneralLedgerPendingEntry) ObjectUtils
0554: .deepCopy(explicitEntry);
0555: success &= processOffsetGeneralLedgerPendingEntry(
0556: FinancialDocument, sequenceHelper,
0557: accountingLine, explicitEntry, offsetEntry);
0558:
0559: // increment the sequence counter
0560: sequenceHelper.increment();
0561: }
0562: }
0563: }
0564:
0565: return success;
0566: }
0567:
0568: /**
0569: * Validates the total of the monthly amount fields (if not 0) equals the current budget amount. If current budget is 0, then
0570: * total of monthly fields must be 0.
0571: *
0572: * @param financialDocument submitted accounting document
0573: * @param accountingLine validated accounting line
0574: * @return true if monthly amount fields equals the current budget amount
0575: */
0576: public boolean validateMonthlyLines(
0577: AccountingDocument financialDocument,
0578: AccountingLine accountingLine) {
0579: BudgetAdjustmentAccountingLine budgetAdjustmentAccountingLine = (BudgetAdjustmentAccountingLine) accountingLine;
0580:
0581: boolean validMonthlyLines = true;
0582:
0583: KualiDecimal monthlyTotal = budgetAdjustmentAccountingLine
0584: .getMonthlyLinesTotal();
0585: if (monthlyTotal.isNonZero()
0586: && monthlyTotal
0587: .compareTo(budgetAdjustmentAccountingLine
0588: .getCurrentBudgetAdjustmentAmount()) != 0) {
0589: GlobalVariables
0590: .getErrorMap()
0591: .putError(
0592: KFSPropertyConstants.CURRENT_BUDGET_ADJUSTMENT_AMOUNT,
0593: KFSKeyConstants.ERROR_DOCUMENT_BA_MONTH_TOTAL_NOT_EQUAL_CURRENT);
0594: validMonthlyLines = false;
0595: }
0596:
0597: return validMonthlyLines;
0598: }
0599:
0600: /**
0601: * Retrieves the fund group and sub fund group for each accounting line. Then verifies that the codes associated with the
0602: * 'Budget Adjustment Restriction Code' field are met.
0603: *
0604: * @param financialDocument submitted accounting document
0605: * @return true if fund group and sub fund group for each accounting line if restrictions are met
0606: */
0607: public boolean validateFundGroupAdjustmentRestrictions(
0608: AccountingDocument financialDocument) {
0609: BudgetAdjustmentDocument baDocument = (BudgetAdjustmentDocument) financialDocument;
0610: ErrorMap errors = GlobalVariables.getErrorMap();
0611:
0612: boolean isAdjustmentAllowed = true;
0613:
0614: List accountingLines = new ArrayList();
0615: accountingLines.addAll(baDocument.getSourceAccountingLines());
0616: accountingLines.addAll(baDocument.getTargetAccountingLines());
0617:
0618: // fund group is global restriction
0619: boolean restrictedToSubFund = false;
0620: boolean restrictedToChart = false;
0621: boolean restrictedToOrg = false;
0622: boolean restrictedToAccount = false;
0623:
0624: // fields to help with error messages
0625: String accountRestrictingSubFund = "";
0626: String accountRestrictingChart = "";
0627: String accountRestrictingOrg = "";
0628: String accountRestrictingAccount = "";
0629:
0630: // first find the restriction level required by the fund or sub funds used on document
0631: String restrictionLevel = "";
0632: for (Iterator iter = accountingLines.iterator(); iter.hasNext();) {
0633: BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter
0634: .next();
0635: SubFundGroup subFund = line.getAccount().getSubFundGroup();
0636: if (!KFSConstants.BudgetAdjustmentDocumentConstants.ADJUSTMENT_RESTRICTION_LEVEL_NONE
0637: .equals(subFund
0638: .getFundGroupBudgetAdjustmentRestrictionLevelCode())) {
0639: restrictionLevel = subFund
0640: .getFundGroupBudgetAdjustmentRestrictionLevelCode();
0641: restrictedToSubFund = true;
0642: accountRestrictingSubFund = line.getAccountNumber();
0643: } else {
0644: restrictionLevel = subFund
0645: .getFundGroup()
0646: .getFundGroupBudgetAdjustmentRestrictionLevelCode();
0647: }
0648:
0649: if (KFSConstants.BudgetAdjustmentDocumentConstants.ADJUSTMENT_RESTRICTION_LEVEL_CHART
0650: .equals(restrictionLevel)) {
0651: restrictedToChart = true;
0652: accountRestrictingChart = line.getAccountNumber();
0653: } else if (KFSConstants.BudgetAdjustmentDocumentConstants.ADJUSTMENT_RESTRICTION_LEVEL_ORGANIZATION
0654: .equals(restrictionLevel)) {
0655: restrictedToOrg = true;
0656: accountRestrictingOrg = line.getAccountNumber();
0657: } else if (KFSConstants.BudgetAdjustmentDocumentConstants.ADJUSTMENT_RESTRICTION_LEVEL_ACCOUNT
0658: .equals(restrictionLevel)) {
0659: restrictedToAccount = true;
0660: accountRestrictingAccount = line.getAccountNumber();
0661: }
0662:
0663: // if we have a sub fund restriction, this overrides anything coming later
0664: if (restrictedToSubFund) {
0665: break;
0666: }
0667: }
0668:
0669: String fundLabel = AccountingLineRuleUtil
0670: .getFundGroupCodeLabel();
0671: String subFundLabel = AccountingLineRuleUtil
0672: .getSubFundGroupCodeLabel();
0673: String chartLabel = AccountingLineRuleUtil.getChartLabel();
0674: String orgLabel = AccountingLineRuleUtil
0675: .getOrganizationCodeLabel();
0676: String acctLabel = AccountingLineRuleUtil.getAccountLabel();
0677:
0678: /*
0679: * now iterate through the accounting lines again and check each record against the previous to verify the restrictions are
0680: * met
0681: */
0682: BudgetAdjustmentAccountingLine previousLine = null;
0683: for (Iterator iter = accountingLines.iterator(); iter.hasNext();) {
0684: BudgetAdjustmentAccountingLine line = (BudgetAdjustmentAccountingLine) iter
0685: .next();
0686:
0687: if (previousLine != null) {
0688: String currentFundGroup = line.getAccount()
0689: .getSubFundGroup().getFundGroupCode();
0690: String previousFundGroup = previousLine.getAccount()
0691: .getSubFundGroup().getFundGroupCode();
0692:
0693: if (!currentFundGroup.equals(previousFundGroup)) {
0694: errors
0695: .putErrorWithoutFullErrorPath(
0696: KFSConstants.ACCOUNTING_LINE_ERRORS,
0697: KFSKeyConstants.ERROR_DOCUMENT_BA_MIXED_FUND_GROUPS);
0698: isAdjustmentAllowed = false;
0699: break;
0700: }
0701:
0702: if (restrictedToSubFund) {
0703: if (!line.getAccount().getSubFundGroupCode()
0704: .equals(
0705: previousLine.getAccount()
0706: .getSubFundGroupCode())) {
0707: errors
0708: .putErrorWithoutFullErrorPath(
0709: KFSConstants.ACCOUNTING_LINE_ERRORS,
0710: KFSKeyConstants.ERROR_DOCUMENT_BA_RESTRICTION_LEVELS,
0711: new String[] {
0712: accountRestrictingSubFund,
0713: subFundLabel });
0714: isAdjustmentAllowed = false;
0715: break;
0716: }
0717: }
0718:
0719: if (restrictedToChart) {
0720: if (!line.getChartOfAccountsCode().equals(
0721: previousLine.getChartOfAccountsCode())) {
0722: if (restrictedToSubFund) {
0723: errors
0724: .putErrorWithoutFullErrorPath(
0725: KFSConstants.ACCOUNTING_LINE_ERRORS,
0726: KFSKeyConstants.ERROR_DOCUMENT_BA_RESTRICTION_LEVELS,
0727: new String[] {
0728: accountRestrictingChart,
0729: subFundLabel
0730: + " and "
0731: + chartLabel });
0732: } else {
0733: errors
0734: .putErrorWithoutFullErrorPath(
0735: KFSConstants.ACCOUNTING_LINE_ERRORS,
0736: KFSKeyConstants.ERROR_DOCUMENT_BA_RESTRICTION_LEVELS,
0737: new String[] {
0738: accountRestrictingChart,
0739: fundLabel
0740: + " and "
0741: + chartLabel });
0742: }
0743: isAdjustmentAllowed = false;
0744: break;
0745: }
0746: }
0747:
0748: if (restrictedToOrg) {
0749: if (!line.getAccount().getOrganizationCode()
0750: .equals(
0751: previousLine.getAccount()
0752: .getOrganizationCode())) {
0753: if (restrictedToSubFund) {
0754: errors
0755: .putErrorWithoutFullErrorPath(
0756: KFSConstants.ACCOUNTING_LINE_ERRORS,
0757: KFSKeyConstants.ERROR_DOCUMENT_BA_RESTRICTION_LEVELS,
0758: new String[] {
0759: accountRestrictingOrg,
0760: subFundLabel
0761: + " and "
0762: + orgLabel });
0763: } else {
0764: errors
0765: .putErrorWithoutFullErrorPath(
0766: KFSConstants.ACCOUNTING_LINE_ERRORS,
0767: KFSKeyConstants.ERROR_DOCUMENT_BA_RESTRICTION_LEVELS,
0768: new String[] {
0769: accountRestrictingOrg,
0770: fundLabel + " and "
0771: + orgLabel });
0772: }
0773: isAdjustmentAllowed = false;
0774: break;
0775: }
0776: }
0777:
0778: if (restrictedToAccount) {
0779: if (!line.getAccountNumber().equals(
0780: previousLine.getAccountNumber())) {
0781: errors
0782: .putErrorWithoutFullErrorPath(
0783: KFSConstants.ACCOUNTING_LINE_ERRORS,
0784: KFSKeyConstants.ERROR_DOCUMENT_BA_RESTRICTION_LEVELS,
0785: new String[] {
0786: accountRestrictingAccount,
0787: acctLabel });
0788: isAdjustmentAllowed = false;
0789: break;
0790: }
0791: }
0792: }
0793:
0794: previousLine = line;
0795: }
0796:
0797: return isAdjustmentAllowed;
0798: }
0799:
0800: /**
0801: * Checks account number restrictions, including restrictions in parameters table.
0802: *
0803: * @param financialDocument submitted accounting document
0804: * @param accountingLine accounting line with validated account number
0805: * @return true if account number has a budget recording level and if the current adjustment amount is non-zero, account must
0806: * have an associated income stream chart and account
0807: */
0808: public boolean validateAccountNumber(
0809: AccountingDocument financialDocument,
0810: AccountingLine accountingLine) {
0811: BudgetAdjustmentDocument baDocument = (BudgetAdjustmentDocument) financialDocument;
0812: BudgetAdjustmentAccountingLine budgetAccountingLine = (BudgetAdjustmentAccountingLine) accountingLine;
0813: ErrorMap errors = GlobalVariables.getErrorMap();
0814:
0815: String errorKey = KFSPropertyConstants.ACCOUNT_NUMBER;
0816: boolean accountNumberAllowed = true;
0817:
0818: // check account has a budget recording level
0819: if (StringUtils.isBlank(accountingLine.getAccount()
0820: .getBudgetRecordingLevelCode())
0821: || ACCOUNT_NUMBER.BUDGET_LEVEL_NO_BUDGET
0822: .equals(accountingLine.getAccount()
0823: .getBudgetRecordingLevelCode())) {
0824: errors
0825: .putError(
0826: errorKey,
0827: KFSKeyConstants.ERROR_DOCUMENT_BA_NON_BUDGETED_ACCOUNT,
0828: accountingLine.getAccountNumber());
0829: accountNumberAllowed = false;
0830: }
0831:
0832: // if current adjustment amount is non zero, account must have an associated income stream chart and account
0833: if (budgetAccountingLine.getCurrentBudgetAdjustmentAmount()
0834: .isNonZero()) {
0835: if (ObjectUtils.isNull(accountingLine.getAccount()
0836: .getIncomeStreamAccount())) {
0837: errors
0838: .putError(
0839: errorKey,
0840: KFSKeyConstants.ERROR_DOCUMENT_BA_NO_INCOME_STREAM_ACCOUNT,
0841: accountingLine.getAccountNumber());
0842: accountNumberAllowed = false;
0843: }
0844: }
0845:
0846: return accountNumberAllowed;
0847: }
0848:
0849: /**
0850: * Override needed to check the current, base, and monthly amounts.
0851: *
0852: * @param document submitted accounting document
0853: * @param accountingLine accounting line where current, base, and monthly amounts are being validated.
0854: * @see org.kuali.core.rule.AccountingLineRule#isAmountValid(org.kuali.core.document.FinancialDocument,
0855: * org.kuali.core.bo.AccountingLine)
0856: */
0857: @Override
0858: public boolean isAmountValid(AccountingDocument document,
0859: AccountingLine accountingLine) {
0860: boolean amountValid = true;
0861:
0862: BudgetAdjustmentAccountingLine budgetAccountingLine = (BudgetAdjustmentAccountingLine) accountingLine;
0863:
0864: // check amounts both current and base amounts are not zero
0865: if (budgetAccountingLine.getCurrentBudgetAdjustmentAmount()
0866: .isZero()
0867: && budgetAccountingLine.getBaseBudgetAdjustmentAmount()
0868: .isZero()) {
0869: GlobalVariables.getErrorMap().putError(
0870: KFSPropertyConstants.BASE_BUDGET_ADJUSTMENT_AMOUNT,
0871: KFSKeyConstants.ERROR_BA_AMOUNT_ZERO);
0872: amountValid = false;
0873: }
0874:
0875: // if not an error correction, all amounts must be positive
0876: if (!isErrorCorrection(document)) {
0877: amountValid &= checkAmountSign(
0878: budgetAccountingLine
0879: .getCurrentBudgetAdjustmentAmount(),
0880: KFSPropertyConstants.CURRENT_BUDGET_ADJUSTMENT_AMOUNT,
0881: "Current");
0882: amountValid &= checkAmountSign(budgetAccountingLine
0883: .getBaseBudgetAdjustmentAmount()
0884: .kualiDecimalValue(),
0885: KFSPropertyConstants.BASE_BUDGET_ADJUSTMENT_AMOUNT,
0886: "Base");
0887: amountValid &= checkAmountSign(
0888: budgetAccountingLine
0889: .getFinancialDocumentMonth1LineAmount(),
0890: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_1_LINE_AMOUNT,
0891: "Month 1");
0892: amountValid &= checkAmountSign(
0893: budgetAccountingLine
0894: .getFinancialDocumentMonth2LineAmount(),
0895: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_2_LINE_AMOUNT,
0896: "Month 2");
0897: amountValid &= checkAmountSign(
0898: budgetAccountingLine
0899: .getFinancialDocumentMonth3LineAmount(),
0900: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_3_LINE_AMOUNT,
0901: "Month 3");
0902: amountValid &= checkAmountSign(
0903: budgetAccountingLine
0904: .getFinancialDocumentMonth4LineAmount(),
0905: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_4_LINE_AMOUNT,
0906: "Month 4");
0907: amountValid &= checkAmountSign(
0908: budgetAccountingLine
0909: .getFinancialDocumentMonth5LineAmount(),
0910: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_5_LINE_AMOUNT,
0911: "Month 5");
0912: amountValid &= checkAmountSign(
0913: budgetAccountingLine
0914: .getFinancialDocumentMonth6LineAmount(),
0915: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_6_LINE_AMOUNT,
0916: "Month 6");
0917: amountValid &= checkAmountSign(
0918: budgetAccountingLine
0919: .getFinancialDocumentMonth7LineAmount(),
0920: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_7_LINE_AMOUNT,
0921: "Month 7");
0922: amountValid &= checkAmountSign(
0923: budgetAccountingLine
0924: .getFinancialDocumentMonth8LineAmount(),
0925: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_8_LINE_AMOUNT,
0926: "Month 8");
0927: amountValid &= checkAmountSign(
0928: budgetAccountingLine
0929: .getFinancialDocumentMonth8LineAmount(),
0930: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_9_LINE_AMOUNT,
0931: "Month 9");
0932: amountValid &= checkAmountSign(
0933: budgetAccountingLine
0934: .getFinancialDocumentMonth10LineAmount(),
0935: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_10_LINE_AMOUNT,
0936: "Month 10");
0937: amountValid &= checkAmountSign(
0938: budgetAccountingLine
0939: .getFinancialDocumentMonth10LineAmount(),
0940: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_11_LINE_AMOUNT,
0941: "Month 11");
0942: amountValid &= checkAmountSign(
0943: budgetAccountingLine
0944: .getFinancialDocumentMonth12LineAmount(),
0945: KFSPropertyConstants.FINANCIAL_DOCUMENT_MONTH_12_LINE_AMOUNT,
0946: "Month 12");
0947: }
0948:
0949: return amountValid;
0950: }
0951:
0952: /**
0953: * In order for the BA document to balance: Total of Base Income Adjustments - Base Expense Adjustments on decrease side must
0954: * equal Total of Base Income Adjustments - Base Expense Adjustments on increase side Total of Current Income Adjustments - Base
0955: * Current Adjustments on decrease side must equal Total of Current Income Adjustments - Base Current Adjustments on increase
0956: * side
0957: *
0958: * @param sumbmitted financial document
0959: * @return true if base amounts are equal and current amounts balance and income stream balance should equal 0
0960: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isDocumentBalanceValid(org.kuali.core.document.FinancialDocument)
0961: */
0962: @Override
0963: protected boolean isDocumentBalanceValid(
0964: AccountingDocument financialDocument) {
0965: BudgetAdjustmentDocument baDocument = (BudgetAdjustmentDocument) financialDocument;
0966: ErrorMap errors = GlobalVariables.getErrorMap();
0967:
0968: boolean balanced = true;
0969:
0970: // check base amounts are equal
0971: if (baDocument.getSourceBaseBudgetTotal().compareTo(
0972: baDocument.getTargetBaseBudgetTotal()) != 0) {
0973: GlobalVariables
0974: .getErrorMap()
0975: .putError(
0976: KFSConstants.ACCOUNTING_LINE_ERRORS,
0977: KFSKeyConstants.ERROR_DOCUMENT_BA_BASE_AMOUNTS_BALANCED);
0978: balanced = false;
0979: }
0980:
0981: // check current amounts balance, income stream balance Map should add to 0
0982: Map incomeStreamMap = buildIncomeStreamBalanceMap(baDocument);
0983: KualiDecimal totalCurrentAmount = new KualiDecimal(0);
0984: for (Iterator iter = incomeStreamMap.values().iterator(); iter
0985: .hasNext();) {
0986: KualiDecimal streamAmount = (KualiDecimal) iter.next();
0987: totalCurrentAmount = totalCurrentAmount.add(streamAmount);
0988: }
0989:
0990: if (totalCurrentAmount.isNonZero()) {
0991: GlobalVariables
0992: .getErrorMap()
0993: .putError(
0994: KFSConstants.ACCOUNTING_LINE_ERRORS,
0995: KFSKeyConstants.ERROR_DOCUMENT_BA_CURRENT_AMOUNTS_BALANCED);
0996: balanced = false;
0997: }
0998:
0999: return balanced;
1000: }
1001:
1002: /**
1003: * Builds a map used for balancing current adjustment amounts. The map contains income chart and accounts contained on the
1004: * document as the keys, and transfer amounts as the values. The transfer amount is calculated from (curr_frm_inc -
1005: * curr_frm_exp) - (curr_to_inc - curr_to_exp)
1006: *
1007: * @param baDocument budget ajdustment document
1008: * @return Map used to balance current amounts
1009: */
1010: public Map buildIncomeStreamBalanceMap(
1011: BudgetAdjustmentDocument baDocument) {
1012: Map incomeStreamBalance = new HashMap();
1013:
1014: List accountingLines = new ArrayList();
1015: accountingLines.addAll(baDocument.getSourceAccountingLines());
1016: accountingLines.addAll(baDocument.getTargetAccountingLines());
1017: for (Iterator iter = accountingLines.iterator(); iter.hasNext();) {
1018: BudgetAdjustmentAccountingLine budgetAccountingLine = (BudgetAdjustmentAccountingLine) iter
1019: .next();
1020: String incomeStreamKey = budgetAccountingLine.getAccount()
1021: .getIncomeStreamFinancialCoaCode()
1022: + INCOME_STREAM_CHART_ACCOUNT_DELIMITER
1023: + budgetAccountingLine.getAccount()
1024: .getIncomeStreamAccountNumber();
1025:
1026: KualiDecimal incomeStreamAmount = new KualiDecimal(0);
1027: if (incomeStreamBalance.containsKey(incomeStreamKey)) {
1028: incomeStreamAmount = (KualiDecimal) incomeStreamBalance
1029: .get(incomeStreamKey);
1030: }
1031:
1032: // amounts need reversed for source expense lines and target income lines
1033: if ((budgetAccountingLine instanceof BudgetAdjustmentSourceAccountingLine && super
1034: .isExpense((AccountingLine) budgetAccountingLine))
1035: || (budgetAccountingLine instanceof BudgetAdjustmentTargetAccountingLine && super
1036: .isIncome((AccountingLine) budgetAccountingLine))) {
1037: incomeStreamAmount = incomeStreamAmount
1038: .subtract(budgetAccountingLine
1039: .getCurrentBudgetAdjustmentAmount());
1040: } else {
1041: incomeStreamAmount = incomeStreamAmount
1042: .add(budgetAccountingLine
1043: .getCurrentBudgetAdjustmentAmount());
1044: }
1045:
1046: // place record in balance map
1047: incomeStreamBalance
1048: .put(incomeStreamKey, incomeStreamAmount);
1049: }
1050:
1051: return incomeStreamBalance;
1052: }
1053:
1054: /**
1055: * Helper method to check if an amount is negative and add an error if not.
1056: *
1057: * @param amount to check
1058: * @param propertyName to add error under
1059: * @param label for error
1060: * @return boolean indicating if the value has the requested sign
1061: */
1062: private boolean checkAmountSign(KualiDecimal amount,
1063: String propertyName, String label) {
1064: boolean correctSign = true;
1065:
1066: if (amount.isNegative()) {
1067: GlobalVariables.getErrorMap().putError(propertyName,
1068: KFSKeyConstants.ERROR_BA_AMOUNT_NEGATIVE, label);
1069: correctSign = false;
1070: }
1071:
1072: return correctSign;
1073: }
1074:
1075: /**
1076: * BA document does not have to have source accounting lines. In the case of setting up a budget for a new account, only targets
1077: * line (increase section) are setup.
1078: *
1079: * @param financialDocument submitted financial document
1080: * @return true if both source and target lines are NOT empty
1081: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isSourceAccountingLinesRequiredNumberForRoutingMet(org.kuali.core.document.FinancialDocument)
1082: */
1083: @Override
1084: protected boolean isSourceAccountingLinesRequiredNumberForRoutingMet(
1085: AccountingDocument financialDocument) {
1086: // check that both source and target are not empty, in which case is an error
1087: if (financialDocument.getSourceAccountingLines().isEmpty()
1088: && financialDocument.getTargetAccountingLines()
1089: .isEmpty()) {
1090: GlobalVariables.getErrorMap().putError(
1091: KFSConstants.ACCOUNTING_LINE_ERRORS,
1092: KFSKeyConstants.ERROR_DOCUMENT_NO_ACCOUNTING_LINES);
1093: return false;
1094: }
1095:
1096: return true;
1097: }
1098:
1099: /**
1100: * BA document does not have to have source accounting lines. In the case of closing out an account, only source lines (decrease
1101: * section) are setup.
1102: *
1103: * @param financialDocument submitted financial document
1104: * @return true
1105: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isTargetAccountingLinesRequiredNumberForRoutingMet(org.kuali.core.document.FinancialDocument)
1106: */
1107: @Override
1108: protected boolean isTargetAccountingLinesRequiredNumberForRoutingMet(
1109: AccountingDocument FinancialDocument) {
1110: return true;
1111: }
1112:
1113: /**
1114: * Returns true if accounting line is debit
1115: *
1116: * @param financialDocument submitted financial document
1117: * @param accountingLine accouting line being evaulated as a debit or not
1118: * @see org.kuali.core.rule.AccountingLineRule#isDebit(org.kuali.core.document.FinancialDocument,
1119: * org.kuali.core.bo.AccountingLine)
1120: */
1121: public boolean isDebit(AccountingDocument financialDocument,
1122: AccountingLine accountingLine) {
1123: try {
1124: return IsDebitUtils.isDebitConsideringType(this ,
1125: financialDocument, accountingLine);
1126: } catch (IllegalStateException e) {
1127: // for all accounting lines except the transfer lines, the line amount will be 0 and this exception will be thrown
1128: return false;
1129: }
1130: }
1131:
1132: /**
1133: * Returns true if account line totals remains unchanged from what was entered and what was persisted before
1134: *
1135: * @param financialDocument submitted accounting document
1136: * @return true if account line totals remains unchanged fromw what was entered and what was persisted before
1137: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isAccountingLineTotalsUnchanged(org.kuali.core.document.FinancialDocument)
1138: */
1139: @Override
1140: protected boolean isAccountingLineTotalsUnchanged(
1141: AccountingDocument financialDocument) {
1142: boolean isUnchanged = true;
1143:
1144: BudgetAdjustmentDocument persistedDocument = (BudgetAdjustmentDocument) retrievePersistedDocument(financialDocument);
1145: BudgetAdjustmentDocument currentDocument = (BudgetAdjustmentDocument) financialDocument;
1146:
1147: if (persistedDocument == null) {
1148: handleNonExistentDocumentWhenApproving(financialDocument);
1149: } else {
1150: // retrieve the persisted totals
1151: KualiDecimal persistedSourceCurrentBudgetTotal = persistedDocument
1152: .getSourceCurrentBudgetTotal();
1153: KualiInteger persistedSourceBaseBudgetTotal = persistedDocument
1154: .getSourceBaseBudgetTotal();
1155: KualiDecimal persistedTargetCurrentBudgetTotal = persistedDocument
1156: .getTargetCurrentBudgetTotal();
1157: KualiInteger persistedTargetBaseBudgetTotal = persistedDocument
1158: .getTargetBaseBudgetTotal();
1159:
1160: // retrieve the updated totals
1161: KualiDecimal currentSourceCurrentBudgetTotal = currentDocument
1162: .getSourceCurrentBudgetTotal();
1163: KualiInteger currentSourceBaseBudgetTotal = currentDocument
1164: .getSourceBaseBudgetTotal();
1165: KualiDecimal currentTargetCurrentBudgetTotal = currentDocument
1166: .getTargetCurrentBudgetTotal();
1167: KualiInteger currentTargetBaseBudgetTotal = currentDocument
1168: .getTargetBaseBudgetTotal();
1169:
1170: // make sure that totals have remained unchanged, if not, recognize that, and
1171: // generate appropriate error messages
1172: if (persistedSourceCurrentBudgetTotal
1173: .compareTo(currentSourceCurrentBudgetTotal) != 0) {
1174: isUnchanged = false;
1175: buildTotalChangeErrorMessage(
1176: SOURCE_ACCOUNTING_LINE_ERRORS,
1177: "source current budget",
1178: persistedSourceCurrentBudgetTotal,
1179: currentSourceCurrentBudgetTotal);
1180: }
1181: if (persistedSourceBaseBudgetTotal
1182: .compareTo(currentSourceBaseBudgetTotal) != 0) {
1183: isUnchanged = false;
1184: buildTotalChangeErrorMessage(
1185: SOURCE_ACCOUNTING_LINE_ERRORS,
1186: "source base budget",
1187: persistedSourceBaseBudgetTotal
1188: .kualiDecimalValue(),
1189: currentSourceBaseBudgetTotal
1190: .kualiDecimalValue());
1191: }
1192: if (persistedTargetCurrentBudgetTotal
1193: .compareTo(currentTargetCurrentBudgetTotal) != 0) {
1194: isUnchanged = false;
1195: buildTotalChangeErrorMessage(
1196: TARGET_ACCOUNTING_LINE_ERRORS,
1197: "target current budget",
1198: persistedTargetCurrentBudgetTotal,
1199: currentTargetCurrentBudgetTotal);
1200: }
1201: if (persistedTargetBaseBudgetTotal
1202: .compareTo(currentTargetBaseBudgetTotal) != 0) {
1203: isUnchanged = false;
1204: buildTotalChangeErrorMessage(
1205: TARGET_ACCOUNTING_LINE_ERRORS,
1206: "target base budget",
1207: persistedTargetBaseBudgetTotal
1208: .kualiDecimalValue(),
1209: currentTargetBaseBudgetTotal
1210: .kualiDecimalValue());
1211: }
1212: }
1213:
1214: return isUnchanged;
1215: }
1216:
1217: /**
1218: * Builds the error message for when totals have changed.
1219: *
1220: * @param propertyName name of property
1221: * @param sectionTitle title of section
1222: * @param persistedSourceLineTotal previously persisted source line total
1223: * @param currentSourceLineTotal current entered source line total
1224: */
1225: private void buildTotalChangeErrorMessage(String propertyName,
1226: String sectionTitle, KualiDecimal persistedSourceLineTotal,
1227: KualiDecimal currentSourceLineTotal) {
1228: String persistedTotal = (String) new CurrencyFormatter()
1229: .format(persistedSourceLineTotal);
1230: String currentTotal = (String) new CurrencyFormatter()
1231: .format(currentSourceLineTotal);
1232:
1233: GlobalVariables.getErrorMap().putError(
1234: propertyName,
1235: ERROR_DOCUMENT_ACCOUNTING_LINE_TOTAL_CHANGED,
1236: new String[] { sectionTitle, persistedTotal,
1237: currentTotal });
1238: }
1239:
1240: /**
1241: * Returns the document type code for the Transfer of Funds document
1242: *
1243: * @return the document type name to be used for the income stream transfer glpe
1244: */
1245: protected String getTransferDocumentType() {
1246: return TRANSFER_OF_FUNDS_DOC_TYPE_CODE;
1247: }
1248: }
|