/* * 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.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.sql.Date; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.io.FileUtils; import org.apache.commons.io.LineIterator; import org.kuali.kfs.coa.businessobject.A21SubAccount; import org.kuali.kfs.coa.businessobject.Account; import org.kuali.kfs.coa.businessobject.BalanceType; import org.kuali.kfs.coa.businessobject.Chart; import org.kuali.kfs.coa.businessobject.ObjectCode; import org.kuali.kfs.coa.businessobject.OffsetDefinition; import org.kuali.kfs.gl.GeneralLedgerConstants; import org.kuali.kfs.gl.ObjectHelper; import org.kuali.kfs.gl.batch.BatchSortUtil; import org.kuali.kfs.gl.batch.CollectorBatch; import org.kuali.kfs.gl.batch.DemergerSortComparator; import org.kuali.kfs.gl.batch.ScrubberSortComparator; import org.kuali.kfs.gl.batch.ScrubberStep; import org.kuali.kfs.gl.batch.service.AccountingCycleCachingService; import org.kuali.kfs.gl.batch.service.RunDateService; import org.kuali.kfs.gl.batch.service.ScrubberProcess; import org.kuali.kfs.gl.batch.service.impl.FilteringOriginEntryFileIterator.OriginEntryFilter; import org.kuali.kfs.gl.businessobject.DemergerReportData; import org.kuali.kfs.gl.businessobject.OriginEntryFieldUtil; import org.kuali.kfs.gl.businessobject.OriginEntryFull; import org.kuali.kfs.gl.businessobject.OriginEntryInformation; import org.kuali.kfs.gl.businessobject.Transaction; import org.kuali.kfs.gl.report.CollectorReportData; import org.kuali.kfs.gl.report.LedgerSummaryReport; import org.kuali.kfs.gl.report.PreScrubberReport; import org.kuali.kfs.gl.report.PreScrubberReportData; import org.kuali.kfs.gl.report.TransactionListingReport; import org.kuali.kfs.gl.service.PreScrubberService; import org.kuali.kfs.gl.service.ScrubberReportData; import org.kuali.kfs.gl.service.ScrubberValidator; import org.kuali.kfs.gl.service.impl.ScrubberStatus; import org.kuali.kfs.gl.service.impl.StringHelper; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSParameterKeyConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.Message; import org.kuali.kfs.sys.KFSParameterKeyConstants.GlParameterConstants; import org.kuali.kfs.sys.batch.service.WrappingBatchService; import org.kuali.kfs.sys.businessobject.SystemOptions; import org.kuali.kfs.sys.businessobject.UniversityDate; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.exception.InvalidFlexibleOffsetException; import org.kuali.kfs.sys.service.DocumentNumberAwareReportWriterService; import org.kuali.kfs.sys.service.FlexibleOffsetAccountService; import org.kuali.kfs.sys.service.ReportWriterService; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.parameter.ParameterEvaluator; import org.kuali.rice.core.api.parameter.ParameterEvaluatorService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.PersistenceService; import org.kuali.rice.krad.util.ObjectUtils; import org.springframework.util.StringUtils; /** * This class has the logic for the scrubber. It is required because the scrubber process needs instance variables. Instance * variables in a spring service are shared between all code calling the service. This will make sure each run of the scrubber has * it's own instance variables instead of being shared. */ public class ScrubberProcessImpl implements ScrubberProcess { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ScrubberProcessImpl.class); protected static final String TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE = "CE"; protected static final String TRANSACTION_TYPE_OFFSET = "O"; protected static final String TRANSACTION_TYPE_CAPITALIZATION = "C"; protected static final String TRANSACTION_TYPE_LIABILITY = "L"; protected static final String TRANSACTION_TYPE_TRANSFER = "T"; protected static final String TRANSACTION_TYPE_COST_SHARE = "CS"; protected static final String TRANSACTION_TYPE_OTHER = "X"; enum GROUP_TYPE {VALID, ERROR, EXPIRED} protected static final String COST_SHARE_CODE = "CSHR"; protected static final String COST_SHARE_TRANSFER_ENTRY_IND = "***"; // These lengths are different then database field lengths, hence they are not from the DD protected static final int COST_SHARE_ENCUMBRANCE_ENTRY_MAXLENGTH = 28; protected static final int DEMERGER_TRANSACTION_LEDGET_ENTRY_DESCRIPTION = 33; protected static final int OFFSET_MESSAGE_MAXLENGTH = 33; /* Services required */ protected FlexibleOffsetAccountService flexibleOffsetAccountService; protected DateTimeService dateTimeService; protected ConfigurationService configurationService; protected PersistenceService persistenceService; protected ScrubberValidator scrubberValidator; protected RunDateService runDateService; protected AccountingCycleCachingService accountingCycleCachingService; protected DocumentNumberAwareReportWriterService scrubberReportWriterService; protected DocumentNumberAwareReportWriterService scrubberLedgerReportWriterService; protected DocumentNumberAwareReportWriterService scrubberListingReportWriterService; protected DocumentNumberAwareReportWriterService preScrubberReportWriterService; protected ReportWriterService scrubberBadBalanceListingReportWriterService; protected ReportWriterService demergerRemovedTransactionsListingReportWriterService; protected ReportWriterService demergerReportWriterService; protected PreScrubberService preScrubberService; // these three members will only be populated when in collector mode, otherwise the memory requirements will be huge protected Map<OriginEntryInformation, OriginEntryInformation> unscrubbedToScrubbedEntries = new HashMap<OriginEntryInformation, OriginEntryInformation>(); protected Map<Transaction, List<Message>> scrubberReportErrors = new IdentityHashMap<Transaction, List<Message>>(); protected LedgerSummaryReport ledgerSummaryReport = new LedgerSummaryReport(); protected ScrubberReportData scrubberReport; protected DemergerReportData demergerReport; /* These are all different forms of the run date for this job */ protected Date runDate; protected Calendar runCal; protected UniversityDate universityRunDate; protected String offsetString; /* Unit Of Work info */ protected UnitOfWorkInfo unitOfWork; protected KualiDecimal scrubCostShareAmount; /* Statistics for the reports */ protected List<Message> transactionErrors; /* Description names */ protected String offsetDescription; protected String capitalizationDescription; protected String liabilityDescription; protected String transferDescription; protected String costShareDescription; protected ParameterService parameterService; protected BusinessObjectService businessObjectService; /** * Whether this instance is being used to support the scrubbing of a collector batch */ protected boolean collectorMode; protected String batchFileDirectoryName; protected PrintStream OUTPUT_GLE_FILE_ps; protected PrintStream OUTPUT_ERR_FILE_ps; protected PrintStream OUTPUT_EXP_FILE_ps; protected String inputFile; protected String validFile; protected String errorFile; protected String expiredFile; /** * Scrub this single group read only. This will only output the scrubber report. It won't output any other groups. * * @param group the origin entry group that should be scrubbed * @param the document number of any specific entries to scrub */ @Override public void scrubGroupReportOnly(String fileName, String documentNumber) { LOG.debug("scrubGroupReportOnly() started"); String unsortedFile = fileName; this.inputFile = fileName + ".sort"; this.validFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.errorFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.expiredFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_EXPIRED_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; String prescrubOutput = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.PRE_SCRUBBER_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.ledgerSummaryReport = new LedgerSummaryReport(); runDate = calculateRunDate(dateTimeService.getCurrentDate()); PreScrubberReportData preScrubberReportData = null; // run pre-scrubber on the raw input into the sort process LineIterator inputEntries = null; try { inputEntries = FileUtils.lineIterator(new File(unsortedFile)); preScrubberReportData = preScrubberService.preprocessOriginEntries(inputEntries, prescrubOutput); } catch (IOException e1) { LOG.error("Error encountered trying to prescrub GLCP/LLCP document", e1); throw new RuntimeException("Error encountered trying to prescrub GLCP/LLCP document", e1); } finally { LineIterator.closeQuietly(inputEntries); } if (preScrubberReportData != null) { preScrubberReportWriterService.setDocumentNumber(documentNumber); ((WrappingBatchService)preScrubberReportWriterService).initialize(); try { new PreScrubberReport().generateReport(preScrubberReportData, preScrubberReportWriterService); } finally { ((WrappingBatchService)preScrubberReportWriterService).destroy(); } } BatchSortUtil.sortTextFileWithFields(prescrubOutput, inputFile, new ScrubberSortComparator()); scrubEntries(true, documentNumber); // delete files File deleteSortFile = new File(inputFile); File deleteValidFile = new File(validFile); File deleteErrorFile = new File(errorFile); File deleteExpiredFile = new File(expiredFile); try { deleteSortFile.delete(); deleteValidFile.delete(); deleteErrorFile.delete(); deleteExpiredFile.delete(); } catch (Exception e){ LOG.error("scrubGroupReportOnly delete output files process Stopped: " + e.getMessage()); throw new RuntimeException("scrubGroupReportOnly delete output files process Stopped: " + e.getMessage(), e); } } /** * Scrubs all entries in all groups and documents. */ @Override public void scrubEntries() { this.inputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.validFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.errorFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.expiredFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_EXPIRED_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; runDate = calculateRunDate(dateTimeService.getCurrentDate()); scrubEntries(false, null); } /** * Scrubs the origin entry and ID billing details if the given batch. Store all scrubber output into the collectorReportData * parameter. NOTE: DO NOT CALL ANY OF THE scrub* METHODS OF THIS CLASS AFTER CALLING THIS METHOD FOR EVERY UNIQUE INSTANCE OF * THIS CLASS, OR THE COLLECTOR REPORTS MAY BE CORRUPTED * * @param batch the data gathered from a Collector file * @param collectorReportData the statistics generated by running the Collector */ @Override public void scrubCollectorBatch(ScrubberStatus scrubberStatus, CollectorBatch batch, CollectorReportData collectorReportData) { collectorMode = true; this.inputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.validFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.errorFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; this.expiredFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_EXPIRED_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; runDate = calculateRunDate(dateTimeService.getCurrentDate()); this.ledgerSummaryReport = collectorReportData.getLedgerSummaryReport(); // sort input file String scrubberSortInputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_BACKUP_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; String scrubberSortOutputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; BatchSortUtil.sortTextFileWithFields(scrubberSortInputFile, scrubberSortOutputFile, new ScrubberSortComparator()); scrubEntries(false, null); //sort scrubber error file for demerger String demergerSortInputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; String demergerSortOutputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_ERROR_SORTED_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; BatchSortUtil.sortTextFileWithFields(demergerSortInputFile, demergerSortOutputFile, new DemergerSortComparator()); performDemerger(); // the scrubber process has just updated several member variables of this class. Store these values for the collector report collectorReportData.setBatchOriginEntryScrubberErrors(batch, scrubberReportErrors); collectorReportData.setScrubberReportData(batch, scrubberReport); collectorReportData.setDemergerReportData(batch, demergerReport); // report purpose - commented out. If we need, the put string values for fileNames. scrubberStatus.setInputFileName(GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION); scrubberStatus.setValidFileName(GeneralLedgerConstants.BatchFileSystem.COLLECTOR_DEMERGER_VAILD_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION); scrubberStatus.setErrorFileName(GeneralLedgerConstants.BatchFileSystem.COLLECTOR_DEMERGER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION); scrubberStatus.setExpiredFileName(GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_EXPIRED_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION); scrubberStatus.setUnscrubbedToScrubbedEntries(unscrubbedToScrubbedEntries); } /** * Scrub all entries that need it in origin entry. Put valid scrubbed entries in a scrubber valid group, put errors in a * scrubber error group, and transactions with an expired account in the scrubber expired account group. * @param group the specific origin entry group to scrub * @param documentNumber the number of the document with entries to scrub */ @Override public void scrubEntries(boolean reportOnlyMode, String documentNumber) { LOG.debug("scrubEntries() started"); if (reportOnlyMode) { scrubberReportWriterService.setDocumentNumber(documentNumber); scrubberLedgerReportWriterService.setDocumentNumber(documentNumber); } // setup an object to hold the "default" date information runDate = calculateRunDate(dateTimeService.getCurrentDate()); runCal = Calendar.getInstance(); runCal.setTime(runDate); universityRunDate = accountingCycleCachingService.getUniversityDate(runDate); if (universityRunDate == null) { throw new IllegalStateException(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_UNIV_DATE_NOT_FOUND)); } setOffsetString(); setDescriptions(); scrubberReport = new ScrubberReportData(); try { if (!collectorMode) { ((WrappingBatchService) scrubberReportWriterService).initialize(); ((WrappingBatchService) scrubberLedgerReportWriterService).initialize(); } processGroup(reportOnlyMode, scrubberReport); /* temp log for debugging output file delay issue if (new File(validFile).canRead()) { LOG.info("Valid file " + validFile + " is ready for read."); } else { LOG.error("Valid file " + validFile + " is not readable."); } if (new File(errorFile).canRead()) { LOG.info("Error file " + errorFile + " is ready for read."); } else { LOG.error("Error file " + errorFile + " is not readable."); } if (new File(expiredFile).canRead()) { LOG.info("Expired file " + expiredFile + " is ready for read."); } else { LOG.error("Expired file " + expiredFile + " is not readable."); } */ if (reportOnlyMode) { generateScrubberTransactionListingReport(documentNumber, inputFile); } else if (collectorMode) { // defer report generation for later } else { generateScrubberBlankBalanceTypeCodeReport(inputFile); } } finally { if (!collectorMode) { ((WrappingBatchService) scrubberReportWriterService).destroy(); ((WrappingBatchService) scrubberLedgerReportWriterService).destroy(); } } } /** * The demerger process reads all of the documents in the error group, then moves all of the original entries for that document * from the valid group to the error group. It does not move generated entries to the error group. Those are deleted. It also * modifies the doc number and origin code of cost share transfers. * * @param errorGroup this scrubber run's error group * @param validGroup this scrubber run's valid group */ @Override public void performDemerger() { LOG.debug("performDemerger() started"); OriginEntryFieldUtil oefu = new OriginEntryFieldUtil(); Map<String, Integer> pMap = oefu.getFieldBeginningPositionMap(); // Without this step, the job fails with Optimistic Lock Exceptions // persistenceService.clearCache(); demergerReport = new DemergerReportData(); // set runDate here again, because demerger is calling outside from scrubber runDate = calculateRunDate(dateTimeService.getCurrentDate()); runCal = Calendar.getInstance(); runCal.setTime(runDate); // demerger called by outside from scrubber, so reset those values setOffsetString(); setDescriptions(); // new demerger starts String validOutputFilename = null; String errorOutputFilename = null; String demergerValidOutputFilename = null; String demergerErrorOutputFilename = null; if(!collectorMode){ validOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; errorOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_ERROR_SORTED_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; demergerValidOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.DEMERGER_VAILD_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; demergerErrorOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.DEMERGER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; } else { validOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; errorOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_ERROR_SORTED_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; demergerValidOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_DEMERGER_VAILD_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; demergerErrorOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_DEMERGER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; } // Without this step, the job fails with Optimistic Lock Exceptions // persistenceService.clearCache(); FileReader INPUT_GLE_FILE = null; FileReader INPUT_ERR_FILE = null; BufferedReader INPUT_GLE_FILE_br; BufferedReader INPUT_ERR_FILE_br; PrintStream OUTPUT_DEMERGER_GLE_FILE_ps; PrintStream OUTPUT_DEMERGER_ERR_FILE_ps; try { INPUT_GLE_FILE = new FileReader(validOutputFilename); INPUT_ERR_FILE = new FileReader(errorOutputFilename); } catch (FileNotFoundException e) { throw new RuntimeException(e); } try { OUTPUT_DEMERGER_GLE_FILE_ps = new PrintStream(demergerValidOutputFilename); OUTPUT_DEMERGER_ERR_FILE_ps = new PrintStream(demergerErrorOutputFilename); } catch (IOException e) { throw new RuntimeException(e); } int validSaved = 0; int errorSaved = 0; int validReadLine = 0; int errorReadLine = 0; boolean errorsLoading = false; INPUT_GLE_FILE_br = new BufferedReader(INPUT_GLE_FILE); INPUT_ERR_FILE_br = new BufferedReader(INPUT_ERR_FILE); try { String currentValidLine = INPUT_GLE_FILE_br.readLine(); String currentErrorLine = INPUT_ERR_FILE_br.readLine(); boolean meetFlag = false; while (currentValidLine != null || currentErrorLine != null) { // Demerger only catch IOexception since demerger report doesn't display // detail error message. try{ //validLine is null means that errorLine is not null if (org.apache.commons.lang.StringUtils.isEmpty(currentValidLine)) { String errorDesc = currentErrorLine.substring(pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_DESC), pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT)); String errorFinancialBalanceTypeCode = currentErrorLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE)); if (!checkingBypassEntry(errorFinancialBalanceTypeCode, errorDesc, demergerReport)){ createOutputEntry(currentErrorLine, OUTPUT_DEMERGER_ERR_FILE_ps); errorSaved++; } currentErrorLine = INPUT_ERR_FILE_br.readLine(); errorReadLine++; continue; } String financialBalanceTypeCode = currentValidLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE)); String desc = currentValidLine.substring(pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_DESC), pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT)); //errorLine is null means that validLine is not null if (org.apache.commons.lang.StringUtils.isEmpty(currentErrorLine)) { // Read all the transactions in the valid group and update the cost share transactions String updatedValidLine = checkAndSetTransactionTypeCostShare(financialBalanceTypeCode, desc, currentValidLine); createOutputEntry(updatedValidLine, OUTPUT_DEMERGER_GLE_FILE_ps); handleDemergerSaveValidEntry(updatedValidLine); validSaved++; currentValidLine = INPUT_GLE_FILE_br.readLine(); validReadLine++; continue; } String compareStringFromValidEntry = currentValidLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE), pMap.get(KFSPropertyConstants.TRANSACTION_ENTRY_SEQUENCE_NUMBER)); String compareStringFromErrorEntry = currentErrorLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE), pMap.get(KFSPropertyConstants.TRANSACTION_ENTRY_SEQUENCE_NUMBER)); String errorDesc = currentErrorLine.substring(pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_DESC), pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT)); String errorFinancialBalanceTypeCode = currentErrorLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE)); if (compareStringFromValidEntry.compareTo(compareStringFromErrorEntry) < 0){ // Read all the transactions in the valid group and update the cost share transactions String updatedValidLine = checkAndSetTransactionTypeCostShare(financialBalanceTypeCode, desc, currentValidLine); createOutputEntry(updatedValidLine, OUTPUT_DEMERGER_GLE_FILE_ps); handleDemergerSaveValidEntry(updatedValidLine); validSaved++; currentValidLine = INPUT_GLE_FILE_br.readLine(); validReadLine++; } else if (compareStringFromValidEntry.compareTo(compareStringFromErrorEntry) > 0) { if (!checkingBypassEntry(errorFinancialBalanceTypeCode, errorDesc, demergerReport)){ createOutputEntry(currentErrorLine, OUTPUT_DEMERGER_ERR_FILE_ps); errorSaved++; } currentErrorLine = INPUT_ERR_FILE_br.readLine(); errorReadLine++; } else { if (!checkingBypassEntry(financialBalanceTypeCode, desc, demergerReport)){ createOutputEntry(currentValidLine, OUTPUT_DEMERGER_ERR_FILE_ps); errorSaved++; } currentValidLine = INPUT_GLE_FILE_br.readLine(); validReadLine++; } continue; } catch (RuntimeException re) { LOG.error("performDemerger Stopped: " + re.getMessage()); throw new RuntimeException("performDemerger Stopped: " + re.getMessage(), re); } } INPUT_GLE_FILE_br.close(); INPUT_ERR_FILE_br.close(); OUTPUT_DEMERGER_GLE_FILE_ps.close(); OUTPUT_DEMERGER_ERR_FILE_ps.close(); } catch (IOException e) { LOG.error("performDemerger Stopped: " + e.getMessage()); throw new RuntimeException("performDemerger Stopped: " + e.getMessage(), e); } demergerReport.setErrorTransactionWritten(errorSaved); demergerReport.setErrorTransactionsRead(errorReadLine); demergerReport.setValidTransactionsRead(validReadLine); demergerReport.setValidTransactionsSaved(validSaved); if (!collectorMode) { demergerReportWriterService.writeStatisticLine("SCRUBBER ERROR TRANSACTIONS READ %,9d", demergerReport.getErrorTransactionsRead()); demergerReportWriterService.writeStatisticLine("SCRUBBER VALID TRANSACTIONS READ %,9d", demergerReport.getValidTransactionsRead()); demergerReportWriterService.writeNewLines(1); demergerReportWriterService.writeStatisticLine("DEMERGER ERRORS SAVED %,9d", demergerReport.getErrorTransactionsSaved()); demergerReportWriterService.writeStatisticLine("DEMERGER VALID TRANSACTIONS SAVED %,9d", demergerReport.getValidTransactionsSaved()); demergerReportWriterService.writeStatisticLine("OFFSET TRANSACTIONS BYPASSED %,9d", demergerReport.getOffsetTransactionsBypassed()); demergerReportWriterService.writeStatisticLine("CAPITALIZATION TRANSACTIONS BYPASSED %,9d", demergerReport.getCapitalizationTransactionsBypassed()); demergerReportWriterService.writeStatisticLine("LIABILITY TRANSACTIONS BYPASSED %,9d", demergerReport.getLiabilityTransactionsBypassed()); demergerReportWriterService.writeStatisticLine("TRANSFER TRANSACTIONS BYPASSED %,9d", demergerReport.getTransferTransactionsBypassed()); demergerReportWriterService.writeStatisticLine("COST SHARE TRANSACTIONS BYPASSED %,9d", demergerReport.getCostShareTransactionsBypassed()); demergerReportWriterService.writeStatisticLine("COST SHARE ENC TRANSACTIONS BYPASSED %,9d", demergerReport.getCostShareEncumbranceTransactionsBypassed()); generateDemergerRemovedTransactionsReport(demergerErrorOutputFilename); } } /** * Determine the type of the transaction by looking at attributes * * @param transaction Transaction to identify * @return CE (Cost share encumbrance, O (Offset), C (apitalization), L (Liability), T (Transfer), CS (Cost Share), X (Other) */ protected String getTransactionType(OriginEntryInformation transaction) { if (TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE.equals(transaction.getFinancialBalanceTypeCode())) { return TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE; } String desc = transaction.getTransactionLedgerEntryDescription(); if (desc == null) { return TRANSACTION_TYPE_OTHER; } if (desc.startsWith(offsetDescription) && desc.indexOf(COST_SHARE_TRANSFER_ENTRY_IND) > -1) { return TRANSACTION_TYPE_COST_SHARE; } if (desc.startsWith(costShareDescription) && desc.indexOf(COST_SHARE_TRANSFER_ENTRY_IND) > -1) { return TRANSACTION_TYPE_COST_SHARE; } if (desc.startsWith(offsetDescription)) { return TRANSACTION_TYPE_OFFSET; } if (desc.startsWith(capitalizationDescription)) { return TRANSACTION_TYPE_CAPITALIZATION; } if (desc.startsWith(liabilityDescription)) { return TRANSACTION_TYPE_LIABILITY; } if (desc.startsWith(transferDescription)) { return TRANSACTION_TYPE_TRANSFER; } return TRANSACTION_TYPE_OTHER; } protected String getTransactionType(String financialBalanceTypeCode, String desc) { if (TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE.equals(financialBalanceTypeCode)) { return TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE; } if (desc == null) { return TRANSACTION_TYPE_OTHER; } if (desc.startsWith(offsetDescription) && desc.indexOf(COST_SHARE_TRANSFER_ENTRY_IND) > -1) { return TRANSACTION_TYPE_COST_SHARE; } if (desc.startsWith(costShareDescription) && desc.indexOf(COST_SHARE_TRANSFER_ENTRY_IND) > -1) { return TRANSACTION_TYPE_COST_SHARE; } if (desc.startsWith(offsetDescription)) { return TRANSACTION_TYPE_OFFSET; } if (desc.startsWith(capitalizationDescription)) { return TRANSACTION_TYPE_CAPITALIZATION; } if (desc.startsWith(liabilityDescription)) { return TRANSACTION_TYPE_LIABILITY; } if (desc.startsWith(transferDescription)) { return TRANSACTION_TYPE_TRANSFER; } return TRANSACTION_TYPE_OTHER; } /** * This will process a group of origin entries. The COBOL code was refactored a lot to get this so there isn't a 1 to 1 section * of Cobol relating to this. * * @param originEntryGroup Group to process */ protected void processGroup(boolean reportOnlyMode, ScrubberReportData scrubberReport) { OriginEntryFull lastEntry = null; scrubCostShareAmount = KualiDecimal.ZERO; unitOfWork = new UnitOfWorkInfo(); FileReader INPUT_GLE_FILE = null; String GLEN_RECORD; BufferedReader INPUT_GLE_FILE_br; try { INPUT_GLE_FILE = new FileReader(inputFile); } catch (FileNotFoundException e) { throw new RuntimeException(e); } try { OUTPUT_GLE_FILE_ps = new PrintStream(validFile); OUTPUT_ERR_FILE_ps = new PrintStream(errorFile); OUTPUT_EXP_FILE_ps = new PrintStream(expiredFile); LOG.info("Successfully opened " + validFile + ", " + errorFile + ", " + expiredFile + " for writing."); } catch (IOException e) { throw new RuntimeException(e); } INPUT_GLE_FILE_br = new BufferedReader(INPUT_GLE_FILE); int line = 0; LOG.debug("Starting Scrubber Process process group..."); try { while ((GLEN_RECORD = INPUT_GLE_FILE_br.readLine()) != null) { if (!org.apache.commons.lang.StringUtils.isEmpty(GLEN_RECORD) && !org.apache.commons.lang.StringUtils.isBlank(GLEN_RECORD.trim())) { line++; OriginEntryFull unscrubbedEntry = new OriginEntryFull(); List<Message> tmperrors = unscrubbedEntry.setFromTextFileForBatch(GLEN_RECORD, line); scrubberReport.incrementUnscrubbedRecordsRead(); transactionErrors = new ArrayList<Message>(); // // This is done so if the code modifies this row, then saves it, it will be an insert, // and it won't touch the original. The Scrubber never modifies input rows/groups. // not relevant for file version boolean saveErrorTransaction = false; boolean saveValidTransaction = false; boolean fatalErrorOccurred = false; // Build a scrubbed entry OriginEntryFull scrubbedEntry = new OriginEntryFull(); scrubbedEntry.setDocumentNumber(unscrubbedEntry.getDocumentNumber()); scrubbedEntry.setOrganizationDocumentNumber(unscrubbedEntry.getOrganizationDocumentNumber()); scrubbedEntry.setOrganizationReferenceId(unscrubbedEntry.getOrganizationReferenceId()); scrubbedEntry.setReferenceFinancialDocumentNumber(unscrubbedEntry.getReferenceFinancialDocumentNumber()); Integer transactionNumber = unscrubbedEntry.getTransactionLedgerEntrySequenceNumber(); scrubbedEntry.setTransactionLedgerEntrySequenceNumber(null == transactionNumber ? new Integer(0) : transactionNumber); scrubbedEntry.setTransactionLedgerEntryDescription(unscrubbedEntry.getTransactionLedgerEntryDescription()); scrubbedEntry.setTransactionLedgerEntryAmount(unscrubbedEntry.getTransactionLedgerEntryAmount()); scrubbedEntry.setTransactionDebitCreditCode(unscrubbedEntry.getTransactionDebitCreditCode()); if (!collectorMode) { ledgerSummaryReport.summarizeEntry(unscrubbedEntry); } // For Labor Scrubber boolean laborIndicator = false; tmperrors.addAll(scrubberValidator.validateTransaction(unscrubbedEntry, scrubbedEntry, universityRunDate, laborIndicator, accountingCycleCachingService)); transactionErrors.addAll(tmperrors); Account unscrubbedEntryAccount = accountingCycleCachingService.getAccount(unscrubbedEntry.getChartOfAccountsCode(), unscrubbedEntry.getAccountNumber()); // KFSMI-173: both the expired and closed accounts rows are put in the expired account if ((unscrubbedEntryAccount != null) && (scrubberValidator.isAccountExpired(unscrubbedEntryAccount, universityRunDate) || unscrubbedEntryAccount.isClosed())) { // Make a copy of it so OJB doesn't just update the row in the original // group. It needs to make a new one in the expired group OriginEntryFull expiredEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); createOutputEntry(expiredEntry, OUTPUT_EXP_FILE_ps); scrubberReport.incrementExpiredAccountFound(); } // the collector scrubber uses this map to apply the same changes made on an origin entry during scrubbing to // the collector detail record if (collectorMode) { unscrubbedToScrubbedEntries.put(unscrubbedEntry, scrubbedEntry); } if (!isFatal(transactionErrors)) { saveValidTransaction = true; if (!collectorMode) { // See if unit of work has changed if (!unitOfWork.isSameUnitOfWork(scrubbedEntry)) { // Generate offset for last unit of work // pass the String line for generating error files generateOffset(lastEntry, scrubberReport); unitOfWork = new UnitOfWorkInfo(scrubbedEntry); } KualiDecimal transactionAmount = scrubbedEntry.getTransactionLedgerEntryAmount(); ParameterEvaluator offsetFiscalPeriods = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.OFFSET_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()); BalanceType scrubbedEntryBalanceType = accountingCycleCachingService.getBalanceType(scrubbedEntry.getFinancialBalanceTypeCode()); if (scrubbedEntryBalanceType.isFinancialOffsetGenerationIndicator() && offsetFiscalPeriods.evaluationSucceeds()) { if (scrubbedEntry.isDebit()) { unitOfWork.offsetAmount = unitOfWork.offsetAmount.add(transactionAmount); } else { unitOfWork.offsetAmount = unitOfWork.offsetAmount.subtract(transactionAmount); } } // The sub account type code will only exist if there is a valid sub account String subAccountTypeCode = GeneralLedgerConstants.getSpaceSubAccountTypeCode(); // major assumption: the a21 subaccount is proxied, so we don't want to query the database if the // subacct // number is dashes if (!KFSConstants.getDashSubAccountNumber().equals(scrubbedEntry.getSubAccountNumber())) { A21SubAccount scrubbedEntryA21SubAccount = accountingCycleCachingService.getA21SubAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber(), scrubbedEntry.getSubAccountNumber()); if (ObjectUtils.isNotNull(scrubbedEntryA21SubAccount)) { subAccountTypeCode = scrubbedEntryA21SubAccount.getSubAccountTypeCode(); } } ParameterEvaluator costShareObjectTypeCodes = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_OBJ_TYPE_CODES, scrubbedEntry.getFinancialObjectTypeCode()); ParameterEvaluator costShareEncBalanceTypeCodes = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_ENC_BAL_TYP_CODES, scrubbedEntry.getFinancialBalanceTypeCode()); ParameterEvaluator costShareEncFiscalPeriodCodes = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_ENC_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()); ParameterEvaluator costShareEncDocTypeCodes = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_ENC_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode().trim()); ParameterEvaluator costShareFiscalPeriodCodes = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()); Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); if (costShareObjectTypeCodes.evaluationSucceeds() && costShareEncBalanceTypeCodes.evaluationSucceeds() && scrubbedEntryAccount.isForContractsAndGrants() && KFSConstants.SubAccountType.COST_SHARE.equals(subAccountTypeCode) && costShareEncFiscalPeriodCodes.evaluationSucceeds() && costShareEncDocTypeCodes.evaluationSucceeds()) { TransactionError te1 = generateCostShareEncumbranceEntries(scrubbedEntry, scrubberReport); if (te1 != null) { List errors = new ArrayList(); errors.add(te1.message); handleTransactionErrors(te1.transaction, errors); saveValidTransaction = false; saveErrorTransaction = true; } } SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); if (costShareObjectTypeCodes.evaluationSucceeds() && scrubbedEntryOption.getActualFinancialBalanceTypeCd().equals(scrubbedEntry.getFinancialBalanceTypeCode()) && scrubbedEntryAccount.isForContractsAndGrants() && KFSConstants.SubAccountType.COST_SHARE.equals(subAccountTypeCode) && costShareFiscalPeriodCodes.evaluationSucceeds() && costShareEncDocTypeCodes.evaluationSucceeds()) { if (scrubbedEntry.isDebit()) { scrubCostShareAmount = scrubCostShareAmount.subtract(transactionAmount); } else { scrubCostShareAmount = scrubCostShareAmount.add(transactionAmount); } } ParameterEvaluator otherDocTypeCodes = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.OFFSET_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode()); if (otherDocTypeCodes.evaluationSucceeds()) { String m = processCapitalization(scrubbedEntry, scrubberReport); if (m != null) { saveValidTransaction = false; saveErrorTransaction = false; addTransactionError(m, "", Message.TYPE_FATAL); } m = processLiabilities(scrubbedEntry, scrubberReport); if (m != null) { saveValidTransaction = false; saveErrorTransaction = false; addTransactionError(m, "", Message.TYPE_FATAL); } m = processPlantIndebtedness(scrubbedEntry, scrubberReport); if (m != null) { saveValidTransaction = false; saveErrorTransaction = false; addTransactionError(m, "", Message.TYPE_FATAL); } } if (!scrubCostShareAmount.isZero()) { TransactionError te = generateCostShareEntries(scrubbedEntry, scrubberReport); if (te != null) { saveValidTransaction = false; saveErrorTransaction = false; // Make a copy of it so OJB doesn't just update the row in the original // group. It needs to make a new one in the error group OriginEntryFull errorEntry = new OriginEntryFull(te.transaction); errorEntry.setTransactionScrubberOffsetGenerationIndicator(false); createOutputEntry(GLEN_RECORD, OUTPUT_ERR_FILE_ps); scrubberReport.incrementErrorRecordWritten(); unitOfWork.errorsFound = true; handleTransactionError(te.transaction, te.message); } scrubCostShareAmount = KualiDecimal.ZERO; } lastEntry = scrubbedEntry; } } else { // Error transaction saveErrorTransaction = true; fatalErrorOccurred = true; } handleTransactionErrors(OriginEntryFull.copyFromOriginEntryable(unscrubbedEntry), transactionErrors); if (saveValidTransaction) { scrubbedEntry.setTransactionScrubberOffsetGenerationIndicator(false); createOutputEntry(scrubbedEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementScrubbedRecordWritten(); } if (saveErrorTransaction) { // Make a copy of it so OJB doesn't just update the row in the original // group. It needs to make a new one in the error group OriginEntryFull errorEntry = OriginEntryFull.copyFromOriginEntryable(unscrubbedEntry); errorEntry.setTransactionScrubberOffsetGenerationIndicator(false); createOutputEntry(GLEN_RECORD, OUTPUT_ERR_FILE_ps); scrubberReport.incrementErrorRecordWritten(); if (!fatalErrorOccurred) { // if a fatal error occurred, the creation of a new unit of work was by-passed; // therefore, it shouldn't ruin the previous unit of work unitOfWork.errorsFound = true; } } } } if (!collectorMode) { // Generate last offset (if necessary) generateOffset(lastEntry, scrubberReport); } INPUT_GLE_FILE_br.close(); INPUT_GLE_FILE.close(); OUTPUT_GLE_FILE_ps.close(); OUTPUT_ERR_FILE_ps.close(); OUTPUT_EXP_FILE_ps.close(); LOG.info("Successfully writen and closed " + validFile + ", " + errorFile + ", " + expiredFile + "."); handleEndOfScrubberReport(scrubberReport); if (!collectorMode) { ledgerSummaryReport.writeReport(this.scrubberLedgerReportWriterService); } } catch (IOException e) { throw new RuntimeException(e); } } /** * Determines if a given error is fatal and should stop this scrubber run * * @param errors errors from a scrubber run * @return true if the run should be abended, false otherwise */ protected boolean isFatal(List<Message> errors) { for (Iterator<Message> iter = errors.iterator(); iter.hasNext();) { Message element = iter.next(); if (element.getType() == Message.TYPE_FATAL) { return true; } } return false; } /** * Generates a cost share entry and offset for the given entry and saves both to the valid group * * @param scrubbedEntry the originEntry that was scrubbed * @return a TransactionError initialized with any error encounted during entry generation, or (hopefully) null */ protected TransactionError generateCostShareEntries(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { // 3000-COST-SHARE to 3100-READ-OFSD in the cobol Generate Cost Share Entries LOG.debug("generateCostShareEntries() started"); try { OriginEntryFull costShareEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); A21SubAccount scrubbedEntryA21SubAccount = accountingCycleCachingService.getA21SubAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber(), scrubbedEntry.getSubAccountNumber()); costShareEntry.setFinancialObjectCode(parameterService.getParameterValueAsString(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.COST_SHARE_OBJECT_CODE_PARM_NM)); costShareEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); costShareEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinancialObjectTypeTransferExpenseCd()); costShareEntry.setTransactionLedgerEntrySequenceNumber(new Integer(0)); StringBuffer description = new StringBuffer(); description.append(costShareDescription); description.append(" ").append(scrubbedEntry.getAccountNumber()); description.append(offsetString); costShareEntry.setTransactionLedgerEntryDescription(description.toString()); costShareEntry.setTransactionLedgerEntryAmount(scrubCostShareAmount); if (scrubCostShareAmount.isPositive()) { costShareEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } else { costShareEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); costShareEntry.setTransactionLedgerEntryAmount(scrubCostShareAmount.negated()); } costShareEntry.setTransactionDate(runDate); costShareEntry.setOrganizationDocumentNumber(null); costShareEntry.setProjectCode(KFSConstants.getDashProjectCode()); costShareEntry.setOrganizationReferenceId(null); costShareEntry.setReferenceFinancialDocumentTypeCode(null); costShareEntry.setReferenceFinancialSystemOriginationCode(null); costShareEntry.setReferenceFinancialDocumentNumber(null); costShareEntry.setFinancialDocumentReversalDate(null); costShareEntry.setTransactionEncumbranceUpdateCode(null); createOutputEntry(costShareEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementCostShareEntryGenerated(); OriginEntryFull costShareOffsetEntry = new OriginEntryFull(costShareEntry); costShareOffsetEntry.setTransactionLedgerEntryDescription(getOffsetMessage()); OffsetDefinition offsetDefinition = accountingCycleCachingService.getOffsetDefinition(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), KFSConstants.TRANSFER_FUNDS, scrubbedEntry.getFinancialBalanceTypeCode()); if (offsetDefinition != null) { if (offsetDefinition.getFinancialObject() == null) { StringBuffer objectCodeKey = new StringBuffer(); objectCodeKey.append(offsetDefinition.getUniversityFiscalYear()); objectCodeKey.append("-").append(offsetDefinition.getChartOfAccountsCode()); objectCodeKey.append("-").append(offsetDefinition.getFinancialObjectCode()); Message m = new Message(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_OBJECT_CODE_NOT_FOUND) + " (" + objectCodeKey.toString() + ")", Message.TYPE_FATAL); LOG.debug("generateCostShareEntries() Error 1 object not found"); return new TransactionError(costShareEntry, m); } costShareOffsetEntry.setFinancialObjectCode(offsetDefinition.getFinancialObjectCode()); costShareOffsetEntry.setFinancialObject(offsetDefinition.getFinancialObject()); costShareOffsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); } else { Map<Transaction, List<Message>> errors = new HashMap<Transaction, List<Message>>(); StringBuffer offsetKey = new StringBuffer("cost share transfer "); offsetKey.append(scrubbedEntry.getUniversityFiscalYear()); offsetKey.append("-"); offsetKey.append(scrubbedEntry.getChartOfAccountsCode()); offsetKey.append("-TF-"); offsetKey.append(scrubbedEntry.getFinancialBalanceTypeCode()); Message m = new Message(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_NOT_FOUND) + " (" + offsetKey.toString() + ")", Message.TYPE_FATAL); LOG.debug("generateCostShareEntries() Error 2 offset not found"); return new TransactionError(costShareEntry, m); } costShareOffsetEntry.setFinancialObjectTypeCode(offsetDefinition.getFinancialObject().getFinancialObjectTypeCode()); if (costShareEntry.isCredit()) { costShareOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } else { costShareOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } try { flexibleOffsetAccountService.updateOffset(costShareOffsetEntry); } catch (InvalidFlexibleOffsetException e) { Message m = new Message(e.getMessage(), Message.TYPE_FATAL); if (LOG.isDebugEnabled()) { LOG.debug("generateCostShareEntries() Cost Share Transfer Flexible Offset Error: " + e.getMessage()); } return new TransactionError(costShareEntry, m); } createOutputEntry(costShareOffsetEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementCostShareEntryGenerated(); OriginEntryFull costShareSourceAccountEntry = new OriginEntryFull(costShareEntry); description = new StringBuffer(); description.append(costShareDescription); description.append(" ").append(scrubbedEntry.getAccountNumber()); description.append(offsetString); costShareSourceAccountEntry.setTransactionLedgerEntryDescription(description.toString()); costShareSourceAccountEntry.setChartOfAccountsCode(scrubbedEntryA21SubAccount.getCostShareChartOfAccountCode()); costShareSourceAccountEntry.setAccountNumber(scrubbedEntryA21SubAccount.getCostShareSourceAccountNumber()); setCostShareObjectCode(costShareSourceAccountEntry, scrubbedEntry); costShareSourceAccountEntry.setSubAccountNumber(scrubbedEntryA21SubAccount.getCostShareSourceSubAccountNumber()); if (StringHelper.isNullOrEmpty(costShareSourceAccountEntry.getSubAccountNumber())) { costShareSourceAccountEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); } costShareSourceAccountEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); costShareSourceAccountEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinancialObjectTypeTransferExpenseCd()); costShareSourceAccountEntry.setTransactionLedgerEntrySequenceNumber(new Integer(0)); costShareSourceAccountEntry.setTransactionLedgerEntryAmount(scrubCostShareAmount); if (scrubCostShareAmount.isPositive()) { costShareSourceAccountEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } else { costShareSourceAccountEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); costShareSourceAccountEntry.setTransactionLedgerEntryAmount(scrubCostShareAmount.negated()); } costShareSourceAccountEntry.setTransactionDate(runDate); costShareSourceAccountEntry.setOrganizationDocumentNumber(null); costShareSourceAccountEntry.setProjectCode(KFSConstants.getDashProjectCode()); costShareSourceAccountEntry.setOrganizationReferenceId(null); costShareSourceAccountEntry.setReferenceFinancialDocumentTypeCode(null); costShareSourceAccountEntry.setReferenceFinancialSystemOriginationCode(null); costShareSourceAccountEntry.setReferenceFinancialDocumentNumber(null); costShareSourceAccountEntry.setFinancialDocumentReversalDate(null); costShareSourceAccountEntry.setTransactionEncumbranceUpdateCode(null); createOutputEntry(costShareSourceAccountEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementCostShareEntryGenerated(); OriginEntryFull costShareSourceAccountOffsetEntry = new OriginEntryFull(costShareSourceAccountEntry); costShareSourceAccountOffsetEntry.setTransactionLedgerEntryDescription(getOffsetMessage()); // Lookup the new offset definition. offsetDefinition = accountingCycleCachingService.getOffsetDefinition(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), KFSConstants.TRANSFER_FUNDS, scrubbedEntry.getFinancialBalanceTypeCode()); if (offsetDefinition != null) { if (offsetDefinition.getFinancialObject() == null) { Map<Transaction, List<Message>> errors = new HashMap<Transaction, List<Message>>(); StringBuffer objectCodeKey = new StringBuffer(); objectCodeKey.append(costShareEntry.getUniversityFiscalYear()); objectCodeKey.append("-").append(scrubbedEntry.getChartOfAccountsCode()); objectCodeKey.append("-").append(scrubbedEntry.getFinancialObjectCode()); Message m = new Message(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_OBJECT_CODE_NOT_FOUND) + " (" + objectCodeKey.toString() + ")", Message.TYPE_FATAL); LOG.debug("generateCostShareEntries() Error 3 object not found"); return new TransactionError(costShareSourceAccountEntry, m); } costShareSourceAccountOffsetEntry.setFinancialObjectCode(offsetDefinition.getFinancialObjectCode()); costShareSourceAccountOffsetEntry.setFinancialObject(offsetDefinition.getFinancialObject()); costShareSourceAccountOffsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); } else { Map<Transaction, List<Message>> errors = new HashMap<Transaction, List<Message>>(); StringBuffer offsetKey = new StringBuffer("cost share transfer source "); offsetKey.append(scrubbedEntry.getUniversityFiscalYear()); offsetKey.append("-"); offsetKey.append(scrubbedEntry.getChartOfAccountsCode()); offsetKey.append("-TF-"); offsetKey.append(scrubbedEntry.getFinancialBalanceTypeCode()); Message m = new Message(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_NOT_FOUND) + " (" + offsetKey.toString() + ")", Message.TYPE_FATAL); LOG.debug("generateCostShareEntries() Error 4 offset not found"); return new TransactionError(costShareSourceAccountEntry, m); } costShareSourceAccountOffsetEntry.setFinancialObjectTypeCode(offsetDefinition.getFinancialObject().getFinancialObjectTypeCode()); if (scrubbedEntry.isCredit()) { costShareSourceAccountOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } else { costShareSourceAccountOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } try { flexibleOffsetAccountService.updateOffset(costShareSourceAccountOffsetEntry); } catch (InvalidFlexibleOffsetException e) { Message m = new Message(e.getMessage(), Message.TYPE_FATAL); if (LOG.isDebugEnabled()) { LOG.debug("generateCostShareEntries() Cost Share Transfer Account Flexible Offset Error: " + e.getMessage()); } return new TransactionError(costShareEntry, m); } createOutputEntry(costShareSourceAccountOffsetEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementCostShareEntryGenerated(); scrubCostShareAmount = KualiDecimal.ZERO; } catch (IOException ioe) { LOG.error("generateCostShareEntries() Stopped: " + ioe.getMessage()); throw new RuntimeException("generateCostShareEntries() Stopped: " + ioe.getMessage(), ioe); } LOG.debug("generateCostShareEntries() successful"); return null; } /** * Get all the transaction descriptions from the param table */ protected void setDescriptions() { //TODO: move to constants class? offsetDescription = "GENERATED OFFSET"; capitalizationDescription = "GENERATED CAPITALIZATION"; liabilityDescription = "GENERATED LIABILITY"; costShareDescription = "GENERATED COST SHARE FROM"; transferDescription = "GENERATED TRANSFER FROM"; } /** * Generate the flag for the end of specific descriptions. This will be used in the demerger step */ protected void setOffsetString() { NumberFormat nf = NumberFormat.getInstance(); nf.setMaximumFractionDigits(0); nf.setMaximumIntegerDigits(2); nf.setMinimumFractionDigits(0); nf.setMinimumIntegerDigits(2); offsetString = COST_SHARE_TRANSFER_ENTRY_IND + nf.format(runCal.get(Calendar.MONTH) + 1) + nf.format(runCal.get(Calendar.DAY_OF_MONTH)); } /** * Generate the offset message with the flag at the end * * @return a generated offset message */ protected String getOffsetMessage() { String msg = offsetDescription + GeneralLedgerConstants.getSpaceTransactionLedgetEntryDescription(); return msg.substring(0, OFFSET_MESSAGE_MAXLENGTH) + offsetString; } /** * Generates capitalization entries if necessary * * @param scrubbedEntry the entry to generate capitalization entries (possibly) for * @return null if no error, message if error */ protected String processCapitalization(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { try { // Lines 4694 - 4798 of the Pro Cobol listing on Confluence if (!parameterService.getParameterValueAsBoolean(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.CAPITALIZATION_IND)) { return null; } OriginEntryFull capitalizationEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); ObjectCode scrubbedEntryObjectCode = accountingCycleCachingService.getObjectCode(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialObjectCode()); Chart scrubbedEntryChart = accountingCycleCachingService.getChart(scrubbedEntry.getChartOfAccountsCode()); Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); ParameterEvaluator documentTypeCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode()) : null; ParameterEvaluator fiscalPeriodCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()) : null; ParameterEvaluator objectSubTypeCodes = (!ObjectUtils.isNull(scrubbedEntryObjectCode)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_OBJ_SUB_TYPE_CODES, scrubbedEntryObjectCode.getFinancialObjectSubTypeCode()) : null; ParameterEvaluator subFundGroupCodes = (!ObjectUtils.isNull(scrubbedEntryAccount)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_SUB_FUND_GROUP_CODES, scrubbedEntryAccount.getSubFundGroupCode()) : null; ParameterEvaluator chartCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_CHART_CODES, scrubbedEntry.getChartOfAccountsCode()) : null; if (scrubbedEntry.getFinancialBalanceTypeCode().equals(scrubbedEntryOption.getActualFinancialBalanceTypeCd()) && scrubbedEntry.getUniversityFiscalYear().intValue() > 1995 && (documentTypeCodes != null && documentTypeCodes.evaluationSucceeds()) && (fiscalPeriodCodes != null && fiscalPeriodCodes.evaluationSucceeds()) && (objectSubTypeCodes != null && objectSubTypeCodes.evaluationSucceeds()) && (subFundGroupCodes != null && subFundGroupCodes.evaluationSucceeds()) && (chartCodes != null && chartCodes.evaluationSucceeds())) { String objectSubTypeCode = scrubbedEntryObjectCode.getFinancialObjectSubTypeCode(); String capitalizationObjectCode = parameterService.getSubParameterValueAsString(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.CAPITALIZATION_SUBTYPE_OBJECT, objectSubTypeCode); if ( org.apache.commons.lang.StringUtils.isNotBlank( capitalizationObjectCode ) ) { capitalizationEntry.setFinancialObjectCode(capitalizationObjectCode); capitalizationEntry.setFinancialObject(accountingCycleCachingService.getObjectCode(capitalizationEntry.getUniversityFiscalYear(), capitalizationEntry.getChartOfAccountsCode(), capitalizationEntry.getFinancialObjectCode())); } // financialSubObjectCode should always be changed to dashes for capitalization entries capitalizationEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); capitalizationEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinancialObjectTypeAssetsCd()); capitalizationEntry.setTransactionLedgerEntryDescription(capitalizationDescription); plantFundAccountLookup(scrubbedEntry, capitalizationEntry); capitalizationEntry.setUniversityFiscalPeriodCode(scrubbedEntry.getUniversityFiscalPeriodCode()); createOutputEntry(capitalizationEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementCapitalizationEntryGenerated(); // Clear out the id & the ojb version number to make sure we do an insert on the next one capitalizationEntry.setVersionNumber(null); capitalizationEntry.setEntryId(null); // Check system parameters for overriding fund balance object code; otherwise, use // the chart fund balance object code. String fundBalanceCode = parameterService.getParameterValueAsString( ScrubberStep.class, GlParameterConstants.CAPITALIZATION_OFFSET_CODE); ObjectCode fundObjectCode = getFundBalanceObjectCode(fundBalanceCode, capitalizationEntry); if (fundObjectCode != null) { capitalizationEntry.setFinancialObjectTypeCode(fundObjectCode.getFinancialObjectTypeCode()); capitalizationEntry.setFinancialObjectCode(fundBalanceCode); } else { capitalizationEntry.setFinancialObjectCode(scrubbedEntryChart.getFundBalanceObjectCode()); //TODO: check to see if COBOL does this - seems weird - is this saying if the object code doesn't exist use the value from options? Shouldn't it always come from one or the other? if (ObjectUtils.isNotNull(scrubbedEntryChart.getFundBalanceObject())) { capitalizationEntry.setFinancialObjectTypeCode(scrubbedEntryChart.getFundBalanceObject().getFinancialObjectTypeCode()); } else { capitalizationEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeFundBalanceCd()); } } populateTransactionDebtCreditCode(scrubbedEntry, capitalizationEntry); try { flexibleOffsetAccountService.updateOffset(capitalizationEntry); } catch (InvalidFlexibleOffsetException e) { if (LOG.isDebugEnabled()) { LOG.debug("processCapitalization() Capitalization Flexible Offset Error: " + e.getMessage()); } return e.getMessage(); } createOutputEntry(capitalizationEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementCapitalizationEntryGenerated(); } } catch (IOException ioe) { LOG.error("processCapitalization() Stopped: " + ioe.getMessage()); throw new RuntimeException("processCapitalization() Stopped: " + ioe.getMessage(), ioe); } return null; } /** * Generates the plant indebtedness entries * * @param scrubbedEntry the entry to generated plant indebtedness entries for if necessary * @return null if no error, message if error */ protected String processPlantIndebtedness(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { try{ // Lines 4855 - 4979 of the Pro Cobol listing on Confluence if (!parameterService.getParameterValueAsBoolean(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.PLANT_INDEBTEDNESS_IND)) { return null; } OriginEntryFull plantIndebtednessEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); ObjectCode scrubbedEntryObjectCode = accountingCycleCachingService.getObjectCode(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialObjectCode()); Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); Chart scrubbedEntryChart = accountingCycleCachingService.getChart(scrubbedEntry.getChartOfAccountsCode()); if (!ObjectUtils.isNull(scrubbedEntryAccount)) { scrubbedEntryAccount.setOrganization(accountingCycleCachingService.getOrganization(scrubbedEntryAccount.getChartOfAccountsCode(), scrubbedEntryAccount.getOrganizationCode())); } ParameterEvaluator objectSubTypeCodes = (!ObjectUtils.isNull(scrubbedEntryObjectCode)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.PLANT_INDEBTEDNESS_OBJ_SUB_TYPE_CODES, scrubbedEntryObjectCode.getFinancialObjectSubTypeCode()) : null; ParameterEvaluator subFundGroupCodes = (!ObjectUtils.isNull(scrubbedEntryAccount)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.PLANT_INDEBTEDNESS_SUB_FUND_GROUP_CODES, scrubbedEntryAccount.getSubFundGroupCode()) : null; if (scrubbedEntry.getFinancialBalanceTypeCode().equals(scrubbedEntryOption.getActualFinancialBalanceTypeCd()) && (subFundGroupCodes != null && subFundGroupCodes.evaluationSucceeds()) && (objectSubTypeCodes != null && objectSubTypeCodes.evaluationSucceeds())) { plantIndebtednessEntry.setTransactionLedgerEntryDescription(KFSConstants.PLANT_INDEBTEDNESS_ENTRY_DESCRIPTION); populateTransactionDebtCreditCode(scrubbedEntry, plantIndebtednessEntry); plantIndebtednessEntry.setTransactionScrubberOffsetGenerationIndicator(true); createOutputEntry(plantIndebtednessEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementPlantIndebtednessEntryGenerated(); // Clear out the id & the ojb version number to make sure we do an insert on the next one plantIndebtednessEntry.setVersionNumber(null); plantIndebtednessEntry.setEntryId(null); // Check system parameters for overriding fund balance object code; otherwise, use // the chart fund balance object code. String fundBalanceCode = parameterService.getParameterValueAsString( ScrubberStep.class, GlParameterConstants.PLANT_INDEBTEDNESS_OFFSET_CODE); ObjectCode fundObjectCode = getFundBalanceObjectCode(fundBalanceCode, plantIndebtednessEntry); if (fundObjectCode != null) { plantIndebtednessEntry.setFinancialObjectTypeCode(fundObjectCode.getFinancialObjectTypeCode()); plantIndebtednessEntry.setFinancialObjectCode(fundBalanceCode); } else { plantIndebtednessEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeFundBalanceCd()); plantIndebtednessEntry.setFinancialObjectCode(scrubbedEntryChart.getFundBalanceObjectCode()); } plantIndebtednessEntry.setTransactionDebitCreditCode(scrubbedEntry.getTransactionDebitCreditCode()); plantIndebtednessEntry.setTransactionScrubberOffsetGenerationIndicator(true); plantIndebtednessEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); try { flexibleOffsetAccountService.updateOffset(plantIndebtednessEntry); } catch (InvalidFlexibleOffsetException e) { LOG.error("processPlantIndebtedness() Flexible Offset Exception (1)", e); if (LOG.isDebugEnabled()) { LOG.debug("processPlantIndebtedness() Plant Indebtedness Flexible Offset Error: " + e.getMessage()); } return e.getMessage(); } createOutputEntry(plantIndebtednessEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementPlantIndebtednessEntryGenerated(); // Clear out the id & the ojb version number to make sure we do an insert on the next one plantIndebtednessEntry.setVersionNumber(null); plantIndebtednessEntry.setEntryId(null); plantIndebtednessEntry.setFinancialObjectCode(scrubbedEntry.getFinancialObjectCode()); plantIndebtednessEntry.setFinancialObjectTypeCode(scrubbedEntry.getFinancialObjectTypeCode()); plantIndebtednessEntry.setTransactionDebitCreditCode(scrubbedEntry.getTransactionDebitCreditCode()); plantIndebtednessEntry.setTransactionLedgerEntryDescription(scrubbedEntry.getTransactionLedgerEntryDescription()); plantIndebtednessEntry.setAccountNumber(scrubbedEntry.getAccountNumber()); plantIndebtednessEntry.setSubAccountNumber(scrubbedEntry.getSubAccountNumber()); plantIndebtednessEntry.setAccountNumber(scrubbedEntryAccount.getOrganization().getCampusPlantAccountNumber()); plantIndebtednessEntry.setChartOfAccountsCode(scrubbedEntryAccount.getOrganization().getCampusPlantChartCode()); plantIndebtednessEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); plantIndebtednessEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); StringBuffer litGenPlantXferFrom = new StringBuffer(); litGenPlantXferFrom.append(transferDescription + " "); litGenPlantXferFrom.append(scrubbedEntry.getChartOfAccountsCode()).append(" "); litGenPlantXferFrom.append(scrubbedEntry.getAccountNumber()); plantIndebtednessEntry.setTransactionLedgerEntryDescription(litGenPlantXferFrom.toString()); createOutputEntry(plantIndebtednessEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementPlantIndebtednessEntryGenerated(); // Clear out the id & the ojb version number to make sure we do an insert on the next one plantIndebtednessEntry.setVersionNumber(null); plantIndebtednessEntry.setEntryId(null); plantIndebtednessEntry.setFinancialObjectCode(scrubbedEntryChart.getFundBalanceObjectCode()); plantIndebtednessEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeFundBalanceCd()); plantIndebtednessEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); populateTransactionDebtCreditCode(scrubbedEntry, plantIndebtednessEntry); try { flexibleOffsetAccountService.updateOffset(plantIndebtednessEntry); } catch (InvalidFlexibleOffsetException e) { LOG.error("processPlantIndebtedness() Flexible Offset Exception (2)", e); LOG.debug("processPlantIndebtedness() Plant Indebtedness Flexible Offset Error: " + e.getMessage()); return e.getMessage(); } createOutputEntry(plantIndebtednessEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementPlantIndebtednessEntryGenerated(); } } catch (IOException ioe) { LOG.error("processPlantIndebtedness() Stopped: " + ioe.getMessage()); throw new RuntimeException("processPlantIndebtedness() Stopped: " + ioe.getMessage(), ioe); } return null; } /** * Generate the liability entries for the entry if necessary * * @param scrubbedEntry the entry to generate liability entries for if necessary * @return null if no error, message if error */ protected String processLiabilities(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { try{ // Lines 4799 to 4839 of the Pro Cobol list of the scrubber on Confluence if (!parameterService.getParameterValueAsBoolean(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.LIABILITY_IND)) { return null; } Chart scrubbedEntryChart = accountingCycleCachingService.getChart(scrubbedEntry.getChartOfAccountsCode()); SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); ObjectCode scrubbedEntryFinancialObject = accountingCycleCachingService.getObjectCode(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialObjectCode()); Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); ParameterEvaluator chartCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_CHART_CODES, scrubbedEntry.getChartOfAccountsCode()) : null; ParameterEvaluator docTypeCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode()) : null; ParameterEvaluator fiscalPeriods = (!ObjectUtils.isNull(scrubbedEntry)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()) : null; ParameterEvaluator objSubTypeCodes = (!ObjectUtils.isNull(scrubbedEntryFinancialObject)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_OBJ_SUB_TYPE_CODES, scrubbedEntryFinancialObject.getFinancialObjectSubTypeCode()) : null; ParameterEvaluator subFundGroupCodes = (!ObjectUtils.isNull(scrubbedEntryAccount)) ? /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_SUB_FUND_GROUP_CODES, scrubbedEntryAccount.getSubFundGroupCode()) : null; if (scrubbedEntry.getFinancialBalanceTypeCode().equals(scrubbedEntryOption.getActualFinancialBalanceTypeCd()) && scrubbedEntry.getUniversityFiscalYear().intValue() > 1995 && (docTypeCodes != null && docTypeCodes.evaluationSucceeds()) && (fiscalPeriods != null && fiscalPeriods.evaluationSucceeds()) && (objSubTypeCodes != null && objSubTypeCodes.evaluationSucceeds()) && (subFundGroupCodes != null && subFundGroupCodes.evaluationSucceeds()) && (chartCodes != null && chartCodes.evaluationSucceeds())) { OriginEntryFull liabilityEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); liabilityEntry.setFinancialObjectCode(parameterService.getParameterValueAsString(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.LIABILITY_OBJECT_CODE)); liabilityEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeLiabilitiesCode()); liabilityEntry.setTransactionDebitCreditCode(scrubbedEntry.getTransactionDebitCreditCode()); liabilityEntry.setTransactionLedgerEntryDescription(liabilityDescription); plantFundAccountLookup(scrubbedEntry, liabilityEntry); createOutputEntry(liabilityEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementLiabilityEntryGenerated(); // Clear out the id & the ojb version number to make sure we do an insert on the next one liabilityEntry.setVersionNumber(null); liabilityEntry.setEntryId(null); // Check system parameters for overriding fund balance object code; otherwise, use // the chart fund balance object code. String fundBalanceCode = parameterService.getParameterValueAsString( ScrubberStep.class, GlParameterConstants.LIABILITY_OFFSET_CODE); ObjectCode fundObjectCode = getFundBalanceObjectCode(fundBalanceCode, liabilityEntry); if (fundObjectCode != null) { liabilityEntry.setFinancialObjectTypeCode(fundObjectCode.getFinancialObjectTypeCode()); liabilityEntry.setFinancialObjectCode(fundBalanceCode); } else { // ... and now generate the offset half of the liability entry liabilityEntry.setFinancialObjectCode(scrubbedEntryChart.getFundBalanceObjectCode()); if (ObjectUtils.isNotNull(scrubbedEntryChart.getFundBalanceObject())) { liabilityEntry.setFinancialObjectTypeCode(scrubbedEntryChart.getFundBalanceObject().getFinancialObjectTypeCode()); } else { liabilityEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeFundBalanceCd()); } } if (liabilityEntry.isDebit()) { liabilityEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } else { liabilityEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } try { flexibleOffsetAccountService.updateOffset(liabilityEntry); } catch (InvalidFlexibleOffsetException e) { if (LOG.isDebugEnabled()) { LOG.debug("processLiabilities() Liability Flexible Offset Error: " + e.getMessage()); } return e.getMessage(); } createOutputEntry(liabilityEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementLiabilityEntryGenerated(); } } catch (IOException ioe) { LOG.error("processLiabilities() Stopped: " + ioe.getMessage()); throw new RuntimeException("processLiabilities() Stopped: " + ioe.getMessage(), ioe); } return null; } /** * * This method... * @param fundBalanceCodeParameter * @param originEntryFull * @return */ protected ObjectCode getFundBalanceObjectCode(String fundBalanceCode, OriginEntryFull originEntryFull) { ObjectCode fundBalanceObjectCode = null; if (fundBalanceCode != null) { Map<String, Object> criteriaMap = new HashMap<String, Object>(); criteriaMap.put("universityFiscalYear", originEntryFull.getUniversityFiscalYear()); criteriaMap.put("chartOfAccountsCode", originEntryFull.getChartOfAccountsCode()); criteriaMap.put("financialObjectCode", fundBalanceCode); fundBalanceObjectCode = businessObjectService.findByPrimaryKey(ObjectCode.class, criteriaMap); } return fundBalanceObjectCode; } /** * * This method... * @param scrubbedEntry * @param fullEntry */ protected void populateTransactionDebtCreditCode(OriginEntryInformation scrubbedEntry, OriginEntryFull fullEntry) { if (scrubbedEntry.isDebit()) { fullEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } else { fullEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } } /** * Updates the entries with the proper chart and account for the plant fund * * @param scrubbedEntry basis for plant fund entry * @param liabilityEntry liability entry */ protected void plantFundAccountLookup(OriginEntryInformation scrubbedEntry, OriginEntryFull liabilityEntry) { // 4000-PLANT-FUND-ACCT to 4000-PLANT-FUND-ACCT-EXIT in cobol liabilityEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); ObjectCode scrubbedEntryObjectCode = accountingCycleCachingService.getObjectCode(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialObjectCode()); Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); scrubbedEntryAccount.setOrganization(accountingCycleCachingService.getOrganization(scrubbedEntryAccount.getChartOfAccountsCode(), scrubbedEntryAccount.getOrganizationCode())); if (!ObjectUtils.isNull(scrubbedEntryAccount) && !ObjectUtils.isNull(scrubbedEntryObjectCode)) { String objectSubTypeCode = scrubbedEntryObjectCode.getFinancialObjectSubTypeCode(); ParameterEvaluator campusObjSubTypeCodes = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.PLANT_FUND_CAMPUS_OBJECT_SUB_TYPE_CODES, objectSubTypeCode); ParameterEvaluator orgObjSubTypeCodes = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.PLANT_FUND_ORG_OBJECT_SUB_TYPE_CODES, objectSubTypeCode); if (campusObjSubTypeCodes.evaluationSucceeds()) { liabilityEntry.setAccountNumber(scrubbedEntryAccount.getOrganization().getCampusPlantAccountNumber()); liabilityEntry.setChartOfAccountsCode(scrubbedEntryAccount.getOrganization().getCampusPlantChartCode()); } else if (orgObjSubTypeCodes.evaluationSucceeds()) { liabilityEntry.setAccountNumber(scrubbedEntryAccount.getOrganization().getOrganizationPlantAccountNumber()); liabilityEntry.setChartOfAccountsCode(scrubbedEntryAccount.getOrganization().getOrganizationPlantChartCode()); } } } /** * The purpose of this method is to generate a "Cost Share Encumbrance" * transaction for the current transaction and its offset. The cost share chart and account for current transaction are obtained * from the CA_A21_SUB_ACCT_T table. This method calls the method SET-OBJECT-2004 to get the Cost Share Object Code. It then * writes out the cost share transaction. Next it read the GL_OFFSET_DEFN_T table for the offset object code that corresponds to * the cost share object code. In addition to the object code it needs to get subobject code. It then reads the CA_OBJECT_CODE_T * table to make sure the offset object code found in the GL_OFFSET_DEFN_T is valid and to get the object type code associated * with this object code. It writes out the offset transaction and returns. * * @param scrubbedEntry the entry to perhaps create a cost share encumbrance for * @return a message if there was an error encountered generating the entries, or (hopefully) null if no errors were encountered */ protected TransactionError generateCostShareEncumbranceEntries(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { try{ // 3200-COST-SHARE-ENC to 3200-CSE-EXIT in the COBOL LOG.debug("generateCostShareEncumbranceEntries() started"); OriginEntryFull costShareEncumbranceEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); // First 28 characters of the description, padding to 28 if shorter) StringBuffer buffer = new StringBuffer((scrubbedEntry.getTransactionLedgerEntryDescription() + GeneralLedgerConstants.getSpaceTransactionLedgetEntryDescription()).substring(0, COST_SHARE_ENCUMBRANCE_ENTRY_MAXLENGTH)); buffer.append("FR-"); buffer.append(costShareEncumbranceEntry.getChartOfAccountsCode()); buffer.append(costShareEncumbranceEntry.getAccountNumber()); costShareEncumbranceEntry.setTransactionLedgerEntryDescription(buffer.toString()); A21SubAccount scrubbedEntryA21SubAccount = accountingCycleCachingService.getA21SubAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber(), scrubbedEntry.getSubAccountNumber()); SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); costShareEncumbranceEntry.setChartOfAccountsCode(scrubbedEntryA21SubAccount.getCostShareChartOfAccountCode()); costShareEncumbranceEntry.setAccountNumber(scrubbedEntryA21SubAccount.getCostShareSourceAccountNumber()); costShareEncumbranceEntry.setSubAccountNumber(scrubbedEntryA21SubAccount.getCostShareSourceSubAccountNumber()); if (!StringUtils.hasText(costShareEncumbranceEntry.getSubAccountNumber())) { costShareEncumbranceEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); } costShareEncumbranceEntry.setFinancialBalanceTypeCode(scrubbedEntryOption.getCostShareEncumbranceBalanceTypeCd()); setCostShareObjectCode(costShareEncumbranceEntry, scrubbedEntry); costShareEncumbranceEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); costShareEncumbranceEntry.setTransactionLedgerEntrySequenceNumber(new Integer(0)); if (!StringUtils.hasText(scrubbedEntry.getTransactionDebitCreditCode())) { if (scrubbedEntry.getTransactionLedgerEntryAmount().isPositive()) { costShareEncumbranceEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } else { costShareEncumbranceEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); costShareEncumbranceEntry.setTransactionLedgerEntryAmount(scrubbedEntry.getTransactionLedgerEntryAmount().negated()); } } costShareEncumbranceEntry.setTransactionDate(runDate); costShareEncumbranceEntry.setTransactionScrubberOffsetGenerationIndicator(true); createOutputEntry(costShareEncumbranceEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementCostShareEncumbranceGenerated(); OriginEntryFull costShareEncumbranceOffsetEntry = new OriginEntryFull(costShareEncumbranceEntry); costShareEncumbranceOffsetEntry.setTransactionLedgerEntryDescription(offsetDescription); OffsetDefinition offset = accountingCycleCachingService.getOffsetDefinition(costShareEncumbranceEntry.getUniversityFiscalYear(), costShareEncumbranceEntry.getChartOfAccountsCode(), costShareEncumbranceEntry.getFinancialDocumentTypeCode(), costShareEncumbranceEntry.getFinancialBalanceTypeCode()); if (offset != null) { if (offset.getFinancialObject() == null) { StringBuffer offsetKey = new StringBuffer(); offsetKey.append(offset.getUniversityFiscalYear()); offsetKey.append("-"); offsetKey.append(offset.getChartOfAccountsCode()); offsetKey.append("-"); offsetKey.append(offset.getFinancialObjectCode()); LOG.debug("generateCostShareEncumbranceEntries() object code not found"); return new TransactionError(costShareEncumbranceEntry, new Message(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_NO_OBJECT_FOR_OBJECT_ON_OFSD) + "(" + offsetKey.toString() + ")", Message.TYPE_FATAL)); } costShareEncumbranceOffsetEntry.setFinancialObjectCode(offset.getFinancialObjectCode()); costShareEncumbranceOffsetEntry.setFinancialObject(offset.getFinancialObject()); costShareEncumbranceOffsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); } else { StringBuffer offsetKey = new StringBuffer("Cost share encumbrance "); offsetKey.append(costShareEncumbranceEntry.getUniversityFiscalYear()); offsetKey.append("-"); offsetKey.append(costShareEncumbranceEntry.getChartOfAccountsCode()); offsetKey.append("-"); offsetKey.append(costShareEncumbranceEntry.getFinancialDocumentTypeCode()); offsetKey.append("-"); offsetKey.append(costShareEncumbranceEntry.getFinancialBalanceTypeCode()); LOG.debug("generateCostShareEncumbranceEntries() offset not found"); return new TransactionError(costShareEncumbranceEntry, new Message(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_NOT_FOUND) + "(" + offsetKey.toString() + ")", Message.TYPE_FATAL)); } costShareEncumbranceOffsetEntry.setFinancialObjectTypeCode(offset.getFinancialObject().getFinancialObjectTypeCode()); if (costShareEncumbranceEntry.isCredit()) { costShareEncumbranceOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); } else { costShareEncumbranceOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } costShareEncumbranceOffsetEntry.setTransactionDate(runDate); costShareEncumbranceOffsetEntry.setOrganizationDocumentNumber(null); costShareEncumbranceOffsetEntry.setProjectCode(KFSConstants.getDashProjectCode()); costShareEncumbranceOffsetEntry.setOrganizationReferenceId(null); costShareEncumbranceOffsetEntry.setReferenceFinancialDocumentTypeCode(null); costShareEncumbranceOffsetEntry.setReferenceFinancialSystemOriginationCode(null); costShareEncumbranceOffsetEntry.setReferenceFinancialDocumentNumber(null); costShareEncumbranceOffsetEntry.setReversalDate(null); costShareEncumbranceOffsetEntry.setTransactionEncumbranceUpdateCode(null); costShareEncumbranceOffsetEntry.setTransactionScrubberOffsetGenerationIndicator(true); try { flexibleOffsetAccountService.updateOffset(costShareEncumbranceOffsetEntry); } catch (InvalidFlexibleOffsetException e) { Message m = new Message(e.getMessage(), Message.TYPE_FATAL); if (LOG.isDebugEnabled()) { LOG.debug("generateCostShareEncumbranceEntries() Cost Share Encumbrance Flexible Offset Error: " + e.getMessage()); } return new TransactionError(costShareEncumbranceOffsetEntry, m); } createOutputEntry(costShareEncumbranceOffsetEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementCostShareEncumbranceGenerated(); } catch (IOException ioe) { LOG.error("generateCostShareEncumbranceEntries() Stopped: " + ioe.getMessage()); throw new RuntimeException("generateCostShareEncumbranceEntries() Stopped: " + ioe.getMessage(), ioe); } LOG.debug("generateCostShareEncumbranceEntries() returned successfully"); return null; } /** * Sets the proper cost share object code in an entry and its offset * * @param costShareEntry GL Entry for cost share * @param originEntry Scrubbed GL Entry that this is based on */ @Override public void setCostShareObjectCode(OriginEntryFull costShareEntry, OriginEntryInformation originEntry) { ObjectCode originEntryFinancialObject = accountingCycleCachingService.getObjectCode(originEntry.getUniversityFiscalYear(), originEntry.getChartOfAccountsCode(), originEntry.getFinancialObjectCode()); if (originEntryFinancialObject == null) { addTransactionError(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_OBJECT_CODE_NOT_FOUND), originEntry.getFinancialObjectCode(), Message.TYPE_FATAL); } String originEntryObjectLevelCode = (originEntryFinancialObject == null) ? "" : originEntryFinancialObject.getFinancialObjectLevelCode(); String financialOriginEntryObjectCode = originEntry.getFinancialObjectCode(); //String originEntryObjectCode = scrubberProcessObjectCodeOverride.getOriginEntryObjectCode(originEntryObjectLevelCode, financialOriginEntryObjectCode); // General rules String param = parameterService.getSubParameterValueAsString(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.COST_SHARE_OBJECT_CODE_BY_LEVEL_PARM_NM, originEntryObjectLevelCode); if (param == null) { param = parameterService.getSubParameterValueAsString(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.COST_SHARE_OBJECT_CODE_BY_LEVEL_PARM_NM, "DEFAULT"); if (param == null) { throw new RuntimeException("Unable to determine cost sharing object code from object level. Default entry missing."); } } financialOriginEntryObjectCode = param; // Lookup the new object code ObjectCode objectCode = accountingCycleCachingService.getObjectCode(costShareEntry.getUniversityFiscalYear(), costShareEntry.getChartOfAccountsCode(), financialOriginEntryObjectCode); if (objectCode != null) { costShareEntry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode()); costShareEntry.setFinancialObjectCode(financialOriginEntryObjectCode); } else { addTransactionError(configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_COST_SHARE_OBJECT_NOT_FOUND), costShareEntry.getFinancialObjectCode(), Message.TYPE_FATAL); } } /** * The purpose of this method is to build the actual offset transaction. It does this by performing the following steps: 1. * Getting the offset object code and offset subobject code from the GL Offset Definition Table. 2. For the offset object code * it needs to get the associated object type, object subtype, and object active code. * * @param scrubbedEntry entry to determine if an offset is needed for * @return true if an offset would be needed for this entry, false otherwise */ protected boolean generateOffset(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { OriginEntryFull offsetEntry = new OriginEntryFull(); try{ // This code is 3000-OFFSET to SET-OBJECT-2004 in the Cobol LOG.debug("generateOffset() started"); // There was no previous unit of work so we need no offset if (scrubbedEntry == null) { return true; } // If there was an error, don't generate an offset since the record was pulled // and the rest of the document's records will be demerged if (unitOfWork.errorsFound == true) { return true; } // If the offset amount is zero, don't bother to lookup the offset definition ... if (unitOfWork.offsetAmount.isZero()) { return true; } ParameterEvaluator docTypeRule = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.OFFSET_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode()); if (!docTypeRule.evaluationSucceeds()) { return true; } // do nothing if flexible offset is enabled and scrubber offset indicator of the document // type code is turned off in the document type table if (flexibleOffsetAccountService.getEnabled() && !shouldScrubberGenerateOffsetsForDocType(scrubbedEntry.getFinancialDocumentTypeCode())) { return true; } // Create an offset offsetEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); offsetEntry.setTransactionLedgerEntryDescription(offsetDescription); //of course this method should go elsewhere, not in ScrubberValidator! OffsetDefinition offsetDefinition = accountingCycleCachingService.getOffsetDefinition(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialDocumentTypeCode(), scrubbedEntry.getFinancialBalanceTypeCode()); if (offsetDefinition != null) { if (offsetDefinition.getFinancialObject() == null) { StringBuffer offsetKey = new StringBuffer(offsetDefinition.getUniversityFiscalYear()); offsetKey.append("-"); offsetKey.append(offsetDefinition.getChartOfAccountsCode()); offsetKey.append("-"); offsetKey.append(offsetDefinition.getFinancialObjectCode()); putTransactionError(offsetEntry, configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_OBJECT_CODE_NOT_FOUND), offsetKey.toString(), Message.TYPE_FATAL); createOutputEntry(offsetEntry, OUTPUT_ERR_FILE_ps); scrubberReport.incrementErrorRecordWritten(); return false; } offsetEntry.setFinancialObject(offsetDefinition.getFinancialObject()); offsetEntry.setFinancialObjectCode(offsetDefinition.getFinancialObjectCode()); offsetEntry.setFinancialSubObject(null); offsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); } else { StringBuffer sb = new StringBuffer("Unit of work offset "); sb.append(scrubbedEntry.getUniversityFiscalYear()); sb.append("-"); sb.append(scrubbedEntry.getChartOfAccountsCode()); sb.append("-"); sb.append(scrubbedEntry.getFinancialDocumentTypeCode()); sb.append("-"); sb.append(scrubbedEntry.getFinancialBalanceTypeCode()); putTransactionError(offsetEntry, configurationService.getPropertyValueAsString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_NOT_FOUND), sb.toString(), Message.TYPE_FATAL); createOutputEntry(offsetEntry, OUTPUT_ERR_FILE_ps); scrubberReport.incrementErrorRecordWritten(); return false; } offsetEntry.setFinancialObjectTypeCode(offsetEntry.getFinancialObject().getFinancialObjectTypeCode()); offsetEntry.setTransactionLedgerEntryAmount(unitOfWork.offsetAmount); if (unitOfWork.offsetAmount.isPositive()) { offsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); } else { offsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); offsetEntry.setTransactionLedgerEntryAmount(unitOfWork.offsetAmount.negated()); } offsetEntry.setOrganizationDocumentNumber(null); offsetEntry.setOrganizationReferenceId(null); offsetEntry.setReferenceFinancialDocumentTypeCode(null); offsetEntry.setReferenceFinancialSystemOriginationCode(null); offsetEntry.setReferenceFinancialDocumentNumber(null); offsetEntry.setTransactionEncumbranceUpdateCode(null); offsetEntry.setProjectCode(KFSConstants.getDashProjectCode()); offsetEntry.setTransactionDate(getTransactionDateForOffsetEntry(scrubbedEntry)); try { flexibleOffsetAccountService.updateOffset(offsetEntry); } catch (InvalidFlexibleOffsetException e) { if (LOG.isDebugEnabled()) { LOG.debug("generateOffset() Offset Flexible Offset Error: " + e.getMessage()); } putTransactionError(offsetEntry, e.getMessage(), "", Message.TYPE_FATAL); return true; } createOutputEntry(offsetEntry, OUTPUT_GLE_FILE_ps); scrubberReport.incrementOffsetEntryGenerated(); } catch (IOException ioe) { LOG.error("generateOffset() Stopped: " + ioe.getMessage()); throw new RuntimeException("generateOffset() Stopped: " + ioe.getMessage(), ioe); } return true; } protected void createOutputEntry(OriginEntryInformation entry, PrintStream ps) throws IOException { try { ps.printf("%s\n", entry.getLine()); } catch (Exception e) { throw new IOException(e.toString()); } } protected void createOutputEntry(String line, PrintStream ps) throws IOException { try { ps.printf("%s\n", line); } catch (Exception e) { throw new IOException(e.toString()); } } /** * Add an error message to the list of messages for this transaction * * @param errorMessage Error message * @param errorValue Value that is in error * @param type Type of error (Fatal or Warning) */ protected void addTransactionError(String errorMessage, String errorValue, int type) { transactionErrors.add(new Message(errorMessage + " (" + errorValue + ")", type)); } /** * Puts a transaction error into this instance's collection of errors * * @param s a transaction that caused a scrubber error * @param errorMessage the message of what caused the error * @param errorValue the value in error * @param type the type of error */ protected void putTransactionError(Transaction s, String errorMessage, String errorValue, int type) { Message m = new Message(errorMessage + "(" + errorValue + ")", type); scrubberReportWriterService.writeError(s, m); } /** * Determines if the scrubber should generate offsets for the given document type * @param docTypeCode the document type code to check if it generates scrubber offsets * @return true if the scrubber should generate offsets for this doc type, false otherwise */ protected boolean shouldScrubberGenerateOffsetsForDocType(String docTypeCode) { return /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.DOCUMENT_TYPES_REQUIRING_FLEXIBLE_OFFSET_BALANCING_ENTRIES, docTypeCode).evaluationSucceeds(); } /** * A class to hold the current unit of work the scrubber is using */ class UnitOfWorkInfo { // Unit of work key public Integer univFiscalYr = 0; public String finCoaCd = ""; public String accountNbr = ""; public String subAcctNbr = ""; public String finBalanceTypCd = ""; public String fdocTypCd = ""; public String fsOriginCd = ""; public String fdocNbr = ""; public Date fdocReversalDt = new Date(dateTimeService.getCurrentDate().getTime()); public String univFiscalPrdCd = ""; // Data about unit of work public boolean errorsFound = false; public KualiDecimal offsetAmount = KualiDecimal.ZERO; public String scrbFinCoaCd; public String scrbAccountNbr; /** * Constructs a ScrubberProcess.UnitOfWorkInfo instance */ public UnitOfWorkInfo() { } /** * Constructs a ScrubberProcess.UnitOfWorkInfo instance * @param e an origin entry belonging to this unit of work */ public UnitOfWorkInfo(OriginEntryInformation e) { univFiscalYr = e.getUniversityFiscalYear(); finCoaCd = e.getChartOfAccountsCode(); accountNbr = e.getAccountNumber(); subAcctNbr = e.getSubAccountNumber(); finBalanceTypCd = e.getFinancialBalanceTypeCode(); fdocTypCd = e.getFinancialDocumentTypeCode(); fsOriginCd = e.getFinancialSystemOriginationCode(); fdocNbr = e.getDocumentNumber(); fdocReversalDt = e.getFinancialDocumentReversalDate(); univFiscalPrdCd = e.getUniversityFiscalPeriodCode(); } /** * Determines if an entry belongs to this unit of work * * @param e the entry to check * @return true if it belongs to this unit of work, false otherwise */ public boolean isSameUnitOfWork(OriginEntryInformation e) { // Compare the key fields return univFiscalYr.equals(e.getUniversityFiscalYear()) && finCoaCd.equals(e.getChartOfAccountsCode()) && accountNbr.equals(e.getAccountNumber()) && subAcctNbr.equals(e.getSubAccountNumber()) && finBalanceTypCd.equals(e.getFinancialBalanceTypeCode()) && fdocTypCd.equals(e.getFinancialDocumentTypeCode()) && fsOriginCd.equals(e.getFinancialSystemOriginationCode()) && fdocNbr.equals(e.getDocumentNumber()) && ObjectHelper.isEqual(fdocReversalDt, e.getFinancialDocumentReversalDate()) && univFiscalPrdCd.equals(e.getUniversityFiscalPeriodCode()); } /** * Converts this unit of work info to a String * @return a String representation of this UnitOfWorkInfo * @see java.lang.Object#toString() */ @Override public String toString() { return univFiscalYr + finCoaCd + accountNbr + subAcctNbr + finBalanceTypCd + fdocTypCd + fsOriginCd + fdocNbr + fdocReversalDt + univFiscalPrdCd; } /** * Generates the beginning of an OriginEntryFull, based on the unit of work info * * @return a partially initialized OriginEntryFull */ public OriginEntryFull getOffsetTemplate() { OriginEntryFull e = new OriginEntryFull(); e.setUniversityFiscalYear(univFiscalYr); e.setChartOfAccountsCode(finCoaCd); e.setAccountNumber(accountNbr); e.setSubAccountNumber(subAcctNbr); e.setFinancialBalanceTypeCode(finBalanceTypCd); e.setFinancialDocumentTypeCode(fdocTypCd); e.setFinancialSystemOriginationCode(fsOriginCd); e.setDocumentNumber(fdocNbr); e.setFinancialDocumentReversalDate(fdocReversalDt); e.setUniversityFiscalPeriodCode(univFiscalPrdCd); return e; } } /** * An internal class to hold errors encountered by the scrubber */ class TransactionError { public Transaction transaction; public Message message; /** * Constructs a ScrubberProcess.TransactionError instance * @param t the transaction that had the error * @param m a message about the error */ public TransactionError(Transaction t, Message m) { transaction = t; message = m; } } /** * This method modifies the run date if it is before the cutoff time specified by the RunTimeService See * KULRNE-70 This method is public to facilitate unit testing * * @param currentDate the date the scrubber should report as having run on * @return the run date */ @Override public Date calculateRunDate(java.util.Date currentDate) { return new Date(runDateService.calculateRunDate(currentDate).getTime()); } protected boolean checkingBypassEntry (String financialBalanceTypeCode, String desc, DemergerReportData demergerReport){ String transactionType = getTransactionType(financialBalanceTypeCode, desc); if (TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE.equals(transactionType)) { demergerReport.incrementCostShareEncumbranceTransactionsBypassed(); return true; } else if (TRANSACTION_TYPE_OFFSET.equals(transactionType)) { demergerReport.incrementOffsetTransactionsBypassed(); return true; } else if (TRANSACTION_TYPE_CAPITALIZATION.equals(transactionType)) { demergerReport.incrementCapitalizationTransactionsBypassed(); return true; } else if (TRANSACTION_TYPE_LIABILITY.equals(transactionType)) { demergerReport.incrementLiabilityTransactionsBypassed(); return true; } else if (TRANSACTION_TYPE_TRANSFER.equals(transactionType)) { demergerReport.incrementTransferTransactionsBypassed(); return true; } else if (TRANSACTION_TYPE_COST_SHARE.equals(transactionType)) { demergerReport.incrementCostShareTransactionsBypassed(); return true; } return false; } protected String checkAndSetTransactionTypeCostShare (String financialBalanceTypeCode, String desc, String currentValidLine){ // Read all the transactions in the valid group and update the cost share transactions String transactionType = getTransactionType(financialBalanceTypeCode, desc); if (TRANSACTION_TYPE_COST_SHARE.equals(transactionType)) { OriginEntryFull transaction = new OriginEntryFull(); transaction.setFromTextFileForBatch(currentValidLine, 0); transaction.setFinancialDocumentTypeCode(KFSConstants.TRANSFER_FUNDS); transaction.setFinancialSystemOriginationCode(KFSConstants.SubAccountType.COST_SHARE); StringBuffer docNbr = new StringBuffer(COST_SHARE_CODE); docNbr.append(desc.substring(36, 38)); docNbr.append("/"); docNbr.append(desc.substring(38, 40)); transaction.setDocumentNumber(docNbr.toString()); transaction.setTransactionLedgerEntryDescription(desc.substring(0, DEMERGER_TRANSACTION_LEDGET_ENTRY_DESCRIPTION)); currentValidLine = transaction.getLine(); } return currentValidLine; } /** * Generates the scrubber listing report for the GLCP document * @param documentNumber the document number of the GLCP document */ protected void generateScrubberTransactionListingReport(String documentNumber, String inputFileName) { try { scrubberListingReportWriterService.setDocumentNumber(documentNumber); ((WrappingBatchService) scrubberListingReportWriterService).initialize(); new TransactionListingReport().generateReport(scrubberListingReportWriterService, new OriginEntryFileIterator(new File(inputFileName))); } finally { ((WrappingBatchService) scrubberListingReportWriterService).destroy(); } } /** * Generates the scrubber report that lists out the input origin entries with blank balance type codes. */ protected void generateScrubberBlankBalanceTypeCodeReport(String inputFileName) { OriginEntryFilter blankBalanceTypeFilter = new OriginEntryFilter() { /** * @see org.kuali.kfs.gl.batch.service.impl.FilteringOriginEntryFileIterator.OriginEntryFilter#accept(org.kuali.kfs.gl.businessobject.OriginEntryFull) */ @Override public boolean accept(OriginEntryFull originEntry) { boolean acceptFlag = false; String financialBalancetype = originEntry.getFinancialBalanceTypeCode(); BalanceType originEntryBalanceType = accountingCycleCachingService.getBalanceType(financialBalancetype); if (ObjectUtils.isNull(originEntryBalanceType)) { acceptFlag = true; for (int i= 0; i < financialBalancetype.length(); i++) { if (financialBalancetype.charAt(i) != ' ') { acceptFlag = false; break;} } } return acceptFlag; } }; Iterator<OriginEntryFull> blankBalanceOriginEntries = new FilteringOriginEntryFileIterator(new File(inputFileName), blankBalanceTypeFilter); new TransactionListingReport().generateReport(scrubberBadBalanceListingReportWriterService, blankBalanceOriginEntries); } protected void generateDemergerRemovedTransactionsReport(String errorFileName) { OriginEntryFileIterator removedTransactions = new OriginEntryFileIterator(new File(errorFileName)); new TransactionListingReport().generateReport(demergerRemovedTransactionsListingReportWriterService, removedTransactions); } protected void handleTransactionError(Transaction errorTransaction, Message message) { if (collectorMode) { List<Message> messages = scrubberReportErrors.get(errorTransaction); if (messages == null) { messages = new ArrayList<Message>(); scrubberReportErrors.put(errorTransaction, messages); } messages.add(message); } else { scrubberReportWriterService.writeError(errorTransaction, message); } } protected void handleTransactionErrors(Transaction errorTransaction, List<Message> messages) { if (collectorMode) { for (Message message : messages) { handleTransactionError(errorTransaction, message); } } else { if (LOG.isDebugEnabled()) { LOG.debug("Errors on transaction: "+errorTransaction); for (Message message: messages) { LOG.debug(message); } } scrubberReportWriterService.writeError(errorTransaction, messages); } } protected void handleEndOfScrubberReport(ScrubberReportData scrubberReport) { if (!collectorMode) { scrubberReportWriterService.writeStatisticLine("UNSCRUBBED RECORDS READ %,9d", scrubberReport.getNumberOfUnscrubbedRecordsRead()); scrubberReportWriterService.writeStatisticLine("SCRUBBED RECORDS WRITTEN %,9d", scrubberReport.getNumberOfScrubbedRecordsWritten()); scrubberReportWriterService.writeStatisticLine("ERROR RECORDS WRITTEN %,9d", scrubberReport.getNumberOfErrorRecordsWritten()); scrubberReportWriterService.writeStatisticLine("OFFSET ENTRIES GENERATED %,9d", scrubberReport.getNumberOfOffsetEntriesGenerated()); scrubberReportWriterService.writeStatisticLine("CAPITALIZATION ENTRIES GENERATED %,9d", scrubberReport.getNumberOfCapitalizationEntriesGenerated()); scrubberReportWriterService.writeStatisticLine("LIABILITY ENTRIES GENERATED %,9d", scrubberReport.getNumberOfLiabilityEntriesGenerated()); scrubberReportWriterService.writeStatisticLine("PLANT INDEBTEDNESS ENTRIES GENERATED %,9d", scrubberReport.getNumberOfPlantIndebtednessEntriesGenerated()); scrubberReportWriterService.writeStatisticLine("COST SHARE ENTRIES GENERATED %,9d", scrubberReport.getNumberOfCostShareEntriesGenerated()); scrubberReportWriterService.writeStatisticLine("COST SHARE ENC ENTRIES GENERATED %,9d", scrubberReport.getNumberOfCostShareEncumbrancesGenerated()); scrubberReportWriterService.writeStatisticLine("TOTAL OUTPUT RECORDS WRITTEN %,9d", scrubberReport.getTotalNumberOfRecordsWritten()); scrubberReportWriterService.writeStatisticLine("EXPIRED ACCOUNTS FOUND %,9d", scrubberReport.getNumberOfExpiredAccountsFound()); } } protected void handleDemergerSaveValidEntry(String entryString) { if (collectorMode) { OriginEntryInformation tempEntry = new OriginEntryFull(entryString); ledgerSummaryReport.summarizeEntry(tempEntry); } } /** * Sets the batchFileDirectoryName attribute value. * @param batchFileDirectoryName The batchFileDirectoryName to set. */ public void setBatchFileDirectoryName(String batchFileDirectoryName) { this.batchFileDirectoryName = batchFileDirectoryName; } /** * Gets the transferDescription attribute. * @return Returns the transferDescription. */ public String getTransferDescription() { return transferDescription; } /** * Sets the transferDescription attribute value. * @param transferDescription The transferDescription to set. */ public void setTransferDescription(String transferDescription) { this.transferDescription = transferDescription; } /** * Sets the dateTimeService attribute value. * @param dateTimeService The dateTimeService to set. */ public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } /** * Sets the flexibleOffsetAccountService attribute value. * @param flexibleOffsetAccountService The flexibleOffsetAccountService to set. */ public void setFlexibleOffsetAccountService(FlexibleOffsetAccountService flexibleOffsetAccountService) { this.flexibleOffsetAccountService = flexibleOffsetAccountService; } /** * Sets the configurationService attribute value. * @param configurationService The configurationService to set. */ public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } /** * Sets the persistenceService attribute value. * @param persistenceService The persistenceService to set. */ public void setPersistenceService(PersistenceService persistenceService) { this.persistenceService = persistenceService; } /** * Sets the scrubberValidator attribute value. * @param scrubberValidator The scrubberValidator to set. */ public void setScrubberValidator(ScrubberValidator scrubberValidator) { this.scrubberValidator = scrubberValidator; } /** * Sets the accountingCycleCachingService attribute value. * @param accountingCycleCachingService The accountingCycleCachingService to set. */ public void setAccountingCycleCachingService(AccountingCycleCachingService accountingCycleCachingService) { this.accountingCycleCachingService = accountingCycleCachingService; } /** * Sets the scrubberReportWriterService attribute value. * @param scrubberReportWriterService The scrubberReportWriterService to set. */ public void setScrubberReportWriterService(DocumentNumberAwareReportWriterService scrubberReportWriterService) { this.scrubberReportWriterService = scrubberReportWriterService; } /** * Sets the scrubberLedgerReportWriterService attribute value. * @param scrubberLedgerReportWriterService The scrubberLedgerReportWriterService to set. */ public void setScrubberLedgerReportWriterService(DocumentNumberAwareReportWriterService scrubberLedgerReportWriterService) { this.scrubberLedgerReportWriterService = scrubberLedgerReportWriterService; } /** * Sets the scrubberListingReportWriterService attribute value. * @param scrubberListingReportWriterService The scrubberListingReportWriterService to set. */ public void setScrubberListingReportWriterService(DocumentNumberAwareReportWriterService scrubberListingReportWriterService) { this.scrubberListingReportWriterService = scrubberListingReportWriterService; } /** * Sets the scrubberBadBalanceListingReportWriterService attribute value. * @param scrubberBadBalanceListingReportWriterService The scrubberBadBalanceListingReportWriterService to set. */ public void setScrubberBadBalanceListingReportWriterService(ReportWriterService scrubberBadBalanceListingReportWriterService) { this.scrubberBadBalanceListingReportWriterService = scrubberBadBalanceListingReportWriterService; } /** * Sets the demergerRemovedTransactionsListingReportWriterService attribute value. * @param demergerRemovedTransactionsListingReportWriterService The demergerRemovedTransactionsListingReportWriterService to set. */ public void setDemergerRemovedTransactionsListingReportWriterService(ReportWriterService demergerRemovedTransactionsListingReportWriterService) { this.demergerRemovedTransactionsListingReportWriterService = demergerRemovedTransactionsListingReportWriterService; } /** * Sets the demergerReportWriterService attribute value. * @param demergerReportWriterService The demergerReportWriterService to set. */ public void setDemergerReportWriterService(ReportWriterService demergerReportWriterService) { this.demergerReportWriterService = demergerReportWriterService; } /** * Sets the preScrubberService attribute value. * @param preScrubberService The preScrubberService to set. */ public void setPreScrubberService(PreScrubberService preScrubberService) { this.preScrubberService = preScrubberService; } /** * Sets the parameterService attribute value. * @param parameterService The parameterService to set. */ public void setParameterService(ParameterService parameterService) { this.parameterService = parameterService; } /** * Sets the runDateService attribute value. * @param runDateService The runDateService to set. */ public void setRunDateService(RunDateService runDateService) { this.runDateService = runDateService; } /** * Gets the flexibleOffsetAccountService attribute. * @return Returns the flexibleOffsetAccountService. */ public FlexibleOffsetAccountService getFlexibleOffsetAccountService() { return flexibleOffsetAccountService; } /** * Gets the dateTimeService attribute. * @return Returns the dateTimeService. */ public DateTimeService getDateTimeService() { return dateTimeService; } /** * Gets the configurationService attribute. * @return Returns the configurationService. */ public ConfigurationService getConfigurationService() { return configurationService; } /** * Gets the persistenceService attribute. * @return Returns the persistenceService. */ public PersistenceService getPersistenceService() { return persistenceService; } /** * Gets the scrubberValidator attribute. * @return Returns the scrubberValidator. */ public ScrubberValidator getScrubberValidator() { return scrubberValidator; } /** * Gets the runDateService attribute. * @return Returns the runDateService. */ public RunDateService getRunDateService() { return runDateService; } /** * Gets the accountingCycleCachingService attribute. * @return Returns the accountingCycleCachingService. */ public AccountingCycleCachingService getAccountingCycleCachingService() { return accountingCycleCachingService; } /** * Gets the scrubberReportWriterService attribute. * @return Returns the scrubberReportWriterService. */ public DocumentNumberAwareReportWriterService getScrubberReportWriterService() { return scrubberReportWriterService; } /** * Gets the scrubberLedgerReportWriterService attribute. * @return Returns the scrubberLedgerReportWriterService. */ public DocumentNumberAwareReportWriterService getScrubberLedgerReportWriterService() { return scrubberLedgerReportWriterService; } /** * Gets the scrubberListingReportWriterService attribute. * @return Returns the scrubberListingReportWriterService. */ public DocumentNumberAwareReportWriterService getScrubberListingReportWriterService() { return scrubberListingReportWriterService; } /** * Gets the scrubberBadBalanceListingReportWriterService attribute. * @return Returns the scrubberBadBalanceListingReportWriterService. */ public ReportWriterService getScrubberBadBalanceListingReportWriterService() { return scrubberBadBalanceListingReportWriterService; } /** * Gets the demergerRemovedTransactionsListingReportWriterService attribute. * @return Returns the demergerRemovedTransactionsListingReportWriterService. */ public ReportWriterService getDemergerRemovedTransactionsListingReportWriterService() { return demergerRemovedTransactionsListingReportWriterService; } /** * Gets the demergerReportWriterService attribute. * @return Returns the demergerReportWriterService. */ public ReportWriterService getDemergerReportWriterService() { return demergerReportWriterService; } /** * Gets the preScrubberService attribute. * @return Returns the preScrubberService. */ public PreScrubberService getPreScrubberService() { return preScrubberService; } /** * Gets the parameterService attribute. * @return Returns the parameterService. */ public ParameterService getParameterService() { return parameterService; } /** * Sets the preScrubberReportWriterService attribute value. * @param preScrubberReportWriterService The preScrubberReportWriterService to set. */ public void setPreScrubberReportWriterService(DocumentNumberAwareReportWriterService preScrubberReportWriterService) { this.preScrubberReportWriterService = preScrubberReportWriterService; } /** * Sets the businessObjectService attribute value. * @param businessObjectService The businessObjectService to set. */ public void setBusinessObjectService(BusinessObjectService businessObjectService) { this.businessObjectService = businessObjectService; } // Offset entry to have the same transaction date as the original transaction for Payroll Posting protected Date getTransactionDateForOffsetEntry(OriginEntryInformation scrubbedEntry) { if (getParameterService().parameterExists(ScrubberStep.class, KFSParameterKeyConstants.GeneralLedgerSysParmeterKeys.TRANSACTION_DATE_BYPASS_ORIGINATIONS)) { Collection<String> transactionDateAutoAssignmentBypassOriginCodes = getParameterService().getParameterValuesAsString(ScrubberStep.class, KFSParameterKeyConstants.GeneralLedgerSysParmeterKeys.TRANSACTION_DATE_BYPASS_ORIGINATIONS); String originationCode = scrubbedEntry.getFinancialSystemOriginationCode(); if (transactionDateAutoAssignmentBypassOriginCodes.contains(originationCode)) { return scrubbedEntry.getTransactionDate(); } } return this.runDate; } }