/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.gl.batch.service.impl; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintStream; import java.sql.Date; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.kuali.kfs.coa.businessobject.AccountIntf; import org.kuali.kfs.coa.businessobject.CarryForwardReversionProcessOrganizationInfo; import org.kuali.kfs.coa.businessobject.ClosedAccountOrganizationReversion; import org.kuali.kfs.coa.businessobject.ObjectCode; import org.kuali.kfs.coa.businessobject.OrganizationReversion; import org.kuali.kfs.coa.businessobject.OrganizationReversionCategory; import org.kuali.kfs.coa.businessobject.OrganizationReversionCategoryInfo; import org.kuali.kfs.coa.service.OrganizationReversionService; import org.kuali.kfs.coa.service.PriorYearAccountService; import org.kuali.kfs.gl.GeneralLedgerConstants; import org.kuali.kfs.gl.batch.service.OrganizationReversionCategoryLogic; import org.kuali.kfs.gl.batch.service.OrganizationReversionProcess; import org.kuali.kfs.gl.batch.service.OrganizationReversionUnitOfWorkService; import org.kuali.kfs.gl.batch.service.impl.exception.FatalErrorException; import org.kuali.kfs.gl.businessobject.Balance; import org.kuali.kfs.gl.businessobject.OrgReversionUnitOfWork; import org.kuali.kfs.gl.businessobject.OrgReversionUnitOfWorkCategoryAmount; import org.kuali.kfs.gl.businessobject.OriginEntryFull; import org.kuali.kfs.gl.report.LedgerSummaryReport; import org.kuali.kfs.gl.service.BalanceService; import org.kuali.kfs.gl.service.OriginEntryService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.businessobject.SystemOptions; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.service.FlexibleOffsetAccountService; import org.kuali.kfs.sys.service.OptionsService; import org.kuali.kfs.sys.service.ReportWriterService; import org.kuali.kfs.sys.service.impl.KfsParameterConstants; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.krad.service.PersistenceService; import org.kuali.rice.krad.util.ObjectUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.transaction.annotation.Transactional; /** * This class actually runs the year end organization reversion process */ @Transactional public class OrganizationReversionProcessImpl implements OrganizationReversionProcess, InitializingBean { private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(OrganizationReversionProcessImpl.class); // Services private OrganizationReversionService organizationReversionService; private BalanceService balanceService; private OriginEntryService originEntryService; private PersistenceService persistenceService; private DateTimeService dateTimeService; private OrganizationReversionCategoryLogic cashOrganizationReversionCategoryLogic; private PriorYearAccountService priorYearAccountService; private OrganizationReversionUnitOfWorkService orgReversionUnitOfWorkService; private FlexibleOffsetAccountService flexibleOffsetAccountService; private ParameterService parameterService; private ConfigurationService configurationService; private String batchFileDirectoryName; private String outputFileName; private OrgReversionUnitOfWork unitOfWork; private Map<String, OrganizationReversionCategoryLogic> categories; private List<OrganizationReversionCategory> categoryList; private CarryForwardReversionProcessOrganizationInfo organizationReversion; private AccountIntf account; private Map jobParameters; private Map<String, Integer> organizationReversionCounts; private boolean usePriorYearInformation; private boolean holdGeneratedOriginEntries = false; private List<OriginEntryFull> generatedOriginEntries; public String CARRY_FORWARD_OBJECT_CODE; public String DEFAULT_FINANCIAL_DOCUMENT_TYPE_CODE; public String DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE; public String DEFAULT_FINANCIAL_BALANCE_TYPE_CODE; public String DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END; public String DEFAULT_DOCUMENT_NUMBER_PREFIX; private String CASH_REVERTED_TO_MESSAGE; private String FUND_BALANCE_REVERTED_TO_MESSAGE; private String CASH_REVERTED_FROM_MESSAGE; private String FUND_BALANCE_REVERTED_FROM_MESSAGE; private String FUND_CARRIED_MESSAGE; private String FUND_REVERTED_TO_MESSAGE; private String FUND_REVERTED_FROM_MESSAGE; private SystemOptions systemOptions; private Integer paramFiscalYear; private LedgerSummaryReport ledgerReport; private PrintStream outputPs; /** * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { this.CARRY_FORWARD_OBJECT_CODE = getParameterService().getParameterValueAsString(OrganizationReversion.class, GeneralLedgerConstants.OrganizationReversionProcess.CARRY_FORWARD_OBJECT_CODE); this.DEFAULT_FINANCIAL_DOCUMENT_TYPE_CODE = getParameterService().getParameterValueAsString(KfsParameterConstants.GENERAL_LEDGER_BATCH.class, GeneralLedgerConstants.ANNUAL_CLOSING_DOCUMENT_TYPE); this.DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE = getParameterService().getParameterValueAsString(OrganizationReversion.class, GeneralLedgerConstants.OrganizationReversionProcess.DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE); this.DEFAULT_FINANCIAL_BALANCE_TYPE_CODE = getParameterService().getParameterValueAsString(OrganizationReversion.class, GeneralLedgerConstants.OrganizationReversionProcess.DEFAULT_FINANCIAL_BALANCE_TYPE_CODE); this.DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END = getParameterService().getParameterValueAsString(OrganizationReversion.class, GeneralLedgerConstants.OrganizationReversionProcess.DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END); this.DEFAULT_DOCUMENT_NUMBER_PREFIX = getParameterService().getParameterValueAsString(OrganizationReversion.class, GeneralLedgerConstants.OrganizationReversionProcess.DEFAULT_DOCUMENT_NUMBER_PREFIX); this.CASH_REVERTED_TO_MESSAGE = getConfigurationService().getPropertyValueAsString(KFSKeyConstants.OrganizationReversionProcess.CASH_REVERTED_TO); this.FUND_BALANCE_REVERTED_TO_MESSAGE = getConfigurationService().getPropertyValueAsString(KFSKeyConstants.OrganizationReversionProcess.FUND_BALANCE_REVERTED_TO); this.CASH_REVERTED_FROM_MESSAGE = getConfigurationService().getPropertyValueAsString(KFSKeyConstants.OrganizationReversionProcess.CASH_REVERTED_FROM); this.FUND_BALANCE_REVERTED_FROM_MESSAGE = getConfigurationService().getPropertyValueAsString(KFSKeyConstants.OrganizationReversionProcess.FUND_BALANCE_REVERTED_FROM); this.FUND_CARRIED_MESSAGE = getConfigurationService().getPropertyValueAsString(KFSKeyConstants.OrganizationReversionProcess.FUND_CARRIED); this.FUND_REVERTED_TO_MESSAGE = getConfigurationService().getPropertyValueAsString(KFSKeyConstants.OrganizationReversionProcess.FUND_REVERTED_TO); this.FUND_REVERTED_FROM_MESSAGE = getConfigurationService().getPropertyValueAsString(KFSKeyConstants.OrganizationReversionProcess.FUND_REVERTED_FROM); outputFileName = getBatchFileDirectoryName() + File.separator + (usePriorYearInformation ? GeneralLedgerConstants.BatchFileSystem.ORGANIZATION_REVERSION_CLOSING_FILE : GeneralLedgerConstants.BatchFileSystem.ORGANIZATION_REVERSION_PRE_CLOSING_FILE) + GeneralLedgerConstants.BatchFileSystem.EXTENSION; } /** * This evilly named method actually runs the organization reversion process. */ public void organizationReversionProcess(Map jobParameters, Map<String, Integer> organizationReversionCounts) { if (LOG.isDebugEnabled()) { LOG.debug("organizationReversionProcess() started"); } this.jobParameters = jobParameters; this.organizationReversionCounts = organizationReversionCounts; LOG.info("Initializing the process"); initializeProcess(); //create files File outputFile = new File(outputFileName); try { outputPs = new PrintStream(outputFile); Iterator<Balance> balances = getBalanceService().findOrganizationReversionBalancesForFiscalYear((Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR), usePriorYearInformation); processBalances(balances); outputPs.close(); } catch (FileNotFoundException e) { throw new RuntimeException("Organization Reversion File Files doesn't exist " + outputFileName); } } /** * Given a list of balances, this method generates the origin entries for the organization reversion/carry forward process, and saves those * to an initialized origin entry group * * @param balances an iterator of balances to process; each balance returned by the iterator will be processed by this method */ public void processBalances(Iterator<Balance> balances) { boolean skipToNextUnitOfWork = false; unitOfWork = new OrgReversionUnitOfWork(); unitOfWork.setCategories(categoryList); Balance bal; while (balances.hasNext()) { bal = balances.next(); if (LOG.isDebugEnabled()) { LOG.debug("BALANCE SELECTED: " + bal.getUniversityFiscalYear() + bal.getChartOfAccountsCode() + bal.getAccountNumber() + bal.getSubAccountNumber() + bal.getObjectCode() + bal.getSubObjectCode() + bal.getBalanceTypeCode() + bal.getObjectTypeCode() + " " + bal.getAccountLineAnnualBalanceAmount().add(bal.getBeginningBalanceLineAmount())); } try { if (!unitOfWork.isInitialized()) { unitOfWork.setFields(bal.getChartOfAccountsCode(), bal.getAccountNumber(), bal.getSubAccountNumber()); retrieveCurrentReversionAndAccount(bal); } else if (!unitOfWork.wouldHold(bal)) { if (!skipToNextUnitOfWork) { calculateTotals(); List<OriginEntryFull> originEntriesToWrite = generateOutputOriginEntries(); summarizeOriginEntries(originEntriesToWrite); if (holdGeneratedOriginEntries) { generatedOriginEntries.addAll(originEntriesToWrite); } int recordsWritten = writeOriginEntries(originEntriesToWrite); incrementCount("recordsWritten", recordsWritten); getOrgReversionUnitOfWorkService().save(unitOfWork); } unitOfWork.setFields(bal.getChartOfAccountsCode(), bal.getAccountNumber(), bal.getSubAccountNumber()); retrieveCurrentReversionAndAccount(bal); skipToNextUnitOfWork = false; } if (skipToNextUnitOfWork) { continue; // if there is no org reversion or an org reversion detail is missing or the balances are off for // this unit of work, // just skip all the balances until we change unit of work } calculateBucketAmounts(bal); } catch (FatalErrorException fee) { LOG.info(fee.getMessage()); skipToNextUnitOfWork = true; } } // save the final unit of work if (!skipToNextUnitOfWork && getBalancesSelected() > 0) { try { calculateTotals(); List<OriginEntryFull> originEntriesToWrite = generateOutputOriginEntries(); summarizeOriginEntries(originEntriesToWrite); if (holdGeneratedOriginEntries) { generatedOriginEntries.addAll(originEntriesToWrite); } int recordsWritten = writeOriginEntries(originEntriesToWrite); incrementCount("recordsWritten", recordsWritten); getOrgReversionUnitOfWorkService().save(unitOfWork); } catch (FatalErrorException fee) { LOG.info(fee.getMessage()); } } } /** * Given a balance, returns the current organization reversion record and account or prior year account for the balance; it sets them * to private properties * * @param bal the balance to find the account/prior year account and organization reversion record for * @throws FatalErrorException if an organization reversion record cannot be found in the database */ protected void retrieveCurrentReversionAndAccount(Balance bal) throws FatalErrorException { // initialize the account if ((account == null) || (!bal.getChartOfAccountsCode().equals(account.getChartOfAccountsCode())) || (!bal.getAccountNumber().equals(account.getAccountNumber()))) { if (usePriorYearInformation) { account = getPriorYearAccountService().getByPrimaryKey(bal.getChartOfAccountsCode(), bal.getAccountNumber()); } else { account = bal.getAccount(); } } if (LOG.isDebugEnabled()) { LOG.debug("Organization Reversion Service: " + getOrganizationReversionService() + "; fiscal year: " + (Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR) + "; account: " + account + "; account organization code: " + account.getOrganizationCode() + "; balance: " + bal + "; balance chart: " + bal.getChartOfAccountsCode()); } organizationReversion = getOrganizationReversionService().getByPrimaryId((Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR), bal.getChartOfAccountsCode(), account.getOrganizationCode()); if (organizationReversion == null) { // we can't find an organization reversion for this balance? Throw exception throw new FatalErrorException("No Organization Reversion found for: " + (Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR) + "-" + bal.getChartOfAccountsCode() + "-" + account.getOrganizationCode()); } if (account.isClosed()) { organizationReversion = new ClosedAccountOrganizationReversion(organizationReversion); } } /** * This method initializes several properties needed for the process to run correctly */ public void initializeProcess() { // clear out summary tables LOG.info("destroying all unit of work summaries"); orgReversionUnitOfWorkService.destroyAllUnitOfWorkSummaries(); categories = getOrganizationReversionService().getCategories(); categoryList = getOrganizationReversionService().getCategoryList(); this.paramFiscalYear = (Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR); organizationReversionCounts.put("balancesRead", balanceService.countBalancesForFiscalYear(paramFiscalYear)); organizationReversionCounts.put("balancesSelected", new Integer(0)); organizationReversionCounts.put("recordsWritten", new Integer(0)); this.systemOptions = SpringContext.getBean(OptionsService.class).getOptions(paramFiscalYear); ledgerReport = new LedgerSummaryReport(); } /** * Depending on the category that this balance belongs to, adds the balance to the appropriate bucket * * @param bal the current balance to process */ protected void calculateBucketAmounts(Balance bal) { getPersistenceService().retrieveReferenceObject(bal, "financialObject"); if (LOG.isDebugEnabled()) { LOG.debug("CONSIDERING IF TO ADD BALANCE: " + bal.getUniversityFiscalYear() + bal.getChartOfAccountsCode() + bal.getAccountNumber() + bal.getSubAccountNumber() + bal.getObjectCode() + bal.getSubObjectCode() + bal.getBalanceTypeCode() + bal.getObjectTypeCode() + " " + bal.getAccountLineAnnualBalanceAmount().add(bal.getBeginningBalanceLineAmount())); } if (getCashOrganizationReversionCategoryLogic().containsObjectCode(bal.getFinancialObject()) && bal.getBalanceTypeCode().equals(systemOptions.getActualFinancialBalanceTypeCd())) { unitOfWork.addTotalCash(bal.getBeginningBalanceLineAmount()); unitOfWork.addTotalCash(bal.getAccountLineAnnualBalanceAmount()); incrementCount("balancesSelected"); if (LOG.isDebugEnabled()) { LOG.debug("ADDING BALANCE TO CASH: " + bal.getUniversityFiscalYear() + bal.getChartOfAccountsCode() + bal.getAccountNumber() + bal.getSubAccountNumber() + bal.getObjectCode() + bal.getSubObjectCode() + bal.getBalanceTypeCode() + bal.getObjectTypeCode() + " " + bal.getAccountLineAnnualBalanceAmount().add(bal.getBeginningBalanceLineAmount()) + " TO CASH, TOTAL CASH NOW = " + unitOfWork.getTotalCash()); } } else { for (OrganizationReversionCategory cat : categoryList) { OrganizationReversionCategoryLogic logic = categories.get(cat.getOrganizationReversionCategoryCode()); if (logic.containsObjectCode(bal.getFinancialObject())) { if (systemOptions.getActualFinancialBalanceTypeCd().equals(bal.getBalanceTypeCode())) { // Actual unitOfWork.addActualAmount(cat.getOrganizationReversionCategoryCode(), bal.getBeginningBalanceLineAmount()); unitOfWork.addActualAmount(cat.getOrganizationReversionCategoryCode(), bal.getAccountLineAnnualBalanceAmount()); incrementCount("balancesSelected"); if (LOG.isDebugEnabled()) { LOG.debug("ADDING BALANCE TO ACTUAL: " + bal.getUniversityFiscalYear() + bal.getChartOfAccountsCode() + bal.getAccountNumber() + bal.getSubAccountNumber() + bal.getObjectCode() + bal.getSubObjectCode() + bal.getBalanceTypeCode() + bal.getObjectTypeCode() + " " + bal.getAccountLineAnnualBalanceAmount().add(bal.getBeginningBalanceLineAmount()) + " TO ACTUAL, ACTUAL FOR CATEGORY " + cat.getOrganizationReversionCategoryName() + " NOW = " + unitOfWork.getCategoryAmounts().get(cat.getOrganizationReversionCategoryCode()).getActual()); } } else if (systemOptions.getFinObjTypeExpenditureexpCd().equals(bal.getBalanceTypeCode()) || systemOptions.getCostShareEncumbranceBalanceTypeCd().equals(bal.getBalanceTypeCode()) || systemOptions.getIntrnlEncumFinBalanceTypCd().equals(bal.getBalanceTypeCode())) { // Encumbrance KualiDecimal amount = bal.getBeginningBalanceLineAmount().add(bal.getAccountLineAnnualBalanceAmount()); if (amount.isPositive()) { unitOfWork.addEncumbranceAmount(cat.getOrganizationReversionCategoryCode(), amount); incrementCount("balancesSelected"); if (LOG.isDebugEnabled()) { LOG.debug("ADDING BALANCE TO ENCUMBRANCE: " + bal.getUniversityFiscalYear() + bal.getChartOfAccountsCode() + bal.getAccountNumber() + bal.getSubAccountNumber() + bal.getObjectCode() + bal.getSubObjectCode() + bal.getBalanceTypeCode() + bal.getObjectTypeCode() + " " + bal.getAccountLineAnnualBalanceAmount().add(bal.getBeginningBalanceLineAmount()) + " TO ENCUMBRANCE, ENCUMBRANCE FOR CATEGORY " + cat.getOrganizationReversionCategoryName() + " NOW = " + unitOfWork.getCategoryAmounts().get(cat.getOrganizationReversionCategoryCode()).getEncumbrance()); } } } else if (KFSConstants.BALANCE_TYPE_CURRENT_BUDGET.equals(bal.getBalanceTypeCode())) { // Budget if (!CARRY_FORWARD_OBJECT_CODE.equals(bal.getObjectCode())) { unitOfWork.addBudgetAmount(cat.getOrganizationReversionCategoryCode(), bal.getBeginningBalanceLineAmount()); unitOfWork.addBudgetAmount(cat.getOrganizationReversionCategoryCode(), bal.getAccountLineAnnualBalanceAmount()); incrementCount("balancesSelected"); if (LOG.isDebugEnabled()) { LOG.debug("ADDING BALANCE TO BUDGET: " + bal.getUniversityFiscalYear() + bal.getChartOfAccountsCode() + bal.getAccountNumber() + bal.getSubAccountNumber() + bal.getObjectCode() + bal.getSubObjectCode() + bal.getBalanceTypeCode() + bal.getObjectTypeCode() + " " + bal.getAccountLineAnnualBalanceAmount().add(bal.getBeginningBalanceLineAmount()) + " TO CURRENT BUDGET, CURRENT BUDGET FOR CATEGORY " + cat.getOrganizationReversionCategoryName() + " NOW = " + unitOfWork.getCategoryAmounts().get(cat.getOrganizationReversionCategoryCode()).getBudget()); } } } break; } } } } /** * This method determines which origin entries (reversion, cash reversion, or carry forward) need to be generated for the current unit of work, * and then delegates to the origin entry generation methods to create those entries * * @return a list of OriginEntries which need to be written * @throws FatalErrorException thrown if object codes are missing in any of the generation methods */ public List<OriginEntryFull> generateOutputOriginEntries() throws FatalErrorException { List<OriginEntryFull> originEntriesToWrite = new ArrayList<OriginEntryFull>(); if (unitOfWork.getTotalReversion().compareTo(KualiDecimal.ZERO) != 0) { generateReversions(originEntriesToWrite); } if ((unitOfWork.getTotalCarryForward().compareTo(KualiDecimal.ZERO) != 0)) { if (!organizationReversion.isCarryForwardByObjectCodeIndicator()) { generateCarryForwards(originEntriesToWrite); } else { generateMany(originEntriesToWrite); } } if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) != 0) { generateCashReversions(originEntriesToWrite); } return originEntriesToWrite; } /** * This method writes a list of OriginEntryFulls to a given origin entry group * * @param writeGroup the origin entry group to write to * @param originEntriesToWrite a list of origin entry fulls to write * @return the count of origin entries that were written */ protected int writeOriginEntries(List<OriginEntryFull> originEntriesToWrite) { int originEntriesWritten = 0; for (OriginEntryFull originEntry : originEntriesToWrite) { getOriginEntryService().createEntry(originEntry, outputPs); originEntriesWritten += 1; } return originEntriesWritten; } /** * This method starts the creation of an origin entry, by setting fields that are the same in every Org Rev origin entries * * @return an OriginEntryFull partially filled out with constant information */ protected OriginEntryFull getEntry() { OriginEntryFull entry = new OriginEntryFull(); entry.setUniversityFiscalYear((Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR)); entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH13); entry.setFinancialDocumentTypeCode(DEFAULT_FINANCIAL_DOCUMENT_TYPE_CODE); entry.setFinancialSystemOriginationCode(DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE); entry.setTransactionLedgerEntrySequenceNumber(1); entry.setTransactionDebitCreditCode(KFSConstants.GL_BUDGET_CODE); entry.setTransactionDate((Date) jobParameters.get(KFSConstants.TRANSACTION_DT)); entry.setProjectCode(KFSConstants.getDashProjectCode()); return entry; } /** * This method generates cash reversion origin entries for the current organization reversion, and adds them to the given list * * @param originEntriesToWrite a list of OriginEntryFulls to stick generated origin entries into * @throws FatalErrorException thrown if an origin entry's object code can't be found */ public void generateCashReversions(List<OriginEntryFull> originEntriesToWrite) throws FatalErrorException { int entriesWritten = 0; // Reversion of cash from the actual account in the fiscal year ending (balance type of NB) OriginEntryFull entry = getEntry(); entry.refreshReferenceObject("option"); entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode); entry.setAccountNumber(unitOfWork.accountNumber); entry.setSubAccountNumber(unitOfWork.subAccountNumber); entry.setFinancialObjectCode(organizationReversion.getOrganizationChartCashObjectCode()); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(systemOptions.getNominalFinancialBalanceTypeCd()); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + entry.getAccountNumber()); entry.setTransactionLedgerEntryDescription(CASH_REVERTED_TO_MESSAGE + " " + organizationReversion.getCashReversionAccountNumber()); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCash()); if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) > 0) { entry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } else { entry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCash().negated()); } entry.setFinancialObjectTypeCode(entry.getFinancialObject().getFinancialObjectTypeCode()); // 3468 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 3469 WS-AMT-N. // 3470 MOVE WS-AMT-X TO TRN-AMT-RED-X. originEntriesToWrite.add(entry); // Reversion of fund balance, starting with the actual account, to match the cash that was reverted (balance type of NB) entry = getEntry(); entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode); entry.setAccountNumber(unitOfWork.accountNumber); entry.setSubAccountNumber(unitOfWork.subAccountNumber); entry.setFinancialObjectCode((String) jobParameters.get(KFSConstants.FUND_BAL_OBJECT_CD)); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + unitOfWork.accountNumber); entry.setTransactionLedgerEntryDescription(FUND_BALANCE_REVERTED_TO_MESSAGE + organizationReversion.getCashReversionAccountNumber()); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCash().abs()); if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) > 0) { entry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } else { entry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } entry.setFinancialObjectTypeCode(entry.getFinancialObject().getFinancialObjectTypeCode()); // 3570 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 3571 WS-AMT-N. // 3572 MOVE WS-AMT-X TO TRN-AMT-RED-X. getFlexibleOffsetAccountService().updateOffset(entry); originEntriesToWrite.add(entry); // Reversion of cash to the cash reversion account in the fiscal year ending (balance type of NB) entry = getEntry(); entry.setChartOfAccountsCode(organizationReversion.getCashReversionFinancialChartOfAccountsCode()); entry.setAccountNumber(organizationReversion.getCashReversionAccountNumber()); entry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); entry.setFinancialObjectCode(organizationReversion.getCashReversionChartCashObjectCode()); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + unitOfWork.accountNumber); entry.setTransactionLedgerEntryDescription(CASH_REVERTED_FROM_MESSAGE + unitOfWork.accountNumber + " " + unitOfWork.subAccountNumber); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCash()); if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) > 0) { entry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } else { entry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCash().negated()); } entry.setFinancialObjectTypeCode(entry.getFinancialObject().getFinancialObjectTypeCode()); // 3668 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 3669 WS-AMT-N. // 3670 MOVE WS-AMT-X TO TRN-AMT-RED-X. originEntriesToWrite.add(entry); // Reversion of fund balance, starting with the cash reversion account, to match the cash that was reverted (balance type of NB) entry = getEntry(); entry.setChartOfAccountsCode(organizationReversion.getCashReversionFinancialChartOfAccountsCode()); entry.setAccountNumber(organizationReversion.getCashReversionAccountNumber()); entry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); entry.setFinancialObjectCode((String) jobParameters.get(KFSConstants.FUND_BAL_OBJECT_CD)); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + unitOfWork.accountNumber); entry.setTransactionLedgerEntryDescription(FUND_BALANCE_REVERTED_FROM_MESSAGE + unitOfWork.accountNumber + " " + unitOfWork.subAccountNumber); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCash()); if (unitOfWork.getTotalCash().compareTo(KualiDecimal.ZERO) > 0) { entry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } else { entry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCash().negated()); } entry.setFinancialObjectTypeCode(entry.getFinancialObject().getFinancialObjectTypeCode()); // 3768 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 3769 WS-AMT-N. // 3770 MOVE WS-AMT-X TO TRN-AMT-RED-X. getFlexibleOffsetAccountService().updateOffset(entry); originEntriesToWrite.add(entry); } /** * Generates carry forward origin entries on a category by category basis (if the organization reversion record asks for that), assuming carry * forwards are required for the current unit of work * * @param originEntriesToWrite a list of origin entries to write, which any generated origin entries should be added to * @throws FatalErrorException thrown if an object code cannot be found */ public void generateMany(List<OriginEntryFull> originEntriesToWrite) throws FatalErrorException { int originEntriesCreated = 0; for (Iterator<OrganizationReversionCategory> iter = categoryList.iterator(); iter.hasNext();) { OrganizationReversionCategory cat = iter.next(); OrganizationReversionCategoryInfo detail = organizationReversion.getOrganizationReversionDetail(cat.getOrganizationReversionCategoryCode()); OrgReversionUnitOfWorkCategoryAmount amount = unitOfWork.amounts.get(cat.getOrganizationReversionCategoryCode()); if (!amount.getCarryForward().isZero()) { KualiDecimal commonAmount = amount.getCarryForward(); String commonObject = detail.getOrganizationReversionObjectCode(); OriginEntryFull entry = getEntry(); entry.setUniversityFiscalYear((Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR) + 1); entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode); entry.setAccountNumber(unitOfWork.accountNumber); entry.setSubAccountNumber(unitOfWork.subAccountNumber); entry.setFinancialObjectCode((String) jobParameters.get(KFSConstants.BEG_BUD_CASH_OBJECT_CD)); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } ObjectCode objectCode = entry.getFinancialObject(); entry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode()); entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH1); entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + unitOfWork.accountNumber); entry.setTransactionLedgerEntryDescription(FUND_CARRIED_MESSAGE + (Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR)); entry.setTransactionLedgerEntryAmount(commonAmount); // 3259 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 3260 WS-AMT-N. // 3261 MOVE WS-AMT-X TO TRN-AMT-RED-X. originEntriesToWrite.add(entry); entry = getEntry(); entry.setUniversityFiscalYear((Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR) + 1); entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode); entry.setAccountNumber(unitOfWork.accountNumber); entry.setSubAccountNumber(unitOfWork.subAccountNumber); entry.setFinancialObjectCode(commonObject); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } objectCode = entry.getFinancialObject(); entry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode()); entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH1); entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + unitOfWork.accountNumber); entry.setTransactionLedgerEntryDescription(FUND_CARRIED_MESSAGE + (Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR)); entry.setTransactionLedgerEntryAmount(commonAmount); // 3343 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 3344 WS-AMT-N. // 3345 MOVE WS-AMT-X TO TRN-AMT-RED-X. originEntriesToWrite.add(entry); } } } /** * If carry forwards need to be generated for this unit of work, this method will generate the origin entries to accomplish those object codes. * Note: this will only be called if the organization reversion record tells the process to munge all carry forwards for all categories * together; if the organization reversion record does not call for such a thing, then generateMany will be called * * @param originEntriesToWrite a list of origin entries to write, that any generated origin entries should be added to * @throws FatalErrorException thrown if the current object code can't be found in the database */ public void generateCarryForwards(List<OriginEntryFull> originEntriesToWrite) throws FatalErrorException { int originEntriesWritten = 0; OriginEntryFull entry = getEntry(); entry.setUniversityFiscalYear((Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR) + 1); entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode); entry.setAccountNumber(unitOfWork.accountNumber); entry.setSubAccountNumber(unitOfWork.subAccountNumber); entry.setFinancialObjectCode((String) jobParameters.get(KFSConstants.BEG_BUD_CASH_OBJECT_CD)); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } ObjectCode objectCode = entry.getFinancialObject(); entry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode()); entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH1); entry.setFinancialDocumentTypeCode(DEFAULT_FINANCIAL_DOCUMENT_TYPE_CODE); entry.setFinancialSystemOriginationCode(DEFAULT_FINANCIAL_SYSTEM_ORIGINATION_CODE); entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + unitOfWork.accountNumber); entry.setTransactionLedgerEntrySequenceNumber(1); entry.setTransactionLedgerEntryDescription(FUND_CARRIED_MESSAGE + (Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR)); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCarryForward()); entry.setTransactionDate((Date) jobParameters.get(KFSConstants.TRANSACTION_DT)); entry.setProjectCode(KFSConstants.getDashProjectCode()); // 2995 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 2996 WS-AMT-N. // 2997 MOVE WS-AMT-X TO TRN-AMT-RED-X. originEntriesToWrite.add(entry); entry = getEntry(); entry.setUniversityFiscalYear((Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR) + 1); entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode); entry.setAccountNumber(unitOfWork.accountNumber); entry.setSubAccountNumber(unitOfWork.subAccountNumber); entry.setFinancialObjectCode((String) jobParameters.get(KFSConstants.UNALLOC_OBJECT_CD)); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } objectCode = entry.getFinancialObject(); entry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode()); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET); entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH1); entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + unitOfWork.accountNumber); entry.setTransactionLedgerEntryDescription(FUND_CARRIED_MESSAGE + (Integer) jobParameters.get(KFSConstants.UNIV_FISCAL_YR)); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalCarryForward()); // 3079 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 3080 WS-AMT-N. // 3081 MOVE WS-AMT-X TO TRN-AMT-RED-X. originEntriesToWrite.add(entry); } /** * If reversions are necessary, this will generate the origin entries for those reversions * * @param originEntriesToWrite the list of origin entries to add reversions into * @throws FatalErrorException thrown if object code if the entry can't be found */ public void generateReversions(List<OriginEntryFull> originEntriesToWrite) throws FatalErrorException { int originEntriesWritten = 0; OriginEntryFull entry = getEntry(); entry.setChartOfAccountsCode(unitOfWork.chartOfAccountsCode); entry.setAccountNumber(unitOfWork.accountNumber); entry.setSubAccountNumber(unitOfWork.subAccountNumber); entry.setFinancialObjectCode((String) jobParameters.get(KFSConstants.UNALLOC_OBJECT_CD)); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END); getPersistenceService().retrieveReferenceObject(entry, KFSPropertyConstants.FINANCIAL_OBJECT); if (ObjectUtils.isNull(entry.getFinancialObject())) { throw new FatalErrorException("Object Code for Entry not found: " + entry); } ObjectCode objectCode = entry.getFinancialObject(); entry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode()); entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH13); entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + entry.getAccountNumber()); entry.setTransactionLedgerEntryDescription(FUND_REVERTED_TO_MESSAGE + organizationReversion.getBudgetReversionAccountNumber()); entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalReversion().negated()); originEntriesToWrite.add(entry); entry = getEntry(); entry.setChartOfAccountsCode(organizationReversion.getBudgetReversionChartOfAccountsCode()); entry.setAccountNumber(organizationReversion.getBudgetReversionAccountNumber()); entry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); entry.setFinancialObjectCode((String) jobParameters.get(KFSConstants.UNALLOC_OBJECT_CD)); entry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); entry.setFinancialBalanceTypeCode(DEFAULT_FINANCIAL_BALANCE_TYPE_CODE_YEAR_END); entry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode()); entry.setUniversityFiscalPeriodCode(KFSConstants.MONTH13); entry.setDocumentNumber(DEFAULT_DOCUMENT_NUMBER_PREFIX + unitOfWork.accountNumber); if (unitOfWork.accountNumber.equals(KFSConstants.getDashSubAccountNumber())) { entry.setTransactionLedgerEntryDescription(FUND_REVERTED_FROM_MESSAGE + unitOfWork.accountNumber); } else { entry.setTransactionLedgerEntryDescription(FUND_REVERTED_FROM_MESSAGE + unitOfWork.accountNumber + " " + unitOfWork.subAccountNumber); } entry.setTransactionLedgerEntryAmount(unitOfWork.getTotalReversion()); // 2899 MOVE TRN-LDGR-ENTR-AMT TO WS-AMT-W-PERIOD // 2900 WS-AMT-N. // 2901 MOVE WS-AMT-X TO TRN-AMT-RED-X. originEntriesToWrite.add(entry); } /** * This method calculates the totals for a given unit of work's reversion * * @throws FatalErrorException */ public void calculateTotals() throws FatalErrorException { /* * How this works: At the start, in the clearCalculationTotals(), both the unit of work's totalAvailable and totalReversion * are set to the available amounts from each of the category amounts. Then, as the logic is applied, the totalCarryForward * 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 * C01, which has $2000 available, no encumbrances, that's all you've got. This means that at the end of * clearCalculationTotals(), there's $2000 in totalAvailable, $2000 in totalReversion, and $0 in totalCarryForward. Now, C01, * 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 * totalCarryForward, it's own carryForward, the negated available to totalReversion, and that, done, it sets available to * $0. With our example, that means that $2000 is in totalCarryForward (and in the amount's carryForward), the * totalReversion has been knocked down to $0, and the available is $0. So, carry forward origin entries get created, and * reversions do not. This is also why you don't see a block about calculating R2 totals below...the process has a natural * inclination towards creating R2 (ie, ignore encumbrances and revert all available) entries. */ // clear out the unit of work totals we're going to calculate values in, in preperation for applying rules clearCalculationTotals(); // For each category, apply the rules for (OrganizationReversionCategory category : categoryList) { String categoryCode = category.getOrganizationReversionCategoryCode(); OrganizationReversionCategoryLogic logic = categories.get(categoryCode); OrgReversionUnitOfWorkCategoryAmount amount = unitOfWork.amounts.get(categoryCode); OrganizationReversionCategoryInfo detail = organizationReversion.getOrganizationReversionDetail(categoryCode); if (detail == null) { throw new FatalErrorException("Organization Reversion " + organizationReversion.getUniversityFiscalYear() + "-" + organizationReversion.getChartOfAccountsCode() + "-" + organizationReversion.getOrganizationCode() + " does not have a detail for category " + categoryCode); } String ruleCode = detail.getOrganizationReversionCode(); if (LOG.isDebugEnabled()) { LOG.debug("Unit of Work: " + unitOfWork.getChartOfAccountsCode() + unitOfWork.getAccountNumber() + unitOfWork.getSubAccountNumber() + ", category " + category.getOrganizationReversionCategoryName() + ": budget = " + amount.getBudget() + "; actual = " + amount.getActual() + "; encumbrance = " + amount.getEncumbrance() + "; available = " + amount.getAvailable() + "; apply rule code " + ruleCode); } if (KFSConstants.RULE_CODE_R1.equals(ruleCode) || KFSConstants.RULE_CODE_N1.equals(ruleCode) || KFSConstants.RULE_CODE_C1.equals(ruleCode)) { if (amount.getAvailable().compareTo(KualiDecimal.ZERO) > 0) { // do we have budget left? if (amount.getAvailable().compareTo(amount.getEncumbrance()) > 0) { // is it more than enough to cover our // encumbrances? unitOfWork.addTotalCarryForward(amount.getEncumbrance()); amount.addCarryForward(amount.getEncumbrance()); unitOfWork.addTotalReversion(amount.getEncumbrance().negated()); amount.addAvailable(amount.getEncumbrance().negated()); } else { // there's not enough available left to cover the encumbrances; cover what we can unitOfWork.addTotalCarryForward(amount.getAvailable()); amount.addCarryForward(amount.getAvailable()); unitOfWork.addTotalReversion(amount.getAvailable().negated()); amount.setAvailable(KualiDecimal.ZERO); } } } if (KFSConstants.RULE_CODE_A.equals(ruleCode)) { unitOfWork.addTotalCarryForward(amount.getAvailable()); amount.addCarryForward(amount.getAvailable()); unitOfWork.addTotalReversion(amount.getAvailable().negated()); amount.setAvailable(KualiDecimal.ZERO); } if (KFSConstants.RULE_CODE_C1.equals(ruleCode) || KFSConstants.RULE_CODE_C2.equals(ruleCode)) { if (amount.getAvailable().compareTo(KualiDecimal.ZERO) > 0) { unitOfWork.addTotalCarryForward(amount.getAvailable()); amount.addCarryForward(amount.getAvailable()); unitOfWork.addTotalReversion(amount.getAvailable().negated()); amount.setAvailable(KualiDecimal.ZERO); } } if (KFSConstants.RULE_CODE_N1.equals(ruleCode) || KFSConstants.RULE_CODE_N2.equals(ruleCode)) { if (amount.getAvailable().compareTo(KualiDecimal.ZERO) < 0) { unitOfWork.addTotalCarryForward(amount.getAvailable()); amount.addCarryForward(amount.getAvailable()); unitOfWork.addTotalReversion(amount.getAvailable().negated()); amount.setAvailable(KualiDecimal.ZERO); } } if (LOG.isDebugEnabled()) { LOG.debug("Totals Now: " + unitOfWork.getChartOfAccountsCode() + unitOfWork.getAccountNumber() + unitOfWork.getSubAccountNumber() + ", total cash now " + unitOfWork.getTotalCash() + ": total available = " + unitOfWork.getTotalAvailable() + "; total reversion = " + unitOfWork.getTotalReversion() + "; total carry forward = " + unitOfWork.getTotalCarryForward()); } } } /** * This method clears the unit of work's amounts to what they should be before each category bucket is calculated; specifically, * the total available for each category is calculated, and the total available and total reversion are set to the sum of all * available from each category bucket. The total carry forward is set to 0. */ protected void clearCalculationTotals() { // Initialize all the amounts before applying the proper rule KualiDecimal totalAvailable = KualiDecimal.ZERO; for (OrganizationReversionCategory category : categoryList) { OrganizationReversionCategoryLogic logic = categories.get(category.getOrganizationReversionCategoryCode()); OrgReversionUnitOfWorkCategoryAmount amount = unitOfWork.amounts.get(category.getOrganizationReversionCategoryCode()); if (logic.isExpense()) { amount.setAvailable(amount.getBudget().subtract(amount.getActual())); } else { amount.setAvailable(amount.getActual().subtract(amount.getBudget())); } totalAvailable = totalAvailable.add(amount.getAvailable()); amount.setCarryForward(KualiDecimal.ZERO); } unitOfWork.setTotalAvailable(totalAvailable); unitOfWork.setTotalReversion(totalAvailable); unitOfWork.setTotalCarryForward(KualiDecimal.ZERO); } /** * Summarizes the given origin entries to the ledger report * @param originEntries the List of originEntries to summarize */ protected void summarizeOriginEntries(List<OriginEntryFull> originEntries) { for (OriginEntryFull originEntry: originEntries) { ledgerReport.summarizeEntry(originEntry); } } public OrgReversionUnitOfWork getUnitOfWork() { return unitOfWork; } public void setUnitOfWork(OrgReversionUnitOfWork unitOfWork) { this.unitOfWork = unitOfWork; } public List<OrganizationReversionCategory> getCategoryList() { return this.categoryList; } /** * Gets the generatedOriginEntries attribute. * * @return Returns the generatedOriginEntries. */ public List<OriginEntryFull> getGeneratedOriginEntries() { return generatedOriginEntries; } /** * Sets the holdGeneratedOriginEntries attribute value. * * @param holdGeneratedOriginEntries The holdGeneratedOriginEntries to set. */ public void setHoldGeneratedOriginEntries(boolean holdGeneratedOriginEntries) { this.holdGeneratedOriginEntries = holdGeneratedOriginEntries; this.generatedOriginEntries = new ArrayList<OriginEntryFull>(); } /** * Returns the total number of balances for the previous fiscal year * * @return the total number of balances for the previous fiscal year */ public int getBalancesRead() { return organizationReversionCounts.get("balancesRead").intValue(); } /** * Returns the total number of balances selected for inclusion in this process * * @return the total number of balances selected for inclusion in this process */ public int getBalancesSelected() { return organizationReversionCounts.get("balancesSelected").intValue(); } /** * Returns the total number of origin entries written by this process * * @return the total number of origin entries written by this process */ public int getRecordsWritten() { return organizationReversionCounts.get("recordsWritten").intValue(); } /** * Used mainly for unit testing, this method allows a way to change the output group of a org reversion process run * * @param outputGroup */ public void setOutputFileName(String outputFileName) { this.outputFileName = outputFileName; } /** * Increments one of the totals held in the count map this process uses for reported statistics * * @param countName the name of the count to increment */ private void incrementCount(String countName) { incrementCount(countName, 1); } /** * Increments one of the totals held in the count map this process uses for reported statistics by a given increment * * @param countName the name of the count to increment * @param increment the amount to increment */ protected void incrementCount(String countName, int increment) { Integer count = organizationReversionCounts.get(countName); if (countName.equals("recordsWritten")) { int countAsInt = count.intValue(); // add by 1, so we're guaranteed to hit the 1000th for (int i = 1; i <= increment; i++) { countAsInt += 1; if (countAsInt % 1000 == 0) { LOG.info(" ORIGIN ENTRIES INSERTED = "+countAsInt); } else if (countAsInt == 367471) { LOG.info(" YOU HAVE ACHIEVED 367471 ORIGIN ENTRIES INSERTED! TRIUMPH IS YOURS! "); } } organizationReversionCounts.put(countName, new Integer(countAsInt)); } else { organizationReversionCounts.put(countName, new Integer(count.intValue() + increment)); } } /** * Writes out the encapsulated origin entry ledger report to the given reportWriterService * @param reportWriterService the report to write the ledger summary report to */ public void writeLedgerSummaryReport(ReportWriterService reportWriterService) { ledgerReport.writeReport(reportWriterService); } /** * Gets the organizationReversionService attribute. * @return Returns the organizationReversionService. */ public OrganizationReversionService getOrganizationReversionService() { return organizationReversionService; } /** * Sets the organizationReversionService attribute value. * @param organizationReversionService The organizationReversionService to set. */ public void setOrganizationReversionService(OrganizationReversionService organizationReversionService) { this.organizationReversionService = organizationReversionService; } /** * Gets the balanceService attribute. * @return Returns the balanceService. */ public BalanceService getBalanceService() { return balanceService; } /** * Sets the balanceService attribute value. * @param balanceService The balanceService to set. */ public void setBalanceService(BalanceService balanceService) { this.balanceService = balanceService; } /** * Gets the originEntryService attribute. * @return Returns the originEntryService. */ public OriginEntryService getOriginEntryService() { return originEntryService; } /** * Sets the originEntryService attribute value. * @param originEntryService The originEntryService to set. */ public void setOriginEntryService(OriginEntryService originEntryService) { this.originEntryService = originEntryService; } /** * Gets the persistenceService attribute. * @return Returns the persistenceService. */ public PersistenceService getPersistenceService() { return persistenceService; } /** * Sets the persistenceService attribute value. * @param persistenceService The persistenceService to set. */ public void setPersistenceService(PersistenceService persistenceService) { this.persistenceService = persistenceService; } /** * Gets the dateTimeService attribute. * @return Returns the dateTimeService. */ public DateTimeService getDateTimeService() { return dateTimeService; } /** * Sets the dateTimeService attribute value. * @param dateTimeService The dateTimeService to set. */ public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } /** * Gets the priorYearAccountService attribute. * @return Returns the priorYearAccountService. */ public PriorYearAccountService getPriorYearAccountService() { return priorYearAccountService; } /** * Sets the priorYearAccountService attribute value. * @param priorYearAccountService The priorYearAccountService to set. */ public void setPriorYearAccountService(PriorYearAccountService priorYearAccountService) { this.priorYearAccountService = priorYearAccountService; } /** * Gets the orgReversionUnitOfWorkService attribute. * @return Returns the orgReversionUnitOfWorkService. */ public OrganizationReversionUnitOfWorkService getOrgReversionUnitOfWorkService() { return orgReversionUnitOfWorkService; } /** * Sets the orgReversionUnitOfWorkService attribute value. * @param orgReversionUnitOfWorkService The orgReversionUnitOfWorkService to set. */ public void setOrgReversionUnitOfWorkService(OrganizationReversionUnitOfWorkService orgReversionUnitOfWorkService) { this.orgReversionUnitOfWorkService = orgReversionUnitOfWorkService; } /** * Gets the flexibleOffsetAccountService attribute. * @return Returns the flexibleOffsetAccountService. */ public FlexibleOffsetAccountService getFlexibleOffsetAccountService() { return flexibleOffsetAccountService; } /** * Sets the flexibleOffsetAccountService attribute value. * @param flexibleOffsetAccountService The flexibleOffsetAccountService to set. */ public void setFlexibleOffsetAccountService(FlexibleOffsetAccountService flexibleOffsetAccountService) { this.flexibleOffsetAccountService = flexibleOffsetAccountService; } /** * Gets the parameterService attribute. * @return Returns the parameterService. */ public ParameterService getParameterService() { return parameterService; } /** * Sets the parameterService attribute value. * @param parameterService The parameterService to set. */ public void setParameterService(ParameterService parameterService) { this.parameterService = parameterService; } /** * Gets the configurationService attribute. * @return Returns the configurationService. */ public ConfigurationService getConfigurationService() { return configurationService; } /** * Sets the configurationService attribute value. * @param configurationService The configurationService to set. */ public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } /** * Gets the usePriorYearInformation attribute. * @return Returns the usePriorYearInformation. */ public boolean isUsePriorYearInformation() { return usePriorYearInformation; } /** * Sets the usePriorYearInformation attribute value. * @param usePriorYearInformation The usePriorYearInformation to set. */ public void setUsePriorYearInformation(boolean endOfYear) { this.usePriorYearInformation = endOfYear; } /** * Gets the cashOrganizationReversionCategoryLogic attribute. * @return Returns the cashOrganizationReversionCategoryLogic. */ public OrganizationReversionCategoryLogic getCashOrganizationReversionCategoryLogic() { return cashOrganizationReversionCategoryLogic; } /** * Sets the cashOrganizationReversionCategoryLogic attribute value. * @param cashOrganizationReversionCategoryLogic The cashOrganizationReversionCategoryLogic to set. */ public void setCashOrganizationReversionCategoryLogic(OrganizationReversionCategoryLogic cashOrganizationReversionCategoryLogic) { this.cashOrganizationReversionCategoryLogic = cashOrganizationReversionCategoryLogic; } /** * Gets the batchFileDirectoryName attribute. * @return Returns the batchFileDirectoryName. */ public String getBatchFileDirectoryName() { return batchFileDirectoryName; } /** * Sets the batchFileDirectoryName attribute value. * @param batchFileDirectoryName The batchFileDirectoryName to set. */ public void setBatchFileDirectoryName(String batchFileDirectoryName) { this.batchFileDirectoryName = batchFileDirectoryName; } /** * Sets the jobParameters attribute value. * @param jobParameters The jobParameters to set. */ public void setJobParameters(Map jobParameters) { this.jobParameters = jobParameters; } /** * Sets the organizationReversionCounts attribute value. * @param organizationReversionCounts The organizationReversionCounts to set. */ public void setOrganizationReversionCounts(Map<String, Integer> organizationReversionCounts) { this.organizationReversionCounts = organizationReversionCounts; } }