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.gl.service.impl.orgreversion;
0017:
0018: import java.sql.Date;
0019: import java.util.ArrayList;
0020: import java.util.Iterator;
0021: import java.util.List;
0022: import java.util.Map;
0023:
0024: import org.kuali.core.service.DateTimeService;
0025: import org.kuali.core.service.KualiConfigurationService;
0026: import org.kuali.core.service.PersistenceService;
0027: import org.kuali.core.util.KualiDecimal;
0028: import org.kuali.core.util.ObjectUtils;
0029: import org.kuali.kfs.KFSConstants;
0030: import org.kuali.kfs.KFSKeyConstants;
0031: import org.kuali.kfs.KFSPropertyConstants;
0032: import org.kuali.kfs.bo.Options;
0033: import org.kuali.kfs.context.SpringContext;
0034: import org.kuali.kfs.service.OptionsService;
0035: import org.kuali.kfs.service.ParameterService;
0036: import org.kuali.kfs.service.impl.ParameterConstants;
0037: import org.kuali.module.chart.bo.AccountIntf;
0038: import org.kuali.module.chart.bo.ObjectCode;
0039: import org.kuali.module.chart.bo.OrganizationReversion;
0040: import org.kuali.module.chart.bo.OrganizationReversionCategory;
0041: import org.kuali.module.chart.bo.OrganizationReversionDetail;
0042: import org.kuali.module.chart.service.OrganizationReversionService;
0043: import org.kuali.module.chart.service.PriorYearAccountService;
0044: import org.kuali.module.gl.GLConstants;
0045: import org.kuali.module.gl.bo.Balance;
0046: import org.kuali.module.gl.bo.OrgReversionUnitOfWork;
0047: import org.kuali.module.gl.bo.OrgReversionUnitOfWorkCategoryAmount;
0048: import org.kuali.module.gl.bo.OriginEntryFull;
0049: import org.kuali.module.gl.bo.OriginEntryGroup;
0050: import org.kuali.module.gl.service.BalanceService;
0051: import org.kuali.module.gl.service.OrgReversionUnitOfWorkService;
0052: import org.kuali.module.gl.service.OrganizationReversionCategoryLogic;
0053: import org.kuali.module.gl.service.OriginEntryGroupService;
0054: import org.kuali.module.gl.service.OriginEntryService;
0055: import org.kuali.module.gl.util.FatalErrorException;
0056: import org.springframework.transaction.annotation.Transactional;
0057:
0058: /**
0059: * This class actually runs the year end organization reversion process
0060: */
0061: @Transactional
0062: public class OrganizationReversionProcess {
0063: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0064: .getLogger(OrganizationReversionProcess.class);
0065:
0066: // Services
0067: private OrganizationReversionService organizationReversionService;
0068: private BalanceService balanceService;
0069: private OriginEntryGroupService originEntryGroupService;
0070: private OriginEntryService originEntryService;
0071: private PersistenceService persistenceService;
0072: private DateTimeService dateTimeService;
0073: private OrganizationReversionCategoryLogic cashOrganizationReversionCategoryLogic;
0074: private PriorYearAccountService priorYearAccountService;
0075: private OrgReversionUnitOfWorkService orgReversionUnitOfWorkService;
0076:
0077: private OriginEntryGroup outputGroup;
0078: private OrgReversionUnitOfWork unitOfWork;
0079: private Map<String, OrganizationReversionCategoryLogic> categories;
0080: private List<OrganizationReversionCategory> categoryList;
0081: private OrganizationReversion organizationReversion;
0082: private AccountIntf account;
0083:
0084: private Map jobParameters;
0085: private Map<String, Integer> organizationReversionCounts;
0086:
0087: private boolean endOfYear;
0088:
0089: private boolean holdGeneratedOriginEntries = false;
0090: private List<OriginEntryFull> generatedOriginEntries;
0091:
0092: public final String CARRY_FORWARD_OBJECT_CODE;
0093: public final String DEFAULT_FINANCIAL_DOCUMENT_TYPE_CODE;
0094: public final String DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE;
0095: public final String DEFAULT_FINANCIAL_BALANCE_TYPE_CODE;
0096: public final String DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END;
0097: public final String DEFAULT_DOCUMENT_NUMBER_PREFIX;
0098:
0099: private final String CASH_REVERTED_TO_MESSAGE;
0100: private final String FUND_BALANCE_REVERTED_TO_MESSAGE;
0101: private final String CASH_REVERTED_FROM_MESSAGE;
0102: private final String FUND_BALANCE_REVERTED_FROM_MESSAGE;
0103: private final String FUND_CARRIED_MESSAGE;
0104: private final String FUND_REVERTED_TO_MESSAGE;
0105: private final String FUND_REVERTED_FROM_MESSAGE;
0106:
0107: private Options priorYearOptions;
0108: private Options currentYearOptions;
0109: private Integer paramFiscalYear;
0110:
0111: /**
0112: * Constructs a OrganizationReversionProcess, initializing certain parameters
0113: */
0114: public OrganizationReversionProcess() {
0115: super ();
0116:
0117: ParameterService parameterService = SpringContext
0118: .getBean(ParameterService.class);
0119: this .CARRY_FORWARD_OBJECT_CODE = parameterService
0120: .getParameterValue(
0121: OrganizationReversion.class,
0122: GLConstants.OrganizationReversionProcess.CARRY_FORWARD_OBJECT_CODE);
0123: this .DEFAULT_FINANCIAL_DOCUMENT_TYPE_CODE = parameterService
0124: .getParameterValue(
0125: ParameterConstants.GENERAL_LEDGER_BATCH.class,
0126: GLConstants.ANNUAL_CLOSING_DOCUMENT_TYPE);
0127: this .DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE = parameterService
0128: .getParameterValue(
0129: OrganizationReversion.class,
0130: GLConstants.OrganizationReversionProcess.DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE);
0131: this .DEFAULT_FINANCIAL_BALANCE_TYPE_CODE = parameterService
0132: .getParameterValue(
0133: OrganizationReversion.class,
0134: GLConstants.OrganizationReversionProcess.DEFAULT_FINANCIAL_BALANCE_TYPE_CODE);
0135: this .DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END = parameterService
0136: .getParameterValue(
0137: OrganizationReversion.class,
0138: GLConstants.OrganizationReversionProcess.DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END);
0139: this .DEFAULT_DOCUMENT_NUMBER_PREFIX = parameterService
0140: .getParameterValue(
0141: OrganizationReversion.class,
0142: GLConstants.OrganizationReversionProcess.DEFAULT_DOCUMENT_NUMBER_PREFIX);
0143: KualiConfigurationService configurationService = SpringContext
0144: .getBean(KualiConfigurationService.class);
0145: this .CASH_REVERTED_TO_MESSAGE = configurationService
0146: .getPropertyString(KFSKeyConstants.OrganizationReversionProcess.CASH_REVERTED_TO);
0147: this .FUND_BALANCE_REVERTED_TO_MESSAGE = configurationService
0148: .getPropertyString(KFSKeyConstants.OrganizationReversionProcess.FUND_BALANCE_REVERTED_TO);
0149: this .CASH_REVERTED_FROM_MESSAGE = configurationService
0150: .getPropertyString(KFSKeyConstants.OrganizationReversionProcess.CASH_REVERTED_FROM);
0151: this .FUND_BALANCE_REVERTED_FROM_MESSAGE = configurationService
0152: .getPropertyString(KFSKeyConstants.OrganizationReversionProcess.FUND_BALANCE_REVERTED_FROM);
0153: this .FUND_CARRIED_MESSAGE = configurationService
0154: .getPropertyString(KFSKeyConstants.OrganizationReversionProcess.FUND_CARRIED);
0155: this .FUND_REVERTED_TO_MESSAGE = configurationService
0156: .getPropertyString(KFSKeyConstants.OrganizationReversionProcess.FUND_REVERTED_TO);
0157: this .FUND_REVERTED_FROM_MESSAGE = configurationService
0158: .getPropertyString(KFSKeyConstants.OrganizationReversionProcess.FUND_REVERTED_FROM);
0159: }
0160:
0161: /**
0162: * Constructs a OrganizationReversionProcess, setting all of the services needed by the process
0163: *
0164: * @param outputGroup the origin entry group to put generated origin entries into
0165: * @param endOfYear true if this job is "end of year" - which uses Account, false if this job is "beginning of year", which uses PriorYearAccount
0166: * @param ors the organizationReversionService to use
0167: * @param bs the balanceService to use
0168: * @param oegs the originEntryGroupService to use
0169: * @param oes the originEntryService to use
0170: * @param ps the parameterService to use
0171: * @param dts the dateTimeService to use
0172: * @param corc the organizationReversionCategoryLogic implementation to use
0173: * @param pyas the prior year account service to use
0174: * @param oruows the organizationReversionUnitOfWorkService to use
0175: * @param jobParameters the parameters used by this job - the fiscal year to close and the transaction date that all generated origin entries should be set to
0176: * @param organizationReversionCounts a map of statistical counts generated by the process
0177: */
0178: public OrganizationReversionProcess(OriginEntryGroup outputGroup,
0179: boolean endOfYear, OrganizationReversionService ors,
0180: BalanceService bs, OriginEntryGroupService oegs,
0181: OriginEntryService oes, PersistenceService ps,
0182: DateTimeService dts,
0183: OrganizationReversionCategoryLogic corc,
0184: PriorYearAccountService pyas,
0185: OrgReversionUnitOfWorkService oruows, Map jobParameters,
0186: Map<String, Integer> organizationReversionCounts) {
0187: this ();
0188:
0189: this .outputGroup = outputGroup;
0190: this .endOfYear = endOfYear;
0191: balanceService = bs;
0192: organizationReversionService = ors;
0193: originEntryGroupService = oegs;
0194: originEntryService = oes;
0195: persistenceService = ps;
0196: dateTimeService = dts;
0197: cashOrganizationReversionCategoryLogic = corc;
0198: priorYearAccountService = pyas;
0199: orgReversionUnitOfWorkService = oruows;
0200: this .jobParameters = jobParameters;
0201: this .organizationReversionCounts = organizationReversionCounts;
0202: }
0203:
0204: /**
0205: * This evilly named method actually runs the organization reversion process.
0206: */
0207: public void organizationReversionProcess() {
0208: LOG.debug("organizationReversionProcess() started");
0209:
0210: initializeProcess();
0211:
0212: Iterator<Balance> balances = balanceService
0213: .findOrganizationReversionBalancesForFiscalYear(
0214: (Integer) jobParameters
0215: .get(KFSConstants.UNIV_FISCAL_YR),
0216: endOfYear);
0217: processBalances(balances);
0218:
0219: }
0220:
0221: /**
0222: * Given a list of balances, this method generates the origin entries for the organization reversion/carry forward process, and saves those
0223: * to an initialized origin entry group
0224: *
0225: * @param balances an iterator of balances to process; each balance returned by the iterator will be processed by this method
0226: */
0227: public void processBalances(Iterator<Balance> balances) {
0228: boolean skipToNextUnitOfWork = false;
0229: unitOfWork = new OrgReversionUnitOfWork();
0230: unitOfWork.setCategories(categoryList);
0231:
0232: Balance bal;
0233: while (balances.hasNext()) {
0234: bal = balances.next();
0235: if (LOG.isDebugEnabled()) {
0236: LOG.debug("BALANCE SELECTED: "
0237: + bal.getUniversityFiscalYear()
0238: + bal.getChartOfAccountsCode()
0239: + bal.getAccountNumber()
0240: + bal.getSubAccountNumber()
0241: + bal.getObjectCode()
0242: + bal.getSubObjectCode()
0243: + bal.getBalanceTypeCode()
0244: + bal.getObjectTypeCode()
0245: + " "
0246: + bal.getAccountLineAnnualBalanceAmount().add(
0247: bal.getBeginningBalanceLineAmount()));
0248: }
0249:
0250: try {
0251: if (!unitOfWork.isInitialized()) {
0252: unitOfWork.setFields(bal.getChartOfAccountsCode(),
0253: bal.getAccountNumber(), bal
0254: .getSubAccountNumber());
0255: retrieveCurrentReversionAndAccount(bal);
0256: } else if (!unitOfWork.wouldHold(bal)) {
0257: if (!skipToNextUnitOfWork) {
0258: calculateTotals();
0259: List<OriginEntryFull> originEntriesToWrite = generateOutputOriginEntries();
0260: if (holdGeneratedOriginEntries) {
0261: generatedOriginEntries
0262: .addAll(originEntriesToWrite);
0263: }
0264: int recordsWritten = writeOriginEntries(
0265: outputGroup, originEntriesToWrite);
0266: incrementCount("recordsWritten", recordsWritten);
0267: orgReversionUnitOfWorkService.save(unitOfWork);
0268: }
0269: unitOfWork.setFields(bal.getChartOfAccountsCode(),
0270: bal.getAccountNumber(), bal
0271: .getSubAccountNumber());
0272: retrieveCurrentReversionAndAccount(bal);
0273: skipToNextUnitOfWork = false;
0274: }
0275: if (skipToNextUnitOfWork) {
0276: continue; // if there is no org reversion or an org reversion detail is missing or the balances are off for
0277: // this unit of work,
0278: // just skip all the balances until we change unit of work
0279: }
0280: calculateBucketAmounts(bal);
0281: } catch (FatalErrorException fee) {
0282: LOG.info(fee.getMessage());
0283: skipToNextUnitOfWork = true;
0284: }
0285: }
0286: // save the final unit of work
0287: if (!skipToNextUnitOfWork && getBalancesSelected() > 0) {
0288: try {
0289: calculateTotals();
0290: List<OriginEntryFull> originEntriesToWrite = generateOutputOriginEntries();
0291: if (holdGeneratedOriginEntries) {
0292: generatedOriginEntries.addAll(originEntriesToWrite);
0293: }
0294: int recordsWritten = writeOriginEntries(outputGroup,
0295: originEntriesToWrite);
0296: incrementCount("recordsWritten", recordsWritten);
0297: orgReversionUnitOfWorkService.save(unitOfWork);
0298: } catch (FatalErrorException fee) {
0299: LOG.info(fee.getMessage());
0300: }
0301: }
0302: }
0303:
0304: /**
0305: * Given a balance, returns the current organization reversion record and account or prior year account for the balance; it sets them
0306: * to private properties
0307: *
0308: * @param bal the balance to find the account/prior year account and organization reversion record for
0309: * @throws FatalErrorException if an organization reversion record cannot be found in the database
0310: */
0311: private void retrieveCurrentReversionAndAccount(Balance bal)
0312: throws FatalErrorException {
0313: // initialize the account
0314: if ((account == null)
0315: || (!bal.getChartOfAccountsCode().equals(
0316: account.getChartOfAccountsCode()))
0317: || (!bal.getAccountNumber().equals(
0318: account.getAccountNumber()))) {
0319: if (endOfYear) {
0320: account = bal.getAccount();
0321: } else {
0322: account = priorYearAccountService.getByPrimaryKey(bal
0323: .getChartOfAccountsCode(), bal
0324: .getAccountNumber());
0325: }
0326: }
0327:
0328: if ((organizationReversion == null)
0329: || (!organizationReversion.getChartOfAccountsCode()
0330: .equals(bal.getChartOfAccountsCode()))
0331: || (!organizationReversion.getOrganizationCode()
0332: .equals(account.getOrganizationCode()))) {
0333: if (LOG.isDebugEnabled()) {
0334: LOG.debug("Organization Reversion Service: "
0335: + organizationReversionService
0336: + "; fiscal year: "
0337: + (Integer) jobParameters
0338: .get(KFSConstants.UNIV_FISCAL_YR)
0339: + "; account: " + account
0340: + "; account organization code: "
0341: + account.getOrganizationCode() + "; balance: "
0342: + bal + "; balance chart: "
0343: + bal.getChartOfAccountsCode());
0344: }
0345: organizationReversion = organizationReversionService
0346: .getByPrimaryId((Integer) jobParameters
0347: .get(KFSConstants.UNIV_FISCAL_YR), bal
0348: .getChartOfAccountsCode(), account
0349: .getOrganizationCode());
0350: }
0351:
0352: if (organizationReversion == null) {
0353: // we can't find an organization reversion for this balance? Throw exception
0354: throw new FatalErrorException(
0355: "No Organization Reversion found for: "
0356: + (Integer) jobParameters
0357: .get(KFSConstants.UNIV_FISCAL_YR)
0358: + "-" + bal.getChartOfAccountsCode() + "-"
0359: + account.getOrganizationCode());
0360: }
0361: }
0362:
0363: /**
0364: * This method initializes several properties needed for the process to run correctly
0365: */
0366: public void initializeProcess() {
0367:
0368: // clear out summary tables
0369: orgReversionUnitOfWorkService.destroyAllUnitOfWorkSummaries();
0370:
0371: categories = organizationReversionService.getCategories();
0372: categoryList = organizationReversionService.getCategoryList();
0373:
0374: this .paramFiscalYear = (Integer) jobParameters
0375: .get(KFSConstants.UNIV_FISCAL_YR);
0376:
0377: organizationReversionCounts.put("balancesRead", balanceService
0378: .countBalancesForFiscalYear(paramFiscalYear));
0379: organizationReversionCounts.put("balancesSelected",
0380: new Integer(0));
0381: organizationReversionCounts.put("recordsWritten",
0382: new Integer(0));
0383:
0384: this .priorYearOptions = SpringContext.getBean(
0385: OptionsService.class).getOptions(paramFiscalYear);
0386: if (this .endOfYear) {
0387: this .currentYearOptions = priorYearOptions;
0388: } else {
0389: this .currentYearOptions = SpringContext.getBean(
0390: OptionsService.class).getCurrentYearOptions();
0391: }
0392: }
0393:
0394: /**
0395: * Depending on the category that this balance belongs to, adds the balance to the appropriate bucket
0396: *
0397: * @param bal the current balance to process
0398: */
0399: protected void calculateBucketAmounts(Balance bal) {
0400: Options options = priorYearOptions;
0401: if (endOfYear) {
0402: options = currentYearOptions;
0403: }
0404: persistenceService.retrieveReferenceObject(bal,
0405: "financialObject");
0406:
0407: if (LOG.isDebugEnabled()) {
0408: LOG.debug("CONSIDERING IF TO ADD BALANCE: "
0409: + bal.getUniversityFiscalYear()
0410: + bal.getChartOfAccountsCode()
0411: + bal.getAccountNumber()
0412: + bal.getSubAccountNumber()
0413: + bal.getObjectCode()
0414: + bal.getSubObjectCode()
0415: + bal.getBalanceTypeCode()
0416: + bal.getObjectTypeCode()
0417: + " "
0418: + bal.getAccountLineAnnualBalanceAmount().add(
0419: bal.getBeginningBalanceLineAmount()));
0420: }
0421:
0422: if (cashOrganizationReversionCategoryLogic
0423: .containsObjectCode(bal.getFinancialObject())
0424: && bal.getBalanceTypeCode().equals(
0425: options.getActualFinancialBalanceTypeCd())) {
0426: unitOfWork
0427: .addTotalCash(bal.getBeginningBalanceLineAmount());
0428: unitOfWork.addTotalCash(bal
0429: .getAccountLineAnnualBalanceAmount());
0430: incrementCount("balancesSelected");
0431: if (LOG.isDebugEnabled()) {
0432: LOG.debug("ADDING BALANCE TO CASH: "
0433: + bal.getUniversityFiscalYear()
0434: + bal.getChartOfAccountsCode()
0435: + bal.getAccountNumber()
0436: + bal.getSubAccountNumber()
0437: + bal.getObjectCode()
0438: + bal.getSubObjectCode()
0439: + bal.getBalanceTypeCode()
0440: + bal.getObjectTypeCode()
0441: + " "
0442: + bal.getAccountLineAnnualBalanceAmount().add(
0443: bal.getBeginningBalanceLineAmount())
0444: + " TO CASH, TOTAL CASH NOW = "
0445: + unitOfWork.getTotalCash());
0446: }
0447: } else {
0448: for (OrganizationReversionCategory cat : categoryList) {
0449: OrganizationReversionCategoryLogic logic = categories
0450: .get(cat.getOrganizationReversionCategoryCode());
0451: if (logic.containsObjectCode(bal.getFinancialObject())) {
0452: if (options.getActualFinancialBalanceTypeCd()
0453: .equals(bal.getBalanceTypeCode())) {
0454: // Actual
0455: unitOfWork
0456: .addActualAmount(
0457: cat
0458: .getOrganizationReversionCategoryCode(),
0459: bal
0460: .getBeginningBalanceLineAmount());
0461: unitOfWork
0462: .addActualAmount(
0463: cat
0464: .getOrganizationReversionCategoryCode(),
0465: bal
0466: .getAccountLineAnnualBalanceAmount());
0467: incrementCount("balancesSelected");
0468: if (LOG.isDebugEnabled()) {
0469: LOG
0470: .debug("ADDING BALANCE TO ACTUAL: "
0471: + bal
0472: .getUniversityFiscalYear()
0473: + bal
0474: .getChartOfAccountsCode()
0475: + bal.getAccountNumber()
0476: + bal.getSubAccountNumber()
0477: + bal.getObjectCode()
0478: + bal.getSubObjectCode()
0479: + bal.getBalanceTypeCode()
0480: + bal.getObjectTypeCode()
0481: + " "
0482: + bal
0483: .getAccountLineAnnualBalanceAmount()
0484: .add(
0485: bal
0486: .getBeginningBalanceLineAmount())
0487: + " TO ACTUAL, ACTUAL FOR CATEGORY "
0488: + cat
0489: .getOrganizationReversionCategoryName()
0490: + " NOW = "
0491: + unitOfWork
0492: .getCategoryAmounts()
0493: .get(
0494: cat
0495: .getOrganizationReversionCategoryCode())
0496: .getActual());
0497: }
0498: } else if (options.getFinObjTypeExpenditureexpCd()
0499: .equals(bal.getBalanceTypeCode())
0500: || options
0501: .getCostShareEncumbranceBalanceTypeCd()
0502: .equals(bal.getBalanceTypeCode())
0503: || options.getIntrnlEncumFinBalanceTypCd()
0504: .equals(bal.getBalanceTypeCode())) {
0505: // Encumbrance
0506: KualiDecimal amount = bal
0507: .getBeginningBalanceLineAmount()
0508: .add(
0509: bal
0510: .getAccountLineAnnualBalanceAmount());
0511: if (amount.isPositive()) {
0512: unitOfWork
0513: .addEncumbranceAmount(
0514: cat
0515: .getOrganizationReversionCategoryCode(),
0516: amount);
0517: incrementCount("balancesSelected");
0518: if (LOG.isDebugEnabled()) {
0519: LOG
0520: .debug("ADDING BALANCE TO ENCUMBRANCE: "
0521: + bal
0522: .getUniversityFiscalYear()
0523: + bal
0524: .getChartOfAccountsCode()
0525: + bal
0526: .getAccountNumber()
0527: + bal
0528: .getSubAccountNumber()
0529: + bal.getObjectCode()
0530: + bal
0531: .getSubObjectCode()
0532: + bal
0533: .getBalanceTypeCode()
0534: + bal
0535: .getObjectTypeCode()
0536: + " "
0537: + bal
0538: .getAccountLineAnnualBalanceAmount()
0539: .add(
0540: bal
0541: .getBeginningBalanceLineAmount())
0542: + " TO ENCUMBRANCE, ENCUMBRANCE FOR CATEGORY "
0543: + cat
0544: .getOrganizationReversionCategoryName()
0545: + " NOW = "
0546: + unitOfWork
0547: .getCategoryAmounts()
0548: .get(
0549: cat
0550: .getOrganizationReversionCategoryCode())
0551: .getEncumbrance());
0552: }
0553: }
0554: } else if (KFSConstants.BALANCE_TYPE_CURRENT_BUDGET
0555: .equals(bal.getBalanceTypeCode())) {
0556: // Budget
0557: if (!CARRY_FORWARD_OBJECT_CODE.equals(bal
0558: .getObjectCode())) {
0559: unitOfWork
0560: .addBudgetAmount(
0561: cat
0562: .getOrganizationReversionCategoryCode(),
0563: bal
0564: .getBeginningBalanceLineAmount());
0565: unitOfWork
0566: .addBudgetAmount(
0567: cat
0568: .getOrganizationReversionCategoryCode(),
0569: bal
0570: .getAccountLineAnnualBalanceAmount());
0571: incrementCount("balancesSelected");
0572: if (LOG.isDebugEnabled()) {
0573: LOG
0574: .debug("ADDING BALANCE TO BUDGET: "
0575: + bal
0576: .getUniversityFiscalYear()
0577: + bal
0578: .getChartOfAccountsCode()
0579: + bal
0580: .getAccountNumber()
0581: + bal
0582: .getSubAccountNumber()
0583: + bal.getObjectCode()
0584: + bal
0585: .getSubObjectCode()
0586: + bal
0587: .getBalanceTypeCode()
0588: + bal
0589: .getObjectTypeCode()
0590: + " "
0591: + bal
0592: .getAccountLineAnnualBalanceAmount()
0593: .add(
0594: bal
0595: .getBeginningBalanceLineAmount())
0596: + " TO CURRENT BUDGET, CURRENT BUDGET FOR CATEGORY "
0597: + cat
0598: .getOrganizationReversionCategoryName()
0599: + " NOW = "
0600: + unitOfWork
0601: .getCategoryAmounts()
0602: .get(
0603: cat
0604: .getOrganizationReversionCategoryCode())
0605: .getBudget());
0606: }
0607: }
0608: }
0609: break;
0610: }
0611: }
0612: }
0613: }
0614:
0615: /**
0616: * This method determines which origin entries (reversion, cash reversion, or carry forward) need to be generated for the current unit of work,
0617: * and then delegates to the origin entry generation methods to create those entries
0618: *
0619: * @return a list of OriginEntries which need to be written
0620: * @throws FatalErrorException thrown if object codes are missing in any of the generation methods
0621: */
0622: public List<OriginEntryFull> generateOutputOriginEntries()
0623: throws FatalErrorException {
0624: List<OriginEntryFull> originEntriesToWrite = new ArrayList<OriginEntryFull>();
0625: if (unitOfWork.getTotalReversion().compareTo(KualiDecimal.ZERO) != 0) {
0626: generateReversions(originEntriesToWrite);
0627: }
0628: if ((unitOfWork.getTotalCarryForward().compareTo(
0629: KualiDecimal.ZERO) != 0)) {
0630: if (!organizationReversion
0631: .isCarryForwardByObjectCodeIndicator()) {
0632: generateCarryForwards(originEntriesToWrite);
0633: } else {
0634: generateMany(originEntriesToWrite);
0635: }
0636: }
0637: if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) != 0) {
0638: generateCashReversions(originEntriesToWrite);
0639: }
0640: return originEntriesToWrite;
0641: }
0642:
0643: /**
0644: * This method writes a list of OriginEntryFulls to a given origin entry group
0645: *
0646: * @param writeGroup the origin entry group to write to
0647: * @param originEntriesToWrite a list of origin entry fulls to write
0648: * @return the count of origin entries that were written
0649: */
0650: public int writeOriginEntries(OriginEntryGroup writeGroup,
0651: List<OriginEntryFull> originEntriesToWrite) {
0652: int originEntriesWritten = 0;
0653:
0654: for (OriginEntryFull originEntry : originEntriesToWrite) {
0655: originEntryService.createEntry(originEntry, writeGroup);
0656: originEntriesWritten += 1;
0657: }
0658:
0659: return originEntriesWritten;
0660: }
0661:
0662: /**
0663: * This method starts the creation of an origin entry, by setting fields that are the same in every Org Rev origin entries
0664: *
0665: * @return an OriginEntryFull partially filled out with constant information
0666: */
0667: private OriginEntryFull getEntry() {
0668: OriginEntryFull entry = new OriginEntryFull();
0669: entry.setUniversityFiscalYear((Integer) jobParameters
0670: .get(KFSConstants.UNIV_FISCAL_YR));
0671: entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH13);
0672: entry
0673: .setFinancialDocumentTypeCode(DEFAULT_FINANCIAL_DOCUMENT_TYPE_CODE);
0674: entry
0675: .setFinancialSystemOriginationCode(DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE);
0676: entry.setTransactionLedgerEntrySequenceNumber(1);
0677: entry
0678: .setTransactionDebitCreditCode(KFSConstants.GL_BUDGET_CODE);
0679: entry.setTransactionDate((Date) jobParameters
0680: .get(KFSConstants.TRANSACTION_DT));
0681: entry.setProjectCode(KFSConstants.getDashProjectCode());
0682: return entry;
0683: }
0684:
0685: /**
0686: * This method generates cash reversion origin entries for the current organization reversion, and adds them to the given list
0687: *
0688: * @param originEntriesToWrite a list of OriginEntryFulls to stick generated origin entries into
0689: * @throws FatalErrorException thrown if an origin entry's object code can't be found
0690: */
0691: public void generateCashReversions(
0692: List<OriginEntryFull> originEntriesToWrite)
0693: throws FatalErrorException {
0694: int entriesWritten = 0;
0695: OriginEntryFull entry = getEntry();
0696: entry.refreshReferenceObject("option");
0697:
0698: entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
0699: entry.setAccountNumber(unitOfWork.accountNumber);
0700: entry.setSubAccountNumber(unitOfWork.subAccountNumber);
0701: entry.setFinancialObjectCode(organizationReversion
0702: .getChartOfAccounts().getFinancialCashObjectCode());
0703: entry.setFinancialSubObjectCode(KFSConstants
0704: .getDashFinancialSubObjectCode());
0705: if (entry.getUniversityFiscalYear().equals(paramFiscalYear)) {
0706: entry.setFinancialBalanceTypeCode(priorYearOptions
0707: .getNominalFinancialBalanceTypeCd());
0708: } else {
0709: entry.setFinancialBalanceTypeCode(currentYearOptions
0710: .getNominalFinancialBalanceTypeCd());
0711: }
0712:
0713: persistenceService.retrieveReferenceObject(entry,
0714: KFSPropertyConstants.FINANCIAL_OBJECT);
0715: if (ObjectUtils.isNull(entry.getFinancialObject())) {
0716: throw new FatalErrorException(
0717: "Object Code for Entry not found: " + entry);
0718: }
0719:
0720: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
0721: + entry.getAccountNumber());
0722: entry
0723: .setTransactionLedgerEntryDescription(CASH_REVERTED_TO_MESSAGE
0724: + " "
0725: + organizationReversion
0726: .getCashReversionAccountNumber());
0727: entry
0728: .setTransactionLedgerEntryAmount(unitOfWork
0729: .getTotalCash());
0730: if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) > 0) {
0731: entry
0732: .setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE);
0733: } else {
0734: entry
0735: .setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE);
0736: entry.setTransactionLedgerEntryAmount(unitOfWork
0737: .getTotalCash().negated());
0738: }
0739: entry.setFinancialObjectTypeCode(entry.getFinancialObject()
0740: .getFinancialObjectTypeCode());
0741:
0742: // 3468 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
0743: // 3469 WS-AMT-N.
0744: // 3470 MOVE WS-AMT-X TO TRN-AMT-RED-X.
0745:
0746: originEntriesToWrite.add(entry);
0747:
0748: entry = getEntry();
0749: entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
0750: entry.setAccountNumber(unitOfWork.accountNumber);
0751: entry.setSubAccountNumber(unitOfWork.subAccountNumber);
0752: entry.setFinancialObjectCode((String) jobParameters
0753: .get(KFSConstants.FUND_BAL_OBJECT_CD));
0754: entry.setFinancialSubObjectCode(KFSConstants
0755: .getDashFinancialSubObjectCode());
0756: entry
0757: .setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE);
0758:
0759: persistenceService.retrieveReferenceObject(entry,
0760: KFSPropertyConstants.FINANCIAL_OBJECT);
0761: if (ObjectUtils.isNull(entry.getFinancialObject())) {
0762: throw new FatalErrorException(
0763: "Object Code for Entry not found: " + entry);
0764: }
0765:
0766: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
0767: + unitOfWork.accountNumber);
0768: entry
0769: .setTransactionLedgerEntryDescription(FUND_BALANCE_REVERTED_TO_MESSAGE
0770: + organizationReversion
0771: .getCashReversionAccountNumber());
0772: entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCash()
0773: .abs());
0774: if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) > 0) {
0775: entry
0776: .setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE);
0777: } else {
0778: entry
0779: .setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE);
0780: }
0781: entry.setFinancialObjectTypeCode(entry.getFinancialObject()
0782: .getFinancialObjectTypeCode());
0783:
0784: // 3570 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
0785: // 3571 WS-AMT-N.
0786: // 3572 MOVE WS-AMT-X TO TRN-AMT-RED-X.
0787:
0788: originEntriesToWrite.add(entry);
0789:
0790: entry = getEntry();
0791: entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
0792: entry.setAccountNumber(organizationReversion
0793: .getCashReversionAccountNumber());
0794: entry.setSubAccountNumber(KFSConstants
0795: .getDashSubAccountNumber());
0796: entry.setFinancialObjectCode(organizationReversion
0797: .getChartOfAccounts().getFinancialCashObjectCode());
0798: entry.setFinancialSubObjectCode(KFSConstants
0799: .getDashFinancialSubObjectCode());
0800: entry
0801: .setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE);
0802:
0803: persistenceService.retrieveReferenceObject(entry,
0804: KFSPropertyConstants.FINANCIAL_OBJECT);
0805: if (ObjectUtils.isNull(entry.getFinancialObject())) {
0806: throw new FatalErrorException(
0807: "Object Code for Entry not found: " + entry);
0808: }
0809:
0810: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
0811: + unitOfWork.accountNumber);
0812: entry
0813: .setTransactionLedgerEntryDescription(CASH_REVERTED_FROM_MESSAGE
0814: + unitOfWork.accountNumber
0815: + " "
0816: + unitOfWork.subAccountNumber);
0817: entry
0818: .setTransactionLedgerEntryAmount(unitOfWork
0819: .getTotalCash());
0820: if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) > 0) {
0821: entry
0822: .setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE);
0823: } else {
0824: entry
0825: .setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE);
0826: entry.setTransactionLedgerEntryAmount(unitOfWork
0827: .getTotalCash().negated());
0828: }
0829: entry.setFinancialObjectTypeCode(entry.getFinancialObject()
0830: .getFinancialObjectTypeCode());
0831:
0832: // 3668 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
0833: // 3669 WS-AMT-N.
0834: // 3670 MOVE WS-AMT-X TO TRN-AMT-RED-X.
0835:
0836: originEntriesToWrite.add(entry);
0837:
0838: entry = getEntry();
0839: entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
0840: entry.setAccountNumber(organizationReversion
0841: .getCashReversionAccountNumber());
0842: entry.setSubAccountNumber(KFSConstants
0843: .getDashSubAccountNumber());
0844: entry.setFinancialObjectCode((String) jobParameters
0845: .get(KFSConstants.FUND_BAL_OBJECT_CD));
0846: entry.setFinancialSubObjectCode(KFSConstants
0847: .getDashFinancialSubObjectCode());
0848: entry
0849: .setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE);
0850:
0851: persistenceService.retrieveReferenceObject(entry,
0852: KFSPropertyConstants.FINANCIAL_OBJECT);
0853: if (ObjectUtils.isNull(entry.getFinancialObject())) {
0854: throw new FatalErrorException(
0855: "Object Code for Entry not found: " + entry);
0856: }
0857:
0858: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
0859: + unitOfWork.accountNumber);
0860: entry
0861: .setTransactionLedgerEntryDescription(FUND_BALANCE_REVERTED_FROM_MESSAGE
0862: + unitOfWork.accountNumber
0863: + " "
0864: + unitOfWork.subAccountNumber);
0865: entry
0866: .setTransactionLedgerEntryAmount(unitOfWork
0867: .getTotalCash());
0868: if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) > 0) {
0869: entry
0870: .setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE);
0871: } else {
0872: entry
0873: .setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE);
0874: entry.setTransactionLedgerEntryAmount(unitOfWork
0875: .getTotalCash().negated());
0876: }
0877: entry.setFinancialObjectTypeCode(entry.getFinancialObject()
0878: .getFinancialObjectTypeCode());
0879:
0880: // 3768 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
0881: // 3769 WS-AMT-N.
0882: // 3770 MOVE WS-AMT-X TO TRN-AMT-RED-X.
0883:
0884: originEntriesToWrite.add(entry);
0885: }
0886:
0887: /**
0888: * Generates carry forward origin entries on a category by category basis (if the organization reversion record asks for that), assuming carry
0889: * forwards are required for the current unit of work
0890: *
0891: * @param originEntriesToWrite a list of origin entries to write, which any generated origin entries should be added to
0892: * @throws FatalErrorException thrown if an object code cannot be found
0893: */
0894: public void generateMany(List<OriginEntryFull> originEntriesToWrite)
0895: throws FatalErrorException {
0896: int originEntriesCreated = 0;
0897: for (Iterator<OrganizationReversionCategory> iter = categoryList
0898: .iterator(); iter.hasNext();) {
0899: OrganizationReversionCategory cat = iter.next();
0900: OrganizationReversionDetail detail = organizationReversion
0901: .getOrganizationReversionDetail(cat
0902: .getOrganizationReversionCategoryCode());
0903: OrgReversionUnitOfWorkCategoryAmount amount = unitOfWork.amounts
0904: .get(cat.getOrganizationReversionCategoryCode());
0905:
0906: if (!amount.getCarryForward().isZero()) {
0907: KualiDecimal commonAmount = amount.getCarryForward();
0908: String commonObject = detail
0909: .getOrganizationReversionObjectCode();
0910:
0911: OriginEntryFull entry = getEntry();
0912: entry.setUniversityFiscalYear((Integer) jobParameters
0913: .get(KFSConstants.UNIV_FISCAL_YR) + 1);
0914: entry
0915: .setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
0916: entry.setAccountNumber(unitOfWork.accountNumber);
0917: entry.setSubAccountNumber(unitOfWork.subAccountNumber);
0918: entry.setFinancialObjectCode((String) jobParameters
0919: .get(KFSConstants.BEG_BUD_CASH_OBJECT_CD));
0920: entry.setFinancialSubObjectCode(KFSConstants
0921: .getDashFinancialSubObjectCode());
0922: entry
0923: .setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
0924:
0925: persistenceService.retrieveReferenceObject(entry,
0926: KFSPropertyConstants.FINANCIAL_OBJECT);
0927: if (ObjectUtils.isNull(entry.getFinancialObject())) {
0928: throw new FatalErrorException(
0929: "Object Code for Entry not found: " + entry);
0930: }
0931:
0932: ObjectCode objectCode = entry.getFinancialObject();
0933: entry.setFinancialObjectTypeCode(objectCode
0934: .getFinancialObjectTypeCode());
0935: entry
0936: .setUniversityFiscalPeriodCode(KFSConstants.MONTH1);
0937: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
0938: + unitOfWork.accountNumber);
0939: entry
0940: .setTransactionLedgerEntryDescription(FUND_CARRIED_MESSAGE
0941: + (Integer) jobParameters
0942: .get(KFSConstants.UNIV_FISCAL_YR));
0943: entry.setTransactionLedgerEntryAmount(commonAmount);
0944:
0945: // 3259 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
0946: // 3260 WS-AMT-N.
0947: // 3261 MOVE WS-AMT-X TO TRN-AMT-RED-X.
0948:
0949: originEntriesToWrite.add(entry);
0950:
0951: entry = getEntry();
0952: entry.setUniversityFiscalYear((Integer) jobParameters
0953: .get(KFSConstants.UNIV_FISCAL_YR) + 1);
0954: entry
0955: .setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
0956: entry.setAccountNumber(unitOfWork.accountNumber);
0957: entry.setSubAccountNumber(unitOfWork.subAccountNumber);
0958:
0959: entry.setFinancialObjectCode(commonObject);
0960: entry.setFinancialSubObjectCode(KFSConstants
0961: .getDashFinancialSubObjectCode());
0962: entry
0963: .setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
0964:
0965: persistenceService.retrieveReferenceObject(entry,
0966: KFSPropertyConstants.FINANCIAL_OBJECT);
0967: if (ObjectUtils.isNull(entry.getFinancialObject())) {
0968: throw new FatalErrorException(
0969: "Object Code for Entry not found: " + entry);
0970: }
0971:
0972: objectCode = entry.getFinancialObject();
0973: entry.setFinancialObjectTypeCode(objectCode
0974: .getFinancialObjectTypeCode());
0975: entry
0976: .setUniversityFiscalPeriodCode(KFSConstants.MONTH1);
0977: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
0978: + unitOfWork.accountNumber);
0979: entry
0980: .setTransactionLedgerEntryDescription(FUND_CARRIED_MESSAGE
0981: + (Integer) jobParameters
0982: .get(KFSConstants.UNIV_FISCAL_YR));
0983: entry.setTransactionLedgerEntryAmount(commonAmount);
0984:
0985: // 3343 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
0986: // 3344 WS-AMT-N.
0987: // 3345 MOVE WS-AMT-X TO TRN-AMT-RED-X.
0988:
0989: originEntriesToWrite.add(entry);
0990: }
0991: }
0992: }
0993:
0994: /**
0995: * If carry forwards need to be generated for this unit of work, this method will generate the origin entries to accomplish those object codes.
0996: * Note: this will only be called if the organization reversion record tells the process to munge all carry forwards for all categories
0997: * together; if the organization reversion record does not call for such a thing, then generateMany will be called
0998: *
0999: * @param originEntriesToWrite a list of origin entries to write, that any generated origin entries should be added to
1000: * @throws FatalErrorException thrown if the current object code can't be found in the database
1001: */
1002: public void generateCarryForwards(
1003: List<OriginEntryFull> originEntriesToWrite)
1004: throws FatalErrorException {
1005: int originEntriesWritten = 0;
1006:
1007: OriginEntryFull entry = getEntry();
1008: entry.setUniversityFiscalYear((Integer) jobParameters
1009: .get(KFSConstants.UNIV_FISCAL_YR) + 1);
1010: entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
1011: entry.setAccountNumber(unitOfWork.accountNumber);
1012: entry.setSubAccountNumber(unitOfWork.subAccountNumber);
1013: entry.setFinancialObjectCode((String) jobParameters
1014: .get(KFSConstants.BEG_BUD_CASH_OBJECT_CD));
1015: entry.setFinancialSubObjectCode(KFSConstants
1016: .getDashFinancialSubObjectCode());
1017: entry
1018: .setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
1019:
1020: persistenceService.retrieveReferenceObject(entry,
1021: KFSPropertyConstants.FINANCIAL_OBJECT);
1022: if (ObjectUtils.isNull(entry.getFinancialObject())) {
1023: throw new FatalErrorException(
1024: "Object Code for Entry not found: " + entry);
1025: }
1026:
1027: ObjectCode objectCode = entry.getFinancialObject();
1028: entry.setFinancialObjectTypeCode(objectCode
1029: .getFinancialObjectTypeCode());
1030: entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH1);
1031: entry
1032: .setFinancialDocumentTypeCode(DEFAULT_FINANCIAL_DOCUMENT_TYPE_CODE);
1033: entry
1034: .setFinancialSystemOriginationCode(DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE);
1035: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
1036: + unitOfWork.accountNumber);
1037: entry.setTransactionLedgerEntrySequenceNumber(1);
1038: entry.setTransactionLedgerEntryDescription(FUND_CARRIED_MESSAGE
1039: + (Integer) jobParameters
1040: .get(KFSConstants.UNIV_FISCAL_YR));
1041: entry.setTransactionLedgerEntryAmount(unitOfWork
1042: .getTotalCarryForward());
1043: entry.setTransactionDate((Date) jobParameters
1044: .get(KFSConstants.TRANSACTION_DT));
1045: entry.setProjectCode(KFSConstants.getDashProjectCode());
1046: // 2995 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
1047: // 2996 WS-AMT-N.
1048: // 2997 MOVE WS-AMT-X TO TRN-AMT-RED-X.
1049:
1050: originEntriesToWrite.add(entry);
1051:
1052: entry = getEntry();
1053: entry.setUniversityFiscalYear((Integer) jobParameters
1054: .get(KFSConstants.UNIV_FISCAL_YR) + 1);
1055: entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
1056: entry.setAccountNumber(unitOfWork.accountNumber);
1057: entry.setSubAccountNumber(unitOfWork.subAccountNumber);
1058: entry.setFinancialObjectCode((String) jobParameters
1059: .get(KFSConstants.UNALLOC_OBJECT_CD));
1060:
1061: persistenceService.retrieveReferenceObject(entry,
1062: KFSPropertyConstants.FINANCIAL_OBJECT);
1063: if (ObjectUtils.isNull(entry.getFinancialObject())) {
1064: throw new FatalErrorException(
1065: "Object Code for Entry not found: " + entry);
1066: }
1067:
1068: objectCode = entry.getFinancialObject();
1069: entry.setFinancialObjectTypeCode(objectCode
1070: .getFinancialObjectTypeCode());
1071: entry.setFinancialSubObjectCode(KFSConstants
1072: .getDashFinancialSubObjectCode());
1073: entry
1074: .setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
1075: entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH1);
1076: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
1077: + unitOfWork.accountNumber);
1078: entry.setTransactionLedgerEntryDescription(FUND_CARRIED_MESSAGE
1079: + (Integer) jobParameters
1080: .get(KFSConstants.UNIV_FISCAL_YR));
1081: entry.setTransactionLedgerEntryAmount(unitOfWork
1082: .getTotalCarryForward());
1083:
1084: // 3079 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
1085: // 3080 WS-AMT-N.
1086: // 3081 MOVE WS-AMT-X TO TRN-AMT-RED-X.
1087:
1088: originEntriesToWrite.add(entry);
1089:
1090: }
1091:
1092: /**
1093: * If reversions are necessary, this will generate the origin entries for those reversions
1094: *
1095: * @param originEntriesToWrite the list of origin entries to add reversions into
1096: * @throws FatalErrorException thrown if object code if the entry can't be found
1097: */
1098: public void generateReversions(
1099: List<OriginEntryFull> originEntriesToWrite)
1100: throws FatalErrorException {
1101: int originEntriesWritten = 0;
1102:
1103: OriginEntryFull entry = getEntry();
1104: entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
1105: entry.setAccountNumber(unitOfWork.accountNumber);
1106: entry.setSubAccountNumber(unitOfWork.subAccountNumber);
1107: entry.setFinancialObjectCode((String) jobParameters
1108: .get(KFSConstants.UNALLOC_OBJECT_CD));
1109: entry.setFinancialSubObjectCode(KFSConstants
1110: .getDashFinancialSubObjectCode());
1111: entry
1112: .setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END);
1113:
1114: persistenceService.retrieveReferenceObject(entry,
1115: KFSPropertyConstants.FINANCIAL_OBJECT);
1116: if (ObjectUtils.isNull(entry.getFinancialObject())) {
1117: throw new FatalErrorException(
1118: "Object Code for Entry not found: " + entry);
1119: }
1120:
1121: ObjectCode objectCode = entry.getFinancialObject();
1122: entry.setFinancialObjectTypeCode(objectCode
1123: .getFinancialObjectTypeCode());
1124:
1125: entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH13);
1126:
1127: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
1128: + entry.getAccountNumber());
1129:
1130: entry
1131: .setTransactionLedgerEntryDescription(FUND_REVERTED_TO_MESSAGE
1132: + organizationReversion
1133: .getBudgetReversionAccountNumber());
1134: entry.setTransactionLedgerEntryAmount(unitOfWork
1135: .getTotalReversion().negated());
1136:
1137: // 2841 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
1138: // 2842 WS-AMT-N.
1139: // 2843 MOVE WS-AMT-X TO TRN-AMT-RED-X.
1140:
1141: originEntriesToWrite.add(entry);
1142:
1143: entry = getEntry();
1144: entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode);
1145: entry.setAccountNumber(organizationReversion
1146: .getBudgetReversionAccountNumber());
1147: entry.setSubAccountNumber(KFSConstants
1148: .getDashSubAccountNumber());
1149: entry.setFinancialObjectCode((String) jobParameters
1150: .get(KFSConstants.UNALLOC_OBJECT_CD));
1151: entry.setFinancialSubObjectCode(KFSConstants
1152: .getDashFinancialSubObjectCode());
1153: entry
1154: .setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END);
1155: entry.setFinancialObjectTypeCode(objectCode
1156: .getFinancialObjectTypeCode());
1157: entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH13);
1158: entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX
1159: + unitOfWork.accountNumber);
1160: if (unitOfWork.accountNumber.equals(KFSConstants
1161: .getDashSubAccountNumber())) {
1162: entry
1163: .setTransactionLedgerEntryDescription(FUND_REVERTED_FROM_MESSAGE
1164: + unitOfWork.accountNumber);
1165: } else {
1166: entry
1167: .setTransactionLedgerEntryDescription(FUND_REVERTED_FROM_MESSAGE
1168: + unitOfWork.accountNumber
1169: + " "
1170: + unitOfWork.subAccountNumber);
1171: }
1172: entry.setTransactionLedgerEntryAmount(unitOfWork
1173: .getTotalReversion());
1174:
1175: // 2899 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD
1176: // 2900 WS-AMT-N.
1177: // 2901 MOVE WS-AMT-X TO TRN-AMT-RED-X.
1178:
1179: originEntriesToWrite.add(entry);
1180: }
1181:
1182: /**
1183: * This method calculates the totals for a given unit of work's reversion
1184: *
1185: * @throws FatalErrorException
1186: */
1187: public void calculateTotals() throws FatalErrorException {
1188: /*
1189: * How this works At the start, in the clearCalculationTotals(), both the unit of work's totalAvailable and totalReversion
1190: * are set to the available amounts from each of the category amounts. Then, as the logic is applied, the totalCarryForward
1191: * is added to and the totalReversion is subtracted from. Let's look at a simple example: Let's say you've got an amount for
1192: * C01, which has $2000 available, no encumbrances, that's all you've got This means that at the end of
1193: * clearCalculationTotals(), there's $2000 in totalAvailable, $2000 in totalReversion, and $0 in totalCarryForward Now, C01,
1194: * let's say, is for code A. So, look below at the if that catches Code A. You'll note that it adds the available amount to
1195: * totalCarryForward, it's own carryForward, the negated available to totalReversion, and that, done, it sets available to
1196: * $0. With our example, that means that $2000 is in totalCarryForward (and in the amount's carryForward), the
1197: * totalReversion has been knocked down to $0, and the available is $0. So, carry forward origin entries get created, and
1198: * reversions do not. This is also why you don't see a block about calculating R2 totals below...the process has a natural
1199: * inclination towards creating R2 (ie, ignore encumbrances and revert all available) entries.
1200: */
1201:
1202: // clear out the unit of work totals we're going to calculate values in, in preperation for applying rules
1203: clearCalculationTotals();
1204:
1205: // For each category, apply the rules
1206: for (OrganizationReversionCategory category : categoryList) {
1207: String categoryCode = category
1208: .getOrganizationReversionCategoryCode();
1209: OrganizationReversionCategoryLogic logic = categories
1210: .get(categoryCode);
1211: OrgReversionUnitOfWorkCategoryAmount amount = unitOfWork.amounts
1212: .get(categoryCode);
1213:
1214: OrganizationReversionDetail detail = organizationReversion
1215: .getOrganizationReversionDetail(categoryCode);
1216:
1217: if (detail == null) {
1218: throw new FatalErrorException("Organization Reversion "
1219: + organizationReversion
1220: .getUniversityFiscalYear()
1221: + "-"
1222: + organizationReversion
1223: .getChartOfAccountsCode() + "-"
1224: + organizationReversion.getOrganizationCode()
1225: + " does not have a detail for category "
1226: + categoryCode);
1227: }
1228: String ruleCode = detail.getOrganizationReversionCode();
1229:
1230: if (LOG.isDebugEnabled()) {
1231: LOG.debug("Unit of Work: "
1232: + unitOfWork.getChartOfAccountsCode()
1233: + unitOfWork.getAccountNumber()
1234: + unitOfWork.getSubAccountNumber()
1235: + ", category "
1236: + category
1237: .getOrganizationReversionCategoryName()
1238: + ": budget = " + amount.getBudget()
1239: + "; actual = " + amount.getActual()
1240: + "; encumbrance = " + amount.getEncumbrance()
1241: + "; available = " + amount.getAvailable()
1242: + "; apply rule code " + ruleCode);
1243: }
1244:
1245: if (KFSConstants.RULE_CODE_R1.equals(ruleCode)
1246: || KFSConstants.RULE_CODE_N1.equals(ruleCode)
1247: || KFSConstants.RULE_CODE_C1.equals(ruleCode)) {
1248: if (amount.getAvailable().compareTo(KualiDecimal.ZERO) > 0) { // do we have budget left?
1249: if (amount.getAvailable().compareTo(
1250: amount.getEncumbrance()) > 0) { // is it more than enough to cover our
1251: // encumbrances?
1252: unitOfWork.addTotalCarryForward(amount
1253: .getEncumbrance());
1254: amount.addCarryForward(amount.getEncumbrance());
1255: unitOfWork.addTotalReversion(amount
1256: .getEncumbrance().negated());
1257: amount.addAvailable(amount.getEncumbrance()
1258: .negated());
1259: } else {
1260: // there's not enough available left to cover the encumbrances; cover what we can
1261: unitOfWork.addTotalCarryForward(amount
1262: .getAvailable());
1263: amount.addCarryForward(amount.getAvailable());
1264: unitOfWork.addTotalReversion(amount
1265: .getAvailable().negated());
1266: amount.setAvailable(KualiDecimal.ZERO);
1267: }
1268: }
1269: }
1270:
1271: if (KFSConstants.RULE_CODE_A.equals(ruleCode)) {
1272: unitOfWork.addTotalCarryForward(amount.getAvailable());
1273: amount.addCarryForward(amount.getAvailable());
1274: unitOfWork.addTotalReversion(amount.getAvailable()
1275: .negated());
1276: amount.setAvailable(KualiDecimal.ZERO);
1277: }
1278:
1279: if (KFSConstants.RULE_CODE_C1.equals(ruleCode)
1280: || KFSConstants.RULE_CODE_C2.equals(ruleCode)) {
1281: if (amount.getAvailable().compareTo(KualiDecimal.ZERO) > 0) {
1282: unitOfWork.addTotalCarryForward(amount
1283: .getAvailable());
1284: amount.addCarryForward(amount.getAvailable());
1285: unitOfWork.addTotalReversion(amount.getAvailable()
1286: .negated());
1287: amount.setAvailable(KualiDecimal.ZERO);
1288: }
1289: }
1290:
1291: if (KFSConstants.RULE_CODE_N1.equals(ruleCode)
1292: || KFSConstants.RULE_CODE_N2.equals(ruleCode)) {
1293: if (amount.getAvailable().compareTo(KualiDecimal.ZERO) < 0) {
1294: unitOfWork.addTotalCarryForward(amount
1295: .getAvailable());
1296: amount.addCarryForward(amount.getAvailable());
1297: unitOfWork.addTotalReversion(amount.getAvailable()
1298: .negated());
1299: amount.setAvailable(KualiDecimal.ZERO);
1300: }
1301: }
1302:
1303: if (LOG.isDebugEnabled()) {
1304: LOG.debug("Totals Now: "
1305: + unitOfWork.getChartOfAccountsCode()
1306: + unitOfWork.getAccountNumber()
1307: + unitOfWork.getSubAccountNumber()
1308: + ", total cash now "
1309: + unitOfWork.getTotalCash()
1310: + ": total available = "
1311: + unitOfWork.getTotalAvailable()
1312: + "; total reversion = "
1313: + unitOfWork.getTotalReversion()
1314: + "; total carry forward = "
1315: + unitOfWork.getTotalCarryForward());
1316: }
1317: }
1318: }
1319:
1320: /**
1321: * This method clears the unit of work's amounts to what they should be before each category bucket is calculated; specifically,
1322: * the total available for each category is calculated, and the total available and total reversion are set to the sum of all
1323: * available from each category bucket. The total carry forward is set to 0.
1324: */
1325: private void clearCalculationTotals() {
1326: // Initialize all the amounts before applying the proper rule
1327: KualiDecimal totalAvailable = KualiDecimal.ZERO;
1328: for (OrganizationReversionCategory category : categoryList) {
1329: OrganizationReversionCategoryLogic logic = categories
1330: .get(category
1331: .getOrganizationReversionCategoryCode());
1332:
1333: OrgReversionUnitOfWorkCategoryAmount amount = unitOfWork.amounts
1334: .get(category
1335: .getOrganizationReversionCategoryCode());
1336: if (logic.isExpense()) {
1337: amount.setAvailable(amount.getBudget().subtract(
1338: amount.getActual()));
1339: } else {
1340: amount.setAvailable(amount.getActual().subtract(
1341: amount.getBudget()));
1342: }
1343: totalAvailable = totalAvailable.add(amount.getAvailable());
1344: amount.setCarryForward(KualiDecimal.ZERO);
1345: }
1346: unitOfWork.setTotalAvailable(totalAvailable);
1347: unitOfWork.setTotalReversion(totalAvailable);
1348: unitOfWork.setTotalCarryForward(KualiDecimal.ZERO);
1349: }
1350:
1351: public OrgReversionUnitOfWork getUnitOfWork() {
1352: return unitOfWork;
1353: }
1354:
1355: public void setUnitOfWork(OrgReversionUnitOfWork unitOfWork) {
1356: this .unitOfWork = unitOfWork;
1357: }
1358:
1359: public List<OrganizationReversionCategory> getCategoryList() {
1360: return this .categoryList;
1361: }
1362:
1363: /**
1364: * Gets the generatedOriginEntries attribute.
1365: *
1366: * @return Returns the generatedOriginEntries.
1367: */
1368: public List<OriginEntryFull> getGeneratedOriginEntries() {
1369: return generatedOriginEntries;
1370: }
1371:
1372: /**
1373: * Sets the holdGeneratedOriginEntries attribute value.
1374: *
1375: * @param holdGeneratedOriginEntries The holdGeneratedOriginEntries to set.
1376: */
1377: public void setHoldGeneratedOriginEntries(
1378: boolean holdGeneratedOriginEntries) {
1379: this .holdGeneratedOriginEntries = holdGeneratedOriginEntries;
1380: this .generatedOriginEntries = new ArrayList<OriginEntryFull>();
1381: }
1382:
1383: /**
1384: * Returns the total number of balances for the previous fiscal year
1385: *
1386: * @return the total number of balances for the previous fiscal year
1387: */
1388: public int getBalancesRead() {
1389: return organizationReversionCounts.get("balancesRead")
1390: .intValue();
1391: }
1392:
1393: /**
1394: * Returns the total number of balances selected for inclusion in this process
1395: *
1396: * @return the total number of balances selected for inclusion in this process
1397: */
1398: public int getBalancesSelected() {
1399: return organizationReversionCounts.get("balancesSelected")
1400: .intValue();
1401: }
1402:
1403: /**
1404: * Returns the total number of origin entries written by this process
1405: *
1406: * @return the total number of origin entries written by this process
1407: */
1408: public int getRecordsWritten() {
1409: return organizationReversionCounts.get("recordsWritten")
1410: .intValue();
1411: }
1412:
1413: /**
1414: * Used mainly for unit testing, this method allows a way to change the output group of a org reversion process run
1415: *
1416: * @param outputGroup
1417: */
1418: public void setOutputGroup(OriginEntryGroup outputGroup) {
1419: this .outputGroup = outputGroup;
1420: }
1421:
1422: /**
1423: * Increments one of the totals held in the count map this process uses for reported statistics
1424: *
1425: * @param countName the name of the count to increment
1426: */
1427: private void incrementCount(String countName) {
1428: incrementCount(countName, 1);
1429: }
1430:
1431: /**
1432: * Increments one of the totals held in the count map this process uses for reported statistics by a given increment
1433: *
1434: * @param countName the name of the count to increment
1435: * @param increment the amount to increment
1436: */
1437: private void incrementCount(String countName, int increment) {
1438: Integer count = organizationReversionCounts.get(countName);
1439: organizationReversionCounts.put(countName, new Integer(count
1440: .intValue()
1441: + increment));
1442: }
1443: }
|