001 /* 002 * Copyright 2011 The Kuali Foundation. 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.kfs.gl.batch.service.impl; 017 018 import java.io.BufferedReader; 019 import java.io.File; 020 import java.io.FileNotFoundException; 021 import java.io.FileReader; 022 import java.io.IOException; 023 import java.io.PrintStream; 024 import java.sql.Date; 025 import java.text.NumberFormat; 026 import java.util.ArrayList; 027 import java.util.Calendar; 028 import java.util.HashMap; 029 import java.util.IdentityHashMap; 030 import java.util.Iterator; 031 import java.util.List; 032 import java.util.Map; 033 034 import org.apache.commons.io.FileUtils; 035 import org.apache.commons.io.LineIterator; 036 import org.kuali.kfs.coa.businessobject.A21SubAccount; 037 import org.kuali.kfs.coa.businessobject.Account; 038 import org.kuali.kfs.coa.businessobject.BalanceType; 039 import org.kuali.kfs.coa.businessobject.Chart; 040 import org.kuali.kfs.coa.businessobject.ObjectCode; 041 import org.kuali.kfs.coa.businessobject.OffsetDefinition; 042 import org.kuali.kfs.gl.GeneralLedgerConstants; 043 import org.kuali.kfs.gl.ObjectHelper; 044 import org.kuali.kfs.gl.batch.BatchSortUtil; 045 import org.kuali.kfs.gl.batch.CollectorBatch; 046 import org.kuali.kfs.gl.batch.DemergerSortComparator; 047 import org.kuali.kfs.gl.batch.ScrubberSortComparator; 048 import org.kuali.kfs.gl.batch.ScrubberStep; 049 import org.kuali.kfs.gl.batch.service.AccountingCycleCachingService; 050 import org.kuali.kfs.gl.batch.service.RunDateService; 051 import org.kuali.kfs.gl.batch.service.ScrubberProcess; 052 import org.kuali.kfs.gl.batch.service.impl.FilteringOriginEntryFileIterator.OriginEntryFilter; 053 import org.kuali.kfs.gl.businessobject.DemergerReportData; 054 import org.kuali.kfs.gl.businessobject.OriginEntryFieldUtil; 055 import org.kuali.kfs.gl.businessobject.OriginEntryFull; 056 import org.kuali.kfs.gl.businessobject.OriginEntryInformation; 057 import org.kuali.kfs.gl.businessobject.Transaction; 058 import org.kuali.kfs.gl.report.CollectorReportData; 059 import org.kuali.kfs.gl.report.LedgerSummaryReport; 060 import org.kuali.kfs.gl.report.PreScrubberReport; 061 import org.kuali.kfs.gl.report.PreScrubberReportData; 062 import org.kuali.kfs.gl.report.TransactionListingReport; 063 import org.kuali.kfs.gl.service.PreScrubberService; 064 import org.kuali.kfs.gl.service.ScrubberReportData; 065 import org.kuali.kfs.gl.service.ScrubberValidator; 066 import org.kuali.kfs.gl.service.impl.ScrubberStatus; 067 import org.kuali.kfs.gl.service.impl.StringHelper; 068 import org.kuali.kfs.sys.KFSConstants; 069 import org.kuali.kfs.sys.KFSKeyConstants; 070 import org.kuali.kfs.sys.KFSPropertyConstants; 071 import org.kuali.kfs.sys.Message; 072 import org.kuali.kfs.sys.KFSParameterKeyConstants.GlParameterConstants; 073 import org.kuali.kfs.sys.batch.service.WrappingBatchService; 074 import org.kuali.kfs.sys.businessobject.SystemOptions; 075 import org.kuali.kfs.sys.businessobject.UniversityDate; 076 import org.kuali.kfs.sys.exception.InvalidFlexibleOffsetException; 077 import org.kuali.kfs.sys.service.DocumentNumberAwareReportWriterService; 078 import org.kuali.kfs.sys.service.FlexibleOffsetAccountService; 079 import org.kuali.kfs.sys.service.ReportWriterService; 080 import org.kuali.rice.kns.service.BusinessObjectService; 081 import org.kuali.rice.kns.service.DateTimeService; 082 import org.kuali.rice.kns.service.KualiConfigurationService; 083 import org.kuali.rice.kns.service.ParameterEvaluator; 084 import org.kuali.rice.kns.service.ParameterService; 085 import org.kuali.rice.kns.service.PersistenceService; 086 import org.kuali.rice.kns.util.KualiDecimal; 087 import org.kuali.rice.kns.util.ObjectUtils; 088 import org.springframework.util.StringUtils; 089 090 /** 091 * This class has the logic for the scrubber. It is required because the scrubber process needs instance variables. Instance 092 * variables in a spring service are shared between all code calling the service. This will make sure each run of the scrubber has 093 * it's own instance variables instead of being shared. 094 */ 095 public class ScrubberProcessImpl implements ScrubberProcess { 096 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ScrubberProcessImpl.class); 097 098 private static final String TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE = "CE"; 099 private static final String TRANSACTION_TYPE_OFFSET = "O"; 100 private static final String TRANSACTION_TYPE_CAPITALIZATION = "C"; 101 private static final String TRANSACTION_TYPE_LIABILITY = "L"; 102 private static final String TRANSACTION_TYPE_TRANSFER = "T"; 103 private static final String TRANSACTION_TYPE_COST_SHARE = "CS"; 104 private static final String TRANSACTION_TYPE_OTHER = "X"; 105 106 enum GROUP_TYPE {VALID, ERROR, EXPIRED} 107 108 private static final String COST_SHARE_CODE = "CSHR"; 109 110 private static final String COST_SHARE_TRANSFER_ENTRY_IND = "***"; 111 112 // These lengths are different then database field lengths, hence they are not from the DD 113 private static final int COST_SHARE_ENCUMBRANCE_ENTRY_MAXLENGTH = 28; 114 private static final int DEMERGER_TRANSACTION_LEDGET_ENTRY_DESCRIPTION = 33; 115 private static final int OFFSET_MESSAGE_MAXLENGTH = 33; 116 117 /* Services required */ 118 private FlexibleOffsetAccountService flexibleOffsetAccountService; 119 private DateTimeService dateTimeService; 120 private KualiConfigurationService configurationService; 121 private PersistenceService persistenceService; 122 private ScrubberValidator scrubberValidator; 123 private RunDateService runDateService; 124 private AccountingCycleCachingService accountingCycleCachingService; 125 private DocumentNumberAwareReportWriterService scrubberReportWriterService; 126 private DocumentNumberAwareReportWriterService scrubberLedgerReportWriterService; 127 private DocumentNumberAwareReportWriterService scrubberListingReportWriterService; 128 protected DocumentNumberAwareReportWriterService preScrubberReportWriterService; 129 private ReportWriterService scrubberBadBalanceListingReportWriterService; 130 private ReportWriterService demergerRemovedTransactionsListingReportWriterService; 131 private ReportWriterService demergerReportWriterService; 132 private PreScrubberService preScrubberService; 133 134 // these three members will only be populated when in collector mode, otherwise the memory requirements will be huge 135 private Map<OriginEntryInformation, OriginEntryInformation> unscrubbedToScrubbedEntries = new HashMap<OriginEntryInformation, OriginEntryInformation>(); 136 private Map<Transaction, List<Message>> scrubberReportErrors = new IdentityHashMap<Transaction, List<Message>>(); 137 private LedgerSummaryReport ledgerSummaryReport = new LedgerSummaryReport(); 138 139 private ScrubberReportData scrubberReport; 140 private DemergerReportData demergerReport; 141 142 /* These are all different forms of the run date for this job */ 143 private Date runDate; 144 private Calendar runCal; 145 private UniversityDate universityRunDate; 146 private String offsetString; 147 148 /* Unit Of Work info */ 149 private UnitOfWorkInfo unitOfWork; 150 private KualiDecimal scrubCostShareAmount; 151 152 /* Statistics for the reports */ 153 private List<Message> transactionErrors; 154 155 /* Description names */ 156 private String offsetDescription; 157 private String capitalizationDescription; 158 private String liabilityDescription; 159 private String transferDescription; 160 private String costShareDescription; 161 162 private ParameterService parameterService; 163 private BusinessObjectService businessObjectService; 164 165 /** 166 * Whether this instance is being used to support the scrubbing of a collector batch 167 */ 168 private boolean collectorMode; 169 private String batchFileDirectoryName; 170 171 PrintStream OUTPUT_GLE_FILE_ps; 172 PrintStream OUTPUT_ERR_FILE_ps; 173 PrintStream OUTPUT_EXP_FILE_ps; 174 175 private String inputFile; 176 private String validFile; 177 private String errorFile; 178 private String expiredFile; 179 180 /** 181 * Scrub this single group read only. This will only output the scrubber report. It won't output any other groups. 182 * 183 * @param group the origin entry group that should be scrubbed 184 * @param the document number of any specific entries to scrub 185 */ 186 public void scrubGroupReportOnly(String fileName, String documentNumber) { 187 LOG.debug("scrubGroupReportOnly() started"); 188 String unsortedFile = fileName; 189 this.inputFile = fileName + ".sort"; 190 this.validFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 191 this.errorFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 192 this.expiredFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_EXPIRED_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 193 String prescrubOutput = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.PRE_SCRUBBER_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 194 this.ledgerSummaryReport = new LedgerSummaryReport(); 195 runDate = calculateRunDate(dateTimeService.getCurrentDate()); 196 197 PreScrubberReportData preScrubberReportData = null; 198 199 // run pre-scrubber on the raw input into the sort process 200 LineIterator inputEntries = null; 201 try { 202 inputEntries = FileUtils.lineIterator(new File(unsortedFile)); 203 preScrubberReportData = preScrubberService.preprocessOriginEntries(inputEntries, prescrubOutput); 204 } 205 catch (IOException e1) { 206 LOG.error("Error encountered trying to prescrub GLCP/LLCP document", e1); 207 throw new RuntimeException("Error encountered trying to prescrub GLCP/LLCP document", e1); 208 } 209 finally { 210 LineIterator.closeQuietly(inputEntries); 211 } 212 if (preScrubberReportData != null) { 213 preScrubberReportWriterService.setDocumentNumber(documentNumber); 214 ((WrappingBatchService)preScrubberReportWriterService).initialize(); 215 try { 216 new PreScrubberReport().generateReport(preScrubberReportData, preScrubberReportWriterService); 217 } 218 finally { 219 ((WrappingBatchService)preScrubberReportWriterService).destroy(); 220 } 221 } 222 BatchSortUtil.sortTextFileWithFields(prescrubOutput, inputFile, new ScrubberSortComparator()); 223 224 scrubEntries(true, documentNumber); 225 226 // delete files 227 File deleteSortFile = new File(inputFile); 228 File deleteValidFile = new File(validFile); 229 File deleteErrorFile = new File(errorFile); 230 File deleteExpiredFile = new File(expiredFile); 231 try { 232 deleteSortFile.delete(); 233 deleteValidFile.delete(); 234 deleteErrorFile.delete(); 235 deleteExpiredFile.delete(); 236 } catch (Exception e){ 237 LOG.error("scrubGroupReportOnly delete output files process Stopped: " + e.getMessage()); 238 throw new RuntimeException("scrubGroupReportOnly delete output files process Stopped: " + e.getMessage(), e); 239 } 240 } 241 242 /** 243 * Scrubs all entries in all groups and documents. 244 */ 245 public void scrubEntries() { 246 this.inputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 247 this.validFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 248 this.errorFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 249 this.expiredFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_EXPIRED_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 250 runDate = calculateRunDate(dateTimeService.getCurrentDate()); 251 252 scrubEntries(false, null); 253 } 254 255 /** 256 * Scrubs the origin entry and ID billing details if the given batch. Store all scrubber output into the collectorReportData 257 * parameter. NOTE: DO NOT CALL ANY OF THE scrub* METHODS OF THIS CLASS AFTER CALLING THIS METHOD FOR EVERY UNIQUE INSTANCE OF 258 * THIS CLASS, OR THE COLLECTOR REPORTS MAY BE CORRUPTED 259 * 260 * @param batch the data gathered from a Collector file 261 * @param collectorReportData the statistics generated by running the Collector 262 */ 263 public void scrubCollectorBatch(ScrubberStatus scrubberStatus, CollectorBatch batch, CollectorReportData collectorReportData) { 264 collectorMode = true; 265 266 this.inputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 267 this.validFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 268 this.errorFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 269 this.expiredFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_EXPIRED_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 270 runDate = calculateRunDate(dateTimeService.getCurrentDate()); 271 272 this.ledgerSummaryReport = collectorReportData.getLedgerSummaryReport(); 273 274 // sort input file 275 String scrubberSortInputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_BACKUP_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 276 String scrubberSortOutputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 277 BatchSortUtil.sortTextFileWithFields(scrubberSortInputFile, scrubberSortOutputFile, new ScrubberSortComparator()); 278 279 scrubEntries(false, null); 280 281 //sort scrubber error file for demerger 282 String demergerSortInputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 283 String demergerSortOutputFile = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_ERROR_SORTED_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 284 BatchSortUtil.sortTextFileWithFields(demergerSortInputFile, demergerSortOutputFile, new DemergerSortComparator()); 285 286 performDemerger(); 287 288 // the scrubber process has just updated several member variables of this class. Store these values for the collector report 289 collectorReportData.setBatchOriginEntryScrubberErrors(batch, scrubberReportErrors); 290 collectorReportData.setScrubberReportData(batch, scrubberReport); 291 collectorReportData.setDemergerReportData(batch, demergerReport); 292 293 // report purpose - commented out. If we need, the put string values for fileNames. 294 scrubberStatus.setInputFileName(GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION); 295 scrubberStatus.setValidFileName(GeneralLedgerConstants.BatchFileSystem.COLLECTOR_DEMERGER_VAILD_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION); 296 scrubberStatus.setErrorFileName(GeneralLedgerConstants.BatchFileSystem.COLLECTOR_DEMERGER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION); 297 scrubberStatus.setExpiredFileName(GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_EXPIRED_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION); 298 scrubberStatus.setUnscrubbedToScrubbedEntries(unscrubbedToScrubbedEntries); 299 } 300 301 /** 302 * Scrub all entries that need it in origin entry. Put valid scrubbed entries in a scrubber valid group, put errors in a 303 * scrubber error group, and transactions with an expired account in the scrubber expired account group. 304 * @param group the specific origin entry group to scrub 305 * @param documentNumber the number of the document with entries to scrub 306 */ 307 public void scrubEntries(boolean reportOnlyMode, String documentNumber) { 308 LOG.debug("scrubEntries() started"); 309 310 if (reportOnlyMode) { 311 scrubberReportWriterService.setDocumentNumber(documentNumber); 312 scrubberLedgerReportWriterService.setDocumentNumber(documentNumber); 313 } 314 315 // setup an object to hold the "default" date information 316 runDate = calculateRunDate(dateTimeService.getCurrentDate()); 317 runCal = Calendar.getInstance(); 318 runCal.setTime(runDate); 319 320 universityRunDate = accountingCycleCachingService.getUniversityDate(runDate); 321 if (universityRunDate == null) { 322 throw new IllegalStateException(configurationService.getPropertyString(KFSKeyConstants.ERROR_UNIV_DATE_NOT_FOUND)); 323 } 324 325 setOffsetString(); 326 setDescriptions(); 327 scrubberReport = new ScrubberReportData(); 328 329 try { 330 if (!collectorMode) { 331 ((WrappingBatchService) scrubberReportWriterService).initialize(); 332 ((WrappingBatchService) scrubberLedgerReportWriterService).initialize(); 333 } 334 335 processGroup(reportOnlyMode, scrubberReport); 336 337 if (reportOnlyMode) { 338 generateScrubberTransactionListingReport(documentNumber, inputFile); 339 } 340 else if (collectorMode) { 341 // defer report generation for later 342 } 343 else { 344 generateScrubberBlankBalanceTypeCodeReport(inputFile); 345 } 346 } 347 finally { 348 if (!collectorMode) { 349 ((WrappingBatchService) scrubberReportWriterService).destroy(); 350 ((WrappingBatchService) scrubberLedgerReportWriterService).destroy(); 351 } 352 } 353 } 354 355 /** 356 * The demerger process reads all of the documents in the error group, then moves all of the original entries for that document 357 * from the valid group to the error group. It does not move generated entries to the error group. Those are deleted. It also 358 * modifies the doc number and origin code of cost share transfers. 359 * 360 * @param errorGroup this scrubber run's error group 361 * @param validGroup this scrubber run's valid group 362 */ 363 public void performDemerger() { 364 LOG.debug("performDemerger() started"); 365 366 OriginEntryFieldUtil oefu = new OriginEntryFieldUtil(); 367 Map<String, Integer> pMap = oefu.getFieldBeginningPositionMap(); 368 369 // Without this step, the job fails with Optimistic Lock Exceptions 370 persistenceService.clearCache(); 371 372 demergerReport = new DemergerReportData(); 373 374 // set runDate here again, because demerger is calling outside from scrubber 375 runDate = calculateRunDate(dateTimeService.getCurrentDate()); 376 runCal = Calendar.getInstance(); 377 runCal.setTime(runDate); 378 379 // demerger called by outside from scrubber, so reset those values 380 setOffsetString(); 381 setDescriptions(); 382 383 // new demerger starts 384 385 String validOutputFilename = null; 386 String errorOutputFilename = null; 387 388 String demergerValidOutputFilename = null; 389 String demergerErrorOutputFilename = null; 390 391 if(!collectorMode){ 392 validOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 393 errorOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.SCRUBBER_ERROR_SORTED_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 394 395 demergerValidOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.DEMERGER_VAILD_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 396 demergerErrorOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.DEMERGER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 397 398 } else { 399 400 validOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_VALID_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 401 errorOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_SCRUBBER_ERROR_SORTED_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 402 403 demergerValidOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_DEMERGER_VAILD_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 404 demergerErrorOutputFilename = batchFileDirectoryName + File.separator + GeneralLedgerConstants.BatchFileSystem.COLLECTOR_DEMERGER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION; 405 } 406 407 // Without this step, the job fails with Optimistic Lock Exceptions 408 persistenceService.clearCache(); 409 410 FileReader INPUT_GLE_FILE = null; 411 FileReader INPUT_ERR_FILE = null; 412 BufferedReader INPUT_GLE_FILE_br; 413 BufferedReader INPUT_ERR_FILE_br; 414 PrintStream OUTPUT_DEMERGER_GLE_FILE_ps; 415 PrintStream OUTPUT_DEMERGER_ERR_FILE_ps; 416 417 try { 418 INPUT_GLE_FILE = new FileReader(validOutputFilename); 419 INPUT_ERR_FILE = new FileReader(errorOutputFilename); 420 } 421 catch (FileNotFoundException e) { 422 throw new RuntimeException(e); 423 } 424 try { 425 OUTPUT_DEMERGER_GLE_FILE_ps = new PrintStream(demergerValidOutputFilename); 426 OUTPUT_DEMERGER_ERR_FILE_ps = new PrintStream(demergerErrorOutputFilename); 427 } 428 catch (IOException e) { 429 throw new RuntimeException(e); 430 } 431 432 int validSaved = 0; 433 int errorSaved = 0; 434 435 int validReadLine = 0; 436 int errorReadLine = 0; 437 438 boolean errorsLoading = false; 439 INPUT_GLE_FILE_br = new BufferedReader(INPUT_GLE_FILE); 440 INPUT_ERR_FILE_br = new BufferedReader(INPUT_ERR_FILE); 441 442 try { 443 String currentValidLine = INPUT_GLE_FILE_br.readLine(); 444 String currentErrorLine = INPUT_ERR_FILE_br.readLine(); 445 446 boolean meetFlag = false; 447 448 while (currentValidLine != null || currentErrorLine != null) { 449 450 // Demerger only catch IOexception since demerger report doesn't display 451 // detail error message. 452 try{ 453 //validLine is null means that errorLine is not null 454 if (org.apache.commons.lang.StringUtils.isEmpty(currentValidLine)) { 455 String errorDesc = currentErrorLine.substring(pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_DESC), pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT)); 456 String errorFinancialBalanceTypeCode = currentErrorLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE)); 457 458 if (!checkingBypassEntry(errorFinancialBalanceTypeCode, errorDesc, demergerReport)){ 459 createOutputEntry(currentErrorLine, OUTPUT_DEMERGER_ERR_FILE_ps); 460 errorSaved++; 461 } 462 currentErrorLine = INPUT_ERR_FILE_br.readLine(); 463 errorReadLine++; 464 continue; 465 } 466 467 String financialBalanceTypeCode = currentValidLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE)); 468 String desc = currentValidLine.substring(pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_DESC), pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT)); 469 470 //errorLine is null means that validLine is not null 471 if (org.apache.commons.lang.StringUtils.isEmpty(currentErrorLine)) { 472 // Read all the transactions in the valid group and update the cost share transactions 473 String updatedValidLine = checkAndSetTransactionTypeCostShare(financialBalanceTypeCode, desc, currentValidLine); 474 createOutputEntry(updatedValidLine, OUTPUT_DEMERGER_GLE_FILE_ps); 475 handleDemergerSaveValidEntry(updatedValidLine); 476 validSaved++; 477 currentValidLine = INPUT_GLE_FILE_br.readLine(); 478 validReadLine++; 479 continue; 480 } 481 482 String compareStringFromValidEntry = currentValidLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE), pMap.get(KFSPropertyConstants.TRANSACTION_ENTRY_SEQUENCE_NUMBER)); 483 String compareStringFromErrorEntry = currentErrorLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE), pMap.get(KFSPropertyConstants.TRANSACTION_ENTRY_SEQUENCE_NUMBER)); 484 485 String errorDesc = currentErrorLine.substring(pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_DESC), pMap.get(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT)); 486 String errorFinancialBalanceTypeCode = currentErrorLine.substring(pMap.get(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE)); 487 488 if (compareStringFromValidEntry.compareTo(compareStringFromErrorEntry) < 0){ 489 // Read all the transactions in the valid group and update the cost share transactions 490 String updatedValidLine = checkAndSetTransactionTypeCostShare(financialBalanceTypeCode, desc, currentValidLine); 491 createOutputEntry(updatedValidLine, OUTPUT_DEMERGER_GLE_FILE_ps); 492 handleDemergerSaveValidEntry(updatedValidLine); 493 validSaved++; 494 currentValidLine = INPUT_GLE_FILE_br.readLine(); 495 validReadLine++; 496 497 } else if (compareStringFromValidEntry.compareTo(compareStringFromErrorEntry) > 0) { 498 if (!checkingBypassEntry(errorFinancialBalanceTypeCode, errorDesc, demergerReport)){ 499 createOutputEntry(currentErrorLine, OUTPUT_DEMERGER_ERR_FILE_ps); 500 errorSaved++; 501 } 502 currentErrorLine = INPUT_ERR_FILE_br.readLine(); 503 errorReadLine++; 504 505 } else { 506 if (!checkingBypassEntry(financialBalanceTypeCode, desc, demergerReport)){ 507 createOutputEntry(currentValidLine, OUTPUT_DEMERGER_ERR_FILE_ps); 508 errorSaved++; 509 } 510 currentValidLine = INPUT_GLE_FILE_br.readLine(); 511 validReadLine++; 512 } 513 514 continue; 515 516 } catch (RuntimeException re) { 517 LOG.error("performDemerger Stopped: " + re.getMessage()); 518 throw new RuntimeException("performDemerger Stopped: " + re.getMessage(), re); 519 } 520 } 521 INPUT_GLE_FILE_br.close(); 522 INPUT_ERR_FILE_br.close(); 523 OUTPUT_DEMERGER_GLE_FILE_ps.close(); 524 OUTPUT_DEMERGER_ERR_FILE_ps.close(); 525 526 } catch (IOException e) { 527 LOG.error("performDemerger Stopped: " + e.getMessage()); 528 throw new RuntimeException("performDemerger Stopped: " + e.getMessage(), e); 529 } 530 demergerReport.setErrorTransactionWritten(errorSaved); 531 demergerReport.setErrorTransactionsRead(errorReadLine); 532 demergerReport.setValidTransactionsRead(validReadLine); 533 demergerReport.setValidTransactionsSaved(validSaved); 534 535 if (!collectorMode) { 536 demergerReportWriterService.writeStatisticLine("SCRUBBER ERROR TRANSACTIONS READ %,9d", demergerReport.getErrorTransactionsRead()); 537 demergerReportWriterService.writeStatisticLine("SCRUBBER VALID TRANSACTIONS READ %,9d", demergerReport.getValidTransactionsRead()); 538 demergerReportWriterService.writeNewLines(1); 539 demergerReportWriterService.writeStatisticLine("DEMERGER ERRORS SAVED %,9d", demergerReport.getErrorTransactionsSaved()); 540 demergerReportWriterService.writeStatisticLine("DEMERGER VALID TRANSACTIONS SAVED %,9d", demergerReport.getValidTransactionsSaved()); 541 demergerReportWriterService.writeStatisticLine("OFFSET TRANSACTIONS BYPASSED %,9d", demergerReport.getOffsetTransactionsBypassed()); 542 demergerReportWriterService.writeStatisticLine("CAPITALIZATION TRANSACTIONS BYPASSED %,9d", demergerReport.getCapitalizationTransactionsBypassed()); 543 demergerReportWriterService.writeStatisticLine("LIABILITY TRANSACTIONS BYPASSED %,9d", demergerReport.getLiabilityTransactionsBypassed()); 544 demergerReportWriterService.writeStatisticLine("TRANSFER TRANSACTIONS BYPASSED %,9d", demergerReport.getTransferTransactionsBypassed()); 545 demergerReportWriterService.writeStatisticLine("COST SHARE TRANSACTIONS BYPASSED %,9d", demergerReport.getCostShareTransactionsBypassed()); 546 demergerReportWriterService.writeStatisticLine("COST SHARE ENC TRANSACTIONS BYPASSED %,9d", demergerReport.getCostShareEncumbranceTransactionsBypassed()); 547 548 generateDemergerRemovedTransactionsReport(demergerErrorOutputFilename); 549 } 550 } 551 552 /** 553 * Determine the type of the transaction by looking at attributes 554 * 555 * @param transaction Transaction to identify 556 * @return CE (Cost share encumbrance, O (Offset), C (apitalization), L (Liability), T (Transfer), CS (Cost Share), X (Other) 557 */ 558 protected String getTransactionType(OriginEntryInformation transaction) { 559 if (TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE.equals(transaction.getFinancialBalanceTypeCode())) { 560 return TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE; 561 } 562 String desc = transaction.getTransactionLedgerEntryDescription(); 563 564 if (desc == null) { 565 return TRANSACTION_TYPE_OTHER; 566 } 567 if (desc.startsWith(offsetDescription) && desc.indexOf(COST_SHARE_TRANSFER_ENTRY_IND) > -1) { 568 return TRANSACTION_TYPE_COST_SHARE; 569 } 570 if (desc.startsWith(costShareDescription) && desc.indexOf(COST_SHARE_TRANSFER_ENTRY_IND) > -1) { 571 return TRANSACTION_TYPE_COST_SHARE; 572 } 573 if (desc.startsWith(offsetDescription)) { 574 return TRANSACTION_TYPE_OFFSET; 575 } 576 if (desc.startsWith(capitalizationDescription)) { 577 return TRANSACTION_TYPE_CAPITALIZATION; 578 } 579 if (desc.startsWith(liabilityDescription)) { 580 return TRANSACTION_TYPE_LIABILITY; 581 } 582 if (desc.startsWith(transferDescription)) { 583 return TRANSACTION_TYPE_TRANSFER; 584 } 585 return TRANSACTION_TYPE_OTHER; 586 } 587 588 589 protected String getTransactionType(String financialBalanceTypeCode, String desc) { 590 if (TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE.equals(financialBalanceTypeCode)) { 591 return TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE; 592 } 593 if (desc == null) { 594 return TRANSACTION_TYPE_OTHER; 595 } 596 597 if (desc.startsWith(offsetDescription) && desc.indexOf(COST_SHARE_TRANSFER_ENTRY_IND) > -1) { 598 return TRANSACTION_TYPE_COST_SHARE; 599 } 600 if (desc.startsWith(costShareDescription) && desc.indexOf(COST_SHARE_TRANSFER_ENTRY_IND) > -1) { 601 return TRANSACTION_TYPE_COST_SHARE; 602 } 603 if (desc.startsWith(offsetDescription)) { 604 return TRANSACTION_TYPE_OFFSET; 605 } 606 if (desc.startsWith(capitalizationDescription)) { 607 return TRANSACTION_TYPE_CAPITALIZATION; 608 } 609 if (desc.startsWith(liabilityDescription)) { 610 return TRANSACTION_TYPE_LIABILITY; 611 } 612 if (desc.startsWith(transferDescription)) { 613 return TRANSACTION_TYPE_TRANSFER; 614 } 615 return TRANSACTION_TYPE_OTHER; 616 } 617 618 619 /** 620 * 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 621 * of Cobol relating to this. 622 * 623 * @param originEntryGroup Group to process 624 */ 625 protected void processGroup(boolean reportOnlyMode, ScrubberReportData scrubberReport) { 626 OriginEntryFull lastEntry = null; 627 scrubCostShareAmount = KualiDecimal.ZERO; 628 unitOfWork = new UnitOfWorkInfo(); 629 630 FileReader INPUT_GLE_FILE = null; 631 String GLEN_RECORD; 632 BufferedReader INPUT_GLE_FILE_br; 633 try { 634 INPUT_GLE_FILE = new FileReader(inputFile); 635 } 636 catch (FileNotFoundException e) { 637 throw new RuntimeException(e); 638 } 639 try { 640 OUTPUT_GLE_FILE_ps = new PrintStream(validFile); 641 OUTPUT_ERR_FILE_ps = new PrintStream(errorFile); 642 OUTPUT_EXP_FILE_ps = new PrintStream(expiredFile); 643 } 644 catch (IOException e) { 645 throw new RuntimeException(e); 646 } 647 648 INPUT_GLE_FILE_br = new BufferedReader(INPUT_GLE_FILE); 649 int line = 0; 650 LOG.info("Starting Scrubber Process process group..."); 651 try { 652 while ((GLEN_RECORD = INPUT_GLE_FILE_br.readLine()) != null) { 653 if (!org.apache.commons.lang.StringUtils.isEmpty(GLEN_RECORD) && !org.apache.commons.lang.StringUtils.isBlank(GLEN_RECORD.trim())) { 654 line++; 655 OriginEntryFull unscrubbedEntry = new OriginEntryFull(); 656 List<Message> tmperrors = unscrubbedEntry.setFromTextFileForBatch(GLEN_RECORD, line); 657 scrubberReport.incrementUnscrubbedRecordsRead(); 658 transactionErrors = new ArrayList<Message>(); 659 660 // 661 // This is done so if the code modifies this row, then saves it, it will be an insert, 662 // and it won't touch the original. The Scrubber never modifies input rows/groups. 663 // not relevant for file version 664 665 boolean saveErrorTransaction = false; 666 boolean saveValidTransaction = false; 667 boolean fatalErrorOccurred = false; 668 669 // Build a scrubbed entry 670 OriginEntryFull scrubbedEntry = new OriginEntryFull(); 671 scrubbedEntry.setDocumentNumber(unscrubbedEntry.getDocumentNumber()); 672 scrubbedEntry.setOrganizationDocumentNumber(unscrubbedEntry.getOrganizationDocumentNumber()); 673 scrubbedEntry.setOrganizationReferenceId(unscrubbedEntry.getOrganizationReferenceId()); 674 scrubbedEntry.setReferenceFinancialDocumentNumber(unscrubbedEntry.getReferenceFinancialDocumentNumber()); 675 676 Integer transactionNumber = unscrubbedEntry.getTransactionLedgerEntrySequenceNumber(); 677 scrubbedEntry.setTransactionLedgerEntrySequenceNumber(null == transactionNumber ? new Integer(0) : transactionNumber); 678 scrubbedEntry.setTransactionLedgerEntryDescription(unscrubbedEntry.getTransactionLedgerEntryDescription()); 679 scrubbedEntry.setTransactionLedgerEntryAmount(unscrubbedEntry.getTransactionLedgerEntryAmount()); 680 scrubbedEntry.setTransactionDebitCreditCode(unscrubbedEntry.getTransactionDebitCreditCode()); 681 682 if (!collectorMode) { 683 ledgerSummaryReport.summarizeEntry(unscrubbedEntry); 684 } 685 686 // For Labor Scrubber 687 boolean laborIndicator = false; 688 tmperrors.addAll(scrubberValidator.validateTransaction(unscrubbedEntry, scrubbedEntry, universityRunDate, laborIndicator, accountingCycleCachingService)); 689 transactionErrors.addAll(tmperrors); 690 691 692 Account unscrubbedEntryAccount = accountingCycleCachingService.getAccount(unscrubbedEntry.getChartOfAccountsCode(), unscrubbedEntry.getAccountNumber()); 693 // KFSMI-173: both the expired and closed accounts rows are put in the expired account 694 if ((unscrubbedEntryAccount != null) && (scrubberValidator.isAccountExpired(unscrubbedEntryAccount, universityRunDate) || unscrubbedEntryAccount.isClosed())) { 695 // Make a copy of it so OJB doesn't just update the row in the original 696 // group. It needs to make a new one in the expired group 697 OriginEntryFull expiredEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); 698 createOutputEntry(expiredEntry, OUTPUT_EXP_FILE_ps); 699 scrubberReport.incrementExpiredAccountFound(); 700 } 701 702 // the collector scrubber uses this map to apply the same changes made on an origin entry during scrubbing to 703 // the collector detail record 704 if (collectorMode) { 705 unscrubbedToScrubbedEntries.put(unscrubbedEntry, scrubbedEntry); 706 } 707 708 if (!isFatal(transactionErrors)) { 709 saveValidTransaction = true; 710 711 if (!collectorMode) { 712 713 // See if unit of work has changed 714 if (!unitOfWork.isSameUnitOfWork(scrubbedEntry)) { 715 // Generate offset for last unit of work 716 // pass the String line for generating error files 717 generateOffset(lastEntry, scrubberReport); 718 719 unitOfWork = new UnitOfWorkInfo(scrubbedEntry); 720 } 721 722 KualiDecimal transactionAmount = scrubbedEntry.getTransactionLedgerEntryAmount(); 723 724 ParameterEvaluator offsetFiscalPeriods = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.OFFSET_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()); 725 726 BalanceType scrubbedEntryBalanceType = accountingCycleCachingService.getBalanceType(scrubbedEntry.getFinancialBalanceTypeCode()); 727 if (scrubbedEntryBalanceType.isFinancialOffsetGenerationIndicator() && offsetFiscalPeriods.evaluationSucceeds()) { 728 if (scrubbedEntry.isDebit()) { 729 unitOfWork.offsetAmount = unitOfWork.offsetAmount.add(transactionAmount); 730 } 731 else { 732 unitOfWork.offsetAmount = unitOfWork.offsetAmount.subtract(transactionAmount); 733 } 734 } 735 736 // The sub account type code will only exist if there is a valid sub account 737 String subAccountTypeCode = GeneralLedgerConstants.getSpaceSubAccountTypeCode(); 738 // major assumption: the a21 subaccount is proxied, so we don't want to query the database if the 739 // subacct 740 // number is dashes 741 if (!KFSConstants.getDashSubAccountNumber().equals(scrubbedEntry.getSubAccountNumber())) { 742 A21SubAccount scrubbedEntryA21SubAccount = accountingCycleCachingService.getA21SubAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber(), scrubbedEntry.getSubAccountNumber()); 743 if (ObjectUtils.isNotNull(scrubbedEntryA21SubAccount)) { 744 subAccountTypeCode = scrubbedEntryA21SubAccount.getSubAccountTypeCode(); 745 } 746 } 747 748 ParameterEvaluator costShareObjectTypeCodes = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_OBJ_TYPE_CODES, scrubbedEntry.getFinancialObjectTypeCode()); 749 ParameterEvaluator costShareEncBalanceTypeCodes = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_ENC_BAL_TYP_CODES, scrubbedEntry.getFinancialBalanceTypeCode()); 750 ParameterEvaluator costShareEncFiscalPeriodCodes = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_ENC_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()); 751 ParameterEvaluator costShareEncDocTypeCodes = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_ENC_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode().trim()); 752 ParameterEvaluator costShareFiscalPeriodCodes = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.COST_SHARE_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()); 753 Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); 754 755 if (costShareObjectTypeCodes.evaluationSucceeds() && costShareEncBalanceTypeCodes.evaluationSucceeds() && scrubbedEntryAccount.isForContractsAndGrants() && KFSConstants.SubAccountType.COST_SHARE.equals(subAccountTypeCode) && costShareEncFiscalPeriodCodes.evaluationSucceeds() && costShareEncDocTypeCodes.evaluationSucceeds()) { 756 TransactionError te1 = generateCostShareEncumbranceEntries(scrubbedEntry, scrubberReport); 757 if (te1 != null) { 758 List errors = new ArrayList(); 759 errors.add(te1.message); 760 handleTransactionErrors(te1.transaction, errors); 761 saveValidTransaction = false; 762 saveErrorTransaction = true; 763 } 764 } 765 766 SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); 767 if (costShareObjectTypeCodes.evaluationSucceeds() && scrubbedEntryOption.getActualFinancialBalanceTypeCd().equals(scrubbedEntry.getFinancialBalanceTypeCode()) && scrubbedEntryAccount.isForContractsAndGrants() && KFSConstants.SubAccountType.COST_SHARE.equals(subAccountTypeCode) && costShareFiscalPeriodCodes.evaluationSucceeds() && costShareEncDocTypeCodes.evaluationSucceeds()) { 768 if (scrubbedEntry.isDebit()) { 769 scrubCostShareAmount = scrubCostShareAmount.subtract(transactionAmount); 770 } 771 else { 772 scrubCostShareAmount = scrubCostShareAmount.add(transactionAmount); 773 } 774 } 775 776 ParameterEvaluator otherDocTypeCodes = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.OFFSET_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode()); 777 778 if (otherDocTypeCodes.evaluationSucceeds()) { 779 String m = processCapitalization(scrubbedEntry, scrubberReport); 780 if (m != null) { 781 saveValidTransaction = false; 782 saveErrorTransaction = false; 783 addTransactionError(m, "", Message.TYPE_FATAL); 784 } 785 786 m = processLiabilities(scrubbedEntry, scrubberReport); 787 if (m != null) { 788 saveValidTransaction = false; 789 saveErrorTransaction = false; 790 addTransactionError(m, "", Message.TYPE_FATAL); 791 } 792 793 m = processPlantIndebtedness(scrubbedEntry, scrubberReport); 794 if (m != null) { 795 saveValidTransaction = false; 796 saveErrorTransaction = false; 797 addTransactionError(m, "", Message.TYPE_FATAL); 798 } 799 } 800 801 if (!scrubCostShareAmount.isZero()) { 802 TransactionError te = generateCostShareEntries(scrubbedEntry, scrubberReport); 803 804 if (te != null) { 805 saveValidTransaction = false; 806 saveErrorTransaction = false; 807 808 // Make a copy of it so OJB doesn't just update the row in the original 809 // group. It needs to make a new one in the error group 810 OriginEntryFull errorEntry = new OriginEntryFull(te.transaction); 811 errorEntry.setTransactionScrubberOffsetGenerationIndicator(false); 812 createOutputEntry(GLEN_RECORD, OUTPUT_ERR_FILE_ps); 813 scrubberReport.incrementErrorRecordWritten(); 814 unitOfWork.errorsFound = true; 815 816 handleTransactionError(te.transaction, te.message); 817 } 818 scrubCostShareAmount = KualiDecimal.ZERO; 819 } 820 821 lastEntry = scrubbedEntry; 822 } 823 } 824 else { 825 // Error transaction 826 saveErrorTransaction = true; 827 fatalErrorOccurred = true; 828 } 829 handleTransactionErrors(OriginEntryFull.copyFromOriginEntryable(unscrubbedEntry), transactionErrors); 830 831 if (saveValidTransaction) { 832 scrubbedEntry.setTransactionScrubberOffsetGenerationIndicator(false); 833 createOutputEntry(scrubbedEntry, OUTPUT_GLE_FILE_ps); 834 scrubberReport.incrementScrubbedRecordWritten(); 835 } 836 837 if (saveErrorTransaction) { 838 // Make a copy of it so OJB doesn't just update the row in the original 839 // group. It needs to make a new one in the error group 840 OriginEntryFull errorEntry = OriginEntryFull.copyFromOriginEntryable(unscrubbedEntry); 841 errorEntry.setTransactionScrubberOffsetGenerationIndicator(false); 842 createOutputEntry(GLEN_RECORD, OUTPUT_ERR_FILE_ps); 843 scrubberReport.incrementErrorRecordWritten(); 844 if (!fatalErrorOccurred) { 845 // if a fatal error occurred, the creation of a new unit of work was by-passed; 846 // therefore, it shouldn't ruin the previous unit of work 847 unitOfWork.errorsFound = true; 848 } 849 } 850 } 851 } 852 853 if (!collectorMode) { 854 // Generate last offset (if necessary) 855 generateOffset(lastEntry, scrubberReport); 856 } 857 858 INPUT_GLE_FILE_br.close(); 859 INPUT_GLE_FILE.close(); 860 OUTPUT_GLE_FILE_ps.close(); 861 OUTPUT_ERR_FILE_ps.close(); 862 OUTPUT_EXP_FILE_ps.close(); 863 864 handleEndOfScrubberReport(scrubberReport); 865 866 if (!collectorMode) { // winston 867 ledgerSummaryReport.writeReport(this.scrubberLedgerReportWriterService); 868 } 869 } 870 catch (IOException e) { 871 throw new RuntimeException(e); 872 } 873 } 874 875 /** 876 * Determines if a given error is fatal and should stop this scrubber run 877 * 878 * @param errors errors from a scrubber run 879 * @return true if the run should be abended, false otherwise 880 */ 881 protected boolean isFatal(List<Message> errors) { 882 for (Iterator<Message> iter = errors.iterator(); iter.hasNext();) { 883 Message element = iter.next(); 884 if (element.getType() == Message.TYPE_FATAL) { 885 return true; 886 } 887 } 888 return false; 889 } 890 891 /** 892 * Generates a cost share entry and offset for the given entry and saves both to the valid group 893 * 894 * @param scrubbedEntry the originEntry that was scrubbed 895 * @return a TransactionError initialized with any error encounted during entry generation, or (hopefully) null 896 */ 897 protected TransactionError generateCostShareEntries(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { 898 // 3000-COST-SHARE to 3100-READ-OFSD in the cobol Generate Cost Share Entries 899 LOG.debug("generateCostShareEntries() started"); 900 try { 901 OriginEntryFull costShareEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); 902 903 SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); 904 A21SubAccount scrubbedEntryA21SubAccount = accountingCycleCachingService.getA21SubAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber(), scrubbedEntry.getSubAccountNumber()); 905 906 costShareEntry.setFinancialObjectCode(parameterService.getParameterValue(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.COST_SHARE_OBJECT_CODE_PARM_NM)); 907 costShareEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 908 costShareEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinancialObjectTypeTransferExpenseCd()); 909 costShareEntry.setTransactionLedgerEntrySequenceNumber(new Integer(0)); 910 911 StringBuffer description = new StringBuffer(); 912 description.append(costShareDescription); 913 description.append(" ").append(scrubbedEntry.getAccountNumber()); 914 description.append(offsetString); 915 costShareEntry.setTransactionLedgerEntryDescription(description.toString()); 916 917 costShareEntry.setTransactionLedgerEntryAmount(scrubCostShareAmount); 918 if (scrubCostShareAmount.isPositive()) { 919 costShareEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 920 } 921 else { 922 costShareEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 923 costShareEntry.setTransactionLedgerEntryAmount(scrubCostShareAmount.negated()); 924 } 925 926 costShareEntry.setTransactionDate(runDate); 927 costShareEntry.setOrganizationDocumentNumber(null); 928 costShareEntry.setProjectCode(KFSConstants.getDashProjectCode()); 929 costShareEntry.setOrganizationReferenceId(null); 930 costShareEntry.setReferenceFinancialDocumentTypeCode(null); 931 costShareEntry.setReferenceFinancialSystemOriginationCode(null); 932 costShareEntry.setReferenceFinancialDocumentNumber(null); 933 costShareEntry.setFinancialDocumentReversalDate(null); 934 costShareEntry.setTransactionEncumbranceUpdateCode(null); 935 936 createOutputEntry(costShareEntry, OUTPUT_GLE_FILE_ps); 937 scrubberReport.incrementCostShareEntryGenerated(); 938 939 OriginEntryFull costShareOffsetEntry = new OriginEntryFull(costShareEntry); 940 costShareOffsetEntry.setTransactionLedgerEntryDescription(getOffsetMessage()); 941 OffsetDefinition offsetDefinition = accountingCycleCachingService.getOffsetDefinition(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), KFSConstants.TRANSFER_FUNDS, scrubbedEntry.getFinancialBalanceTypeCode()); 942 if (offsetDefinition != null) { 943 if (offsetDefinition.getFinancialObject() == null) { 944 StringBuffer objectCodeKey = new StringBuffer(); 945 objectCodeKey.append(offsetDefinition.getUniversityFiscalYear()); 946 objectCodeKey.append("-").append(offsetDefinition.getChartOfAccountsCode()); 947 objectCodeKey.append("-").append(offsetDefinition.getFinancialObjectCode()); 948 949 Message m = new Message(configurationService.getPropertyString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_OBJECT_CODE_NOT_FOUND) + " (" + objectCodeKey.toString() + ")", Message.TYPE_FATAL); 950 LOG.debug("generateCostShareEntries() Error 1 object not found"); 951 return new TransactionError(costShareEntry, m); 952 } 953 954 costShareOffsetEntry.setFinancialObjectCode(offsetDefinition.getFinancialObjectCode()); 955 costShareOffsetEntry.setFinancialObject(offsetDefinition.getFinancialObject()); 956 costShareOffsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 957 } 958 else { 959 Map<Transaction, List<Message>> errors = new HashMap<Transaction, List<Message>>(); 960 961 StringBuffer offsetKey = new StringBuffer("cost share transfer "); 962 offsetKey.append(scrubbedEntry.getUniversityFiscalYear()); 963 offsetKey.append("-"); 964 offsetKey.append(scrubbedEntry.getChartOfAccountsCode()); 965 offsetKey.append("-TF-"); 966 offsetKey.append(scrubbedEntry.getFinancialBalanceTypeCode()); 967 968 Message m = new Message(configurationService.getPropertyString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_NOT_FOUND) + " (" + offsetKey.toString() + ")", Message.TYPE_FATAL); 969 970 LOG.debug("generateCostShareEntries() Error 2 offset not found"); 971 return new TransactionError(costShareEntry, m); 972 } 973 974 costShareOffsetEntry.setFinancialObjectTypeCode(offsetDefinition.getFinancialObject().getFinancialObjectTypeCode()); 975 976 if (costShareEntry.isCredit()) { 977 costShareOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 978 } 979 else { 980 costShareOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 981 } 982 983 try { 984 flexibleOffsetAccountService.updateOffset(costShareOffsetEntry); 985 } 986 catch (InvalidFlexibleOffsetException e) { 987 Message m = new Message(e.getMessage(), Message.TYPE_FATAL); 988 LOG.debug("generateCostShareEntries() Cost Share Transfer Flexible Offset Error: " + e.getMessage()); 989 return new TransactionError(costShareEntry, m); 990 } 991 992 createOutputEntry(costShareOffsetEntry, OUTPUT_GLE_FILE_ps); 993 scrubberReport.incrementCostShareEntryGenerated(); 994 995 OriginEntryFull costShareSourceAccountEntry = new OriginEntryFull(costShareEntry); 996 997 description = new StringBuffer(); 998 description.append(costShareDescription); 999 description.append(" ").append(scrubbedEntry.getAccountNumber()); 1000 description.append(offsetString); 1001 costShareSourceAccountEntry.setTransactionLedgerEntryDescription(description.toString()); 1002 1003 costShareSourceAccountEntry.setChartOfAccountsCode(scrubbedEntryA21SubAccount.getCostShareChartOfAccountCode()); 1004 costShareSourceAccountEntry.setAccountNumber(scrubbedEntryA21SubAccount.getCostShareSourceAccountNumber()); 1005 1006 setCostShareObjectCode(costShareSourceAccountEntry, scrubbedEntry); 1007 costShareSourceAccountEntry.setSubAccountNumber(scrubbedEntryA21SubAccount.getCostShareSourceSubAccountNumber()); 1008 1009 if (StringHelper.isNullOrEmpty(costShareSourceAccountEntry.getSubAccountNumber())) { 1010 costShareSourceAccountEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 1011 } 1012 1013 costShareSourceAccountEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 1014 costShareSourceAccountEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinancialObjectTypeTransferExpenseCd()); 1015 costShareSourceAccountEntry.setTransactionLedgerEntrySequenceNumber(new Integer(0)); 1016 1017 costShareSourceAccountEntry.setTransactionLedgerEntryAmount(scrubCostShareAmount); 1018 if (scrubCostShareAmount.isPositive()) { 1019 costShareSourceAccountEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 1020 } 1021 else { 1022 costShareSourceAccountEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 1023 costShareSourceAccountEntry.setTransactionLedgerEntryAmount(scrubCostShareAmount.negated()); 1024 } 1025 1026 costShareSourceAccountEntry.setTransactionDate(runDate); 1027 costShareSourceAccountEntry.setOrganizationDocumentNumber(null); 1028 costShareSourceAccountEntry.setProjectCode(KFSConstants.getDashProjectCode()); 1029 costShareSourceAccountEntry.setOrganizationReferenceId(null); 1030 costShareSourceAccountEntry.setReferenceFinancialDocumentTypeCode(null); 1031 costShareSourceAccountEntry.setReferenceFinancialSystemOriginationCode(null); 1032 costShareSourceAccountEntry.setReferenceFinancialDocumentNumber(null); 1033 costShareSourceAccountEntry.setFinancialDocumentReversalDate(null); 1034 costShareSourceAccountEntry.setTransactionEncumbranceUpdateCode(null); 1035 1036 createOutputEntry(costShareSourceAccountEntry, OUTPUT_GLE_FILE_ps); 1037 scrubberReport.incrementCostShareEntryGenerated(); 1038 1039 OriginEntryFull costShareSourceAccountOffsetEntry = new OriginEntryFull(costShareSourceAccountEntry); 1040 costShareSourceAccountOffsetEntry.setTransactionLedgerEntryDescription(getOffsetMessage()); 1041 1042 // Lookup the new offset definition. 1043 offsetDefinition = accountingCycleCachingService.getOffsetDefinition(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), KFSConstants.TRANSFER_FUNDS, scrubbedEntry.getFinancialBalanceTypeCode()); 1044 if (offsetDefinition != null) { 1045 if (offsetDefinition.getFinancialObject() == null) { 1046 Map<Transaction, List<Message>> errors = new HashMap<Transaction, List<Message>>(); 1047 1048 StringBuffer objectCodeKey = new StringBuffer(); 1049 objectCodeKey.append(costShareEntry.getUniversityFiscalYear()); 1050 objectCodeKey.append("-").append(scrubbedEntry.getChartOfAccountsCode()); 1051 objectCodeKey.append("-").append(scrubbedEntry.getFinancialObjectCode()); 1052 1053 Message m = new Message(configurationService.getPropertyString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_OBJECT_CODE_NOT_FOUND) + " (" + objectCodeKey.toString() + ")", Message.TYPE_FATAL); 1054 1055 LOG.debug("generateCostShareEntries() Error 3 object not found"); 1056 return new TransactionError(costShareSourceAccountEntry, m); 1057 } 1058 1059 costShareSourceAccountOffsetEntry.setFinancialObjectCode(offsetDefinition.getFinancialObjectCode()); 1060 costShareSourceAccountOffsetEntry.setFinancialObject(offsetDefinition.getFinancialObject()); 1061 costShareSourceAccountOffsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 1062 } 1063 else { 1064 Map<Transaction, List<Message>> errors = new HashMap<Transaction, List<Message>>(); 1065 1066 StringBuffer offsetKey = new StringBuffer("cost share transfer source "); 1067 offsetKey.append(scrubbedEntry.getUniversityFiscalYear()); 1068 offsetKey.append("-"); 1069 offsetKey.append(scrubbedEntry.getChartOfAccountsCode()); 1070 offsetKey.append("-TF-"); 1071 offsetKey.append(scrubbedEntry.getFinancialBalanceTypeCode()); 1072 1073 Message m = new Message(configurationService.getPropertyString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_NOT_FOUND) + " (" + offsetKey.toString() + ")", Message.TYPE_FATAL); 1074 1075 LOG.debug("generateCostShareEntries() Error 4 offset not found"); 1076 return new TransactionError(costShareSourceAccountEntry, m); 1077 } 1078 1079 costShareSourceAccountOffsetEntry.setFinancialObjectTypeCode(offsetDefinition.getFinancialObject().getFinancialObjectTypeCode()); 1080 1081 if (scrubbedEntry.isCredit()) { 1082 costShareSourceAccountOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 1083 } 1084 else { 1085 costShareSourceAccountOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 1086 } 1087 1088 try { 1089 flexibleOffsetAccountService.updateOffset(costShareSourceAccountOffsetEntry); 1090 } 1091 catch (InvalidFlexibleOffsetException e) { 1092 Message m = new Message(e.getMessage(), Message.TYPE_FATAL); 1093 LOG.debug("generateCostShareEntries() Cost Share Transfer Account Flexible Offset Error: " + e.getMessage()); 1094 return new TransactionError(costShareEntry, m); 1095 } 1096 1097 createOutputEntry(costShareSourceAccountOffsetEntry, OUTPUT_GLE_FILE_ps); 1098 scrubberReport.incrementCostShareEntryGenerated(); 1099 1100 scrubCostShareAmount = KualiDecimal.ZERO; 1101 } catch (IOException ioe) { 1102 LOG.error("generateCostShareEntries() Stopped: " + ioe.getMessage()); 1103 throw new RuntimeException("generateCostShareEntries() Stopped: " + ioe.getMessage(), ioe); 1104 } 1105 LOG.debug("generateCostShareEntries() successful"); 1106 return null; 1107 } 1108 1109 /** 1110 * Get all the transaction descriptions from the param table 1111 */ 1112 protected void setDescriptions() { 1113 //TODO: move to constants class? 1114 offsetDescription = "GENERATED OFFSET"; 1115 capitalizationDescription = "GENERATED CAPITALIZATION"; 1116 liabilityDescription = "GENERATED LIABILITY"; 1117 costShareDescription = "GENERATED COST SHARE FROM"; 1118 transferDescription = "GENERATED TRANSFER FROM"; 1119 } 1120 1121 /** 1122 * Generate the flag for the end of specific descriptions. This will be used in the demerger step 1123 */ 1124 protected void setOffsetString() { 1125 1126 NumberFormat nf = NumberFormat.getInstance(); 1127 nf.setMaximumFractionDigits(0); 1128 nf.setMaximumIntegerDigits(2); 1129 nf.setMinimumFractionDigits(0); 1130 nf.setMinimumIntegerDigits(2); 1131 1132 offsetString = COST_SHARE_TRANSFER_ENTRY_IND + nf.format(runCal.get(Calendar.MONTH) + 1) + nf.format(runCal.get(Calendar.DAY_OF_MONTH)); 1133 } 1134 1135 /** 1136 * Generate the offset message with the flag at the end 1137 * 1138 * @return a generated offset message 1139 */ 1140 protected String getOffsetMessage() { 1141 String msg = offsetDescription + GeneralLedgerConstants.getSpaceTransactionLedgetEntryDescription(); 1142 1143 return msg.substring(0, OFFSET_MESSAGE_MAXLENGTH) + offsetString; 1144 } 1145 1146 /** 1147 * Generates capitalization entries if necessary 1148 * 1149 * @param scrubbedEntry the entry to generate capitalization entries (possibly) for 1150 * @return null if no error, message if error 1151 */ 1152 protected String processCapitalization(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { 1153 1154 try { 1155 // Lines 4694 - 4798 of the Pro Cobol listing on Confluence 1156 if (!parameterService.getIndicatorParameter(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.CAPITALIZATION_IND)) { 1157 return null; 1158 } 1159 1160 OriginEntryFull capitalizationEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); 1161 SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); 1162 ObjectCode scrubbedEntryObjectCode = accountingCycleCachingService.getObjectCode(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialObjectCode()); 1163 Chart scrubbedEntryChart = accountingCycleCachingService.getChart(scrubbedEntry.getChartOfAccountsCode()); 1164 Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); 1165 1166 ParameterEvaluator documentTypeCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode()) : null; 1167 ParameterEvaluator fiscalPeriodCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()) : null; 1168 ParameterEvaluator objectSubTypeCodes = (!ObjectUtils.isNull(scrubbedEntryObjectCode)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_OBJ_SUB_TYPE_CODES, scrubbedEntryObjectCode.getFinancialObjectSubTypeCode()) : null; 1169 ParameterEvaluator subFundGroupCodes = (!ObjectUtils.isNull(scrubbedEntryAccount)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_SUB_FUND_GROUP_CODES, scrubbedEntryAccount.getSubFundGroupCode()) : null; 1170 ParameterEvaluator chartCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.CAPITALIZATION_CHART_CODES, scrubbedEntry.getChartOfAccountsCode()) : null; 1171 1172 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())) { 1173 1174 String objectSubTypeCode = scrubbedEntryObjectCode.getFinancialObjectSubTypeCode(); 1175 1176 String capitalizationObjectCode = parameterService.getParameterValue(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.CAPITALIZATION_SUBTYPE_OBJECT, objectSubTypeCode); 1177 if (capitalizationObjectCode != null) { 1178 capitalizationEntry.setFinancialObjectCode(capitalizationObjectCode); 1179 capitalizationEntry.setFinancialObject(accountingCycleCachingService.getObjectCode(capitalizationEntry.getUniversityFiscalYear(), capitalizationEntry.getChartOfAccountsCode(), capitalizationEntry.getFinancialObjectCode())); 1180 } 1181 1182 capitalizationEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinancialObjectTypeAssetsCd()); 1183 capitalizationEntry.setTransactionLedgerEntryDescription(capitalizationDescription); 1184 1185 plantFundAccountLookup(scrubbedEntry, capitalizationEntry); 1186 1187 capitalizationEntry.setUniversityFiscalPeriodCode(scrubbedEntry.getUniversityFiscalPeriodCode()); 1188 1189 createOutputEntry(capitalizationEntry, OUTPUT_GLE_FILE_ps); 1190 scrubberReport.incrementCapitalizationEntryGenerated(); 1191 1192 // Clear out the id & the ojb version number to make sure we do an insert on the next one 1193 capitalizationEntry.setVersionNumber(null); 1194 capitalizationEntry.setEntryId(null); 1195 1196 // Check system parameters for overriding fund balance object code; otherwise, use 1197 // the chart fund balance object code. 1198 String fundBalanceCode = parameterService.getParameterValue( 1199 ScrubberStep.class, 1200 GlParameterConstants.CAPITALIZATION_OFFSET_CODE); 1201 1202 ObjectCode fundObjectCode = getFundBalanceObjectCode(fundBalanceCode, capitalizationEntry); 1203 1204 if (fundObjectCode != null) { 1205 capitalizationEntry.setFinancialObjectTypeCode(fundObjectCode.getFinancialObjectTypeCode()); 1206 capitalizationEntry.setFinancialObjectCode(fundBalanceCode); 1207 } 1208 else { 1209 capitalizationEntry.setFinancialObjectCode(scrubbedEntryChart.getFundBalanceObjectCode()); 1210 //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? 1211 if (ObjectUtils.isNotNull(scrubbedEntryChart.getFundBalanceObject())) { 1212 capitalizationEntry.setFinancialObjectTypeCode(scrubbedEntryChart.getFundBalanceObject().getFinancialObjectTypeCode()); 1213 } 1214 else { 1215 capitalizationEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeFundBalanceCd()); 1216 } 1217 } 1218 1219 populateTransactionDebtCreditCode(scrubbedEntry, capitalizationEntry); 1220 1221 try { 1222 flexibleOffsetAccountService.updateOffset(capitalizationEntry); 1223 } 1224 catch (InvalidFlexibleOffsetException e) { 1225 LOG.debug("processCapitalization() Capitalization Flexible Offset Error: " + e.getMessage()); 1226 return e.getMessage(); 1227 } 1228 1229 createOutputEntry(capitalizationEntry, OUTPUT_GLE_FILE_ps); 1230 scrubberReport.incrementCapitalizationEntryGenerated(); 1231 } 1232 } catch (IOException ioe) { 1233 LOG.error("processCapitalization() Stopped: " + ioe.getMessage()); 1234 throw new RuntimeException("processCapitalization() Stopped: " + ioe.getMessage(), ioe); 1235 } 1236 return null; 1237 } 1238 1239 /** 1240 * Generates the plant indebtedness entries 1241 * 1242 * @param scrubbedEntry the entry to generated plant indebtedness entries for if necessary 1243 * @return null if no error, message if error 1244 */ 1245 protected String processPlantIndebtedness(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { 1246 try{ 1247 // Lines 4855 - 4979 of the Pro Cobol listing on Confluence 1248 if (!parameterService.getIndicatorParameter(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.PLANT_INDEBTEDNESS_IND)) { 1249 return null; 1250 } 1251 1252 OriginEntryFull plantIndebtednessEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); 1253 1254 SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); 1255 ObjectCode scrubbedEntryObjectCode = accountingCycleCachingService.getObjectCode(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialObjectCode()); 1256 Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); 1257 Chart scrubbedEntryChart = accountingCycleCachingService.getChart(scrubbedEntry.getChartOfAccountsCode()); 1258 if (!ObjectUtils.isNull(scrubbedEntryAccount)) { 1259 scrubbedEntryAccount.setOrganization(accountingCycleCachingService.getOrganization(scrubbedEntryAccount.getChartOfAccountsCode(), scrubbedEntryAccount.getOrganizationCode())); 1260 } 1261 1262 ParameterEvaluator objectSubTypeCodes = (!ObjectUtils.isNull(scrubbedEntryObjectCode)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.PLANT_INDEBTEDNESS_OBJ_SUB_TYPE_CODES, scrubbedEntryObjectCode.getFinancialObjectSubTypeCode()) : null; 1263 ParameterEvaluator subFundGroupCodes = (!ObjectUtils.isNull(scrubbedEntryAccount)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.PLANT_INDEBTEDNESS_SUB_FUND_GROUP_CODES, scrubbedEntryAccount.getSubFundGroupCode()) : null; 1264 1265 if (scrubbedEntry.getFinancialBalanceTypeCode().equals(scrubbedEntryOption.getActualFinancialBalanceTypeCd()) && (subFundGroupCodes != null && subFundGroupCodes.evaluationSucceeds()) && (objectSubTypeCodes != null && objectSubTypeCodes.evaluationSucceeds())) { 1266 1267 plantIndebtednessEntry.setTransactionLedgerEntryDescription(KFSConstants.PLANT_INDEBTEDNESS_ENTRY_DESCRIPTION); 1268 populateTransactionDebtCreditCode(scrubbedEntry, plantIndebtednessEntry); 1269 1270 plantIndebtednessEntry.setTransactionScrubberOffsetGenerationIndicator(true); 1271 createOutputEntry(plantIndebtednessEntry, OUTPUT_GLE_FILE_ps); 1272 scrubberReport.incrementPlantIndebtednessEntryGenerated(); 1273 1274 // Clear out the id & the ojb version number to make sure we do an insert on the next one 1275 plantIndebtednessEntry.setVersionNumber(null); 1276 plantIndebtednessEntry.setEntryId(null); 1277 1278 // Check system parameters for overriding fund balance object code; otherwise, use 1279 // the chart fund balance object code. 1280 String fundBalanceCode = parameterService.getParameterValue( 1281 ScrubberStep.class, 1282 GlParameterConstants.PLANT_INDEBTEDNESS_OFFSET_CODE); 1283 1284 ObjectCode fundObjectCode = getFundBalanceObjectCode(fundBalanceCode, plantIndebtednessEntry); 1285 if (fundObjectCode != null) { 1286 plantIndebtednessEntry.setFinancialObjectTypeCode(fundObjectCode.getFinancialObjectTypeCode()); 1287 plantIndebtednessEntry.setFinancialObjectCode(fundBalanceCode); 1288 } 1289 else { 1290 plantIndebtednessEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeFundBalanceCd()); 1291 plantIndebtednessEntry.setFinancialObjectCode(scrubbedEntryChart.getFundBalanceObjectCode()); 1292 } 1293 1294 plantIndebtednessEntry.setTransactionDebitCreditCode(scrubbedEntry.getTransactionDebitCreditCode()); 1295 1296 plantIndebtednessEntry.setTransactionScrubberOffsetGenerationIndicator(true); 1297 plantIndebtednessEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 1298 1299 try { 1300 flexibleOffsetAccountService.updateOffset(plantIndebtednessEntry); 1301 } 1302 catch (InvalidFlexibleOffsetException e) { 1303 LOG.error("processPlantIndebtedness() Flexible Offset Exception (1)", e); 1304 LOG.debug("processPlantIndebtedness() Plant Indebtedness Flexible Offset Error: " + e.getMessage()); 1305 return e.getMessage(); 1306 } 1307 1308 createOutputEntry(plantIndebtednessEntry, OUTPUT_GLE_FILE_ps); 1309 scrubberReport.incrementPlantIndebtednessEntryGenerated(); 1310 1311 // Clear out the id & the ojb version number to make sure we do an insert on the next one 1312 plantIndebtednessEntry.setVersionNumber(null); 1313 plantIndebtednessEntry.setEntryId(null); 1314 1315 plantIndebtednessEntry.setFinancialObjectCode(scrubbedEntry.getFinancialObjectCode()); 1316 plantIndebtednessEntry.setFinancialObjectTypeCode(scrubbedEntry.getFinancialObjectTypeCode()); 1317 plantIndebtednessEntry.setTransactionDebitCreditCode(scrubbedEntry.getTransactionDebitCreditCode()); 1318 1319 plantIndebtednessEntry.setTransactionLedgerEntryDescription(scrubbedEntry.getTransactionLedgerEntryDescription()); 1320 1321 plantIndebtednessEntry.setAccountNumber(scrubbedEntry.getAccountNumber()); 1322 plantIndebtednessEntry.setSubAccountNumber(scrubbedEntry.getSubAccountNumber()); 1323 1324 plantIndebtednessEntry.setAccountNumber(scrubbedEntryAccount.getOrganization().getCampusPlantAccountNumber()); 1325 plantIndebtednessEntry.setChartOfAccountsCode(scrubbedEntryAccount.getOrganization().getCampusPlantChartCode()); 1326 1327 plantIndebtednessEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 1328 plantIndebtednessEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 1329 1330 StringBuffer litGenPlantXferFrom = new StringBuffer(); 1331 litGenPlantXferFrom.append(transferDescription + " "); 1332 litGenPlantXferFrom.append(scrubbedEntry.getChartOfAccountsCode()).append(" "); 1333 litGenPlantXferFrom.append(scrubbedEntry.getAccountNumber()); 1334 plantIndebtednessEntry.setTransactionLedgerEntryDescription(litGenPlantXferFrom.toString()); 1335 1336 createOutputEntry(plantIndebtednessEntry, OUTPUT_GLE_FILE_ps); 1337 scrubberReport.incrementPlantIndebtednessEntryGenerated(); 1338 1339 // Clear out the id & the ojb version number to make sure we do an insert on the next one 1340 plantIndebtednessEntry.setVersionNumber(null); 1341 plantIndebtednessEntry.setEntryId(null); 1342 1343 plantIndebtednessEntry.setFinancialObjectCode(scrubbedEntryChart.getFundBalanceObjectCode()); 1344 plantIndebtednessEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeFundBalanceCd()); 1345 plantIndebtednessEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 1346 1347 populateTransactionDebtCreditCode(scrubbedEntry, plantIndebtednessEntry); 1348 1349 try { 1350 flexibleOffsetAccountService.updateOffset(plantIndebtednessEntry); 1351 } 1352 catch (InvalidFlexibleOffsetException e) { 1353 LOG.error("processPlantIndebtedness() Flexible Offset Exception (2)", e); 1354 LOG.debug("processPlantIndebtedness() Plant Indebtedness Flexible Offset Error: " + e.getMessage()); 1355 return e.getMessage(); 1356 } 1357 1358 createOutputEntry(plantIndebtednessEntry, OUTPUT_GLE_FILE_ps); 1359 scrubberReport.incrementPlantIndebtednessEntryGenerated(); 1360 } 1361 } catch (IOException ioe) { 1362 LOG.error("processPlantIndebtedness() Stopped: " + ioe.getMessage()); 1363 throw new RuntimeException("processPlantIndebtedness() Stopped: " + ioe.getMessage(), ioe); 1364 } 1365 return null; 1366 } 1367 1368 /** 1369 * Generate the liability entries for the entry if necessary 1370 * 1371 * @param scrubbedEntry the entry to generate liability entries for if necessary 1372 * @return null if no error, message if error 1373 */ 1374 protected String processLiabilities(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { 1375 try{ 1376 // Lines 4799 to 4839 of the Pro Cobol list of the scrubber on Confluence 1377 if (!parameterService.getIndicatorParameter(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.LIABILITY_IND)) { 1378 return null; 1379 } 1380 1381 Chart scrubbedEntryChart = accountingCycleCachingService.getChart(scrubbedEntry.getChartOfAccountsCode()); 1382 SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); 1383 ObjectCode scrubbedEntryFinancialObject = accountingCycleCachingService.getObjectCode(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialObjectCode()); 1384 Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); 1385 1386 ParameterEvaluator chartCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_CHART_CODES, scrubbedEntry.getChartOfAccountsCode()) : null; 1387 ParameterEvaluator docTypeCodes = (!ObjectUtils.isNull(scrubbedEntry)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode()) : null; 1388 ParameterEvaluator fiscalPeriods = (!ObjectUtils.isNull(scrubbedEntry)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_FISCAL_PERIOD_CODES, scrubbedEntry.getUniversityFiscalPeriodCode()) : null; 1389 ParameterEvaluator objSubTypeCodes = (!ObjectUtils.isNull(scrubbedEntryFinancialObject)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_OBJ_SUB_TYPE_CODES, scrubbedEntryFinancialObject.getFinancialObjectSubTypeCode()) : null; 1390 ParameterEvaluator subFundGroupCodes = (!ObjectUtils.isNull(scrubbedEntryAccount)) ? parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.LIABILITY_SUB_FUND_GROUP_CODES, scrubbedEntryAccount.getSubFundGroupCode()) : null; 1391 1392 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())) { 1393 OriginEntryFull liabilityEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); 1394 1395 liabilityEntry.setFinancialObjectCode(parameterService.getParameterValue(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.LIABILITY_OBJECT_CODE)); 1396 liabilityEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeLiabilitiesCode()); 1397 1398 liabilityEntry.setTransactionDebitCreditCode(scrubbedEntry.getTransactionDebitCreditCode()); 1399 liabilityEntry.setTransactionLedgerEntryDescription(liabilityDescription); 1400 plantFundAccountLookup(scrubbedEntry, liabilityEntry); 1401 1402 createOutputEntry(liabilityEntry, OUTPUT_GLE_FILE_ps); 1403 scrubberReport.incrementLiabilityEntryGenerated(); 1404 1405 // Clear out the id & the ojb version number to make sure we do an insert on the next one 1406 liabilityEntry.setVersionNumber(null); 1407 liabilityEntry.setEntryId(null); 1408 1409 // Check system parameters for overriding fund balance object code; otherwise, use 1410 // the chart fund balance object code. 1411 String fundBalanceCode = parameterService.getParameterValue( 1412 ScrubberStep.class, 1413 GlParameterConstants.LIABILITY_OFFSET_CODE); 1414 1415 ObjectCode fundObjectCode = getFundBalanceObjectCode(fundBalanceCode, liabilityEntry); 1416 if (fundObjectCode != null) { 1417 liabilityEntry.setFinancialObjectTypeCode(fundObjectCode.getFinancialObjectTypeCode()); 1418 liabilityEntry.setFinancialObjectCode(fundBalanceCode); 1419 } 1420 else { 1421 // ... and now generate the offset half of the liability entry 1422 liabilityEntry.setFinancialObjectCode(scrubbedEntryChart.getFundBalanceObjectCode()); 1423 if (ObjectUtils.isNotNull(scrubbedEntryChart.getFundBalanceObject())) { 1424 liabilityEntry.setFinancialObjectTypeCode(scrubbedEntryChart.getFundBalanceObject().getFinancialObjectTypeCode()); 1425 } 1426 else { 1427 liabilityEntry.setFinancialObjectTypeCode(scrubbedEntryOption.getFinObjectTypeFundBalanceCd()); 1428 } 1429 } 1430 1431 if (liabilityEntry.isDebit()) { 1432 liabilityEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 1433 } 1434 else { 1435 liabilityEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 1436 } 1437 1438 try { 1439 flexibleOffsetAccountService.updateOffset(liabilityEntry); 1440 } 1441 catch (InvalidFlexibleOffsetException e) { 1442 LOG.debug("processLiabilities() Liability Flexible Offset Error: " + e.getMessage()); 1443 return e.getMessage(); 1444 } 1445 1446 createOutputEntry(liabilityEntry, OUTPUT_GLE_FILE_ps); 1447 scrubberReport.incrementLiabilityEntryGenerated(); 1448 } 1449 } catch (IOException ioe) { 1450 LOG.error("processLiabilities() Stopped: " + ioe.getMessage()); 1451 throw new RuntimeException("processLiabilities() Stopped: " + ioe.getMessage(), ioe); 1452 } 1453 return null; 1454 } 1455 1456 /** 1457 * 1458 * This method... 1459 * @param fundBalanceCodeParameter 1460 * @param originEntryFull 1461 * @return 1462 */ 1463 private ObjectCode getFundBalanceObjectCode(String fundBalanceCode, OriginEntryFull originEntryFull) 1464 { 1465 ObjectCode fundBalanceObjectCode = null; 1466 if (fundBalanceCode != null) { 1467 Map<String, Object> criteriaMap = new HashMap<String, Object>(); 1468 criteriaMap.put("universityFiscalYear", originEntryFull.getUniversityFiscalYear()); 1469 criteriaMap.put("chartOfAccountsCode", originEntryFull.getChartOfAccountsCode()); 1470 criteriaMap.put("financialObjectCode", fundBalanceCode); 1471 1472 fundBalanceObjectCode = ((ObjectCode) businessObjectService.findByPrimaryKey(ObjectCode.class, criteriaMap)); 1473 } 1474 1475 return fundBalanceObjectCode; 1476 } 1477 1478 /** 1479 * 1480 * This method... 1481 * @param scrubbedEntry 1482 * @param fullEntry 1483 */ 1484 private void populateTransactionDebtCreditCode(OriginEntryInformation scrubbedEntry, OriginEntryFull fullEntry) 1485 { 1486 if (scrubbedEntry.isDebit()) { 1487 fullEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 1488 } 1489 else { 1490 fullEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 1491 } 1492 } 1493 1494 /** 1495 * Updates the entries with the proper chart and account for the plant fund 1496 * 1497 * @param scrubbedEntry basis for plant fund entry 1498 * @param liabilityEntry liability entry 1499 */ 1500 protected void plantFundAccountLookup(OriginEntryInformation scrubbedEntry, OriginEntryFull liabilityEntry) { 1501 // 4000-PLANT-FUND-ACCT to 4000-PLANT-FUND-ACCT-EXIT in cobol 1502 1503 liabilityEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 1504 ObjectCode scrubbedEntryObjectCode = accountingCycleCachingService.getObjectCode(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialObjectCode()); 1505 Account scrubbedEntryAccount = accountingCycleCachingService.getAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber()); 1506 scrubbedEntryAccount.setOrganization(accountingCycleCachingService.getOrganization(scrubbedEntryAccount.getChartOfAccountsCode(), scrubbedEntryAccount.getOrganizationCode())); 1507 1508 if (!ObjectUtils.isNull(scrubbedEntryAccount) && !ObjectUtils.isNull(scrubbedEntryObjectCode)) { 1509 String objectSubTypeCode = scrubbedEntryObjectCode.getFinancialObjectSubTypeCode(); 1510 ParameterEvaluator campusObjSubTypeCodes = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.PLANT_FUND_CAMPUS_OBJECT_SUB_TYPE_CODES, objectSubTypeCode); 1511 ParameterEvaluator orgObjSubTypeCodes = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.PLANT_FUND_ORG_OBJECT_SUB_TYPE_CODES, objectSubTypeCode); 1512 1513 if (campusObjSubTypeCodes.evaluationSucceeds()) { 1514 liabilityEntry.setAccountNumber(scrubbedEntryAccount.getOrganization().getCampusPlantAccountNumber()); 1515 liabilityEntry.setChartOfAccountsCode(scrubbedEntryAccount.getOrganization().getCampusPlantChartCode()); 1516 } 1517 else if (orgObjSubTypeCodes.evaluationSucceeds()) { 1518 liabilityEntry.setAccountNumber(scrubbedEntryAccount.getOrganization().getOrganizationPlantAccountNumber()); 1519 liabilityEntry.setChartOfAccountsCode(scrubbedEntryAccount.getOrganization().getOrganizationPlantChartCode()); 1520 } 1521 } 1522 } 1523 1524 /** 1525 * The purpose of this method is to generate a "Cost Share Encumbrance" 1526 * transaction for the current transaction and its offset. The cost share chart and account for current transaction are obtained 1527 * 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 1528 * writes out the cost share transaction. Next it read the GL_OFFSET_DEFN_T table for the offset object code that corresponds to 1529 * 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 1530 * 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 1531 * with this object code. It writes out the offset transaction and returns. 1532 * 1533 * @param scrubbedEntry the entry to perhaps create a cost share encumbrance for 1534 * @return a message if there was an error encountered generating the entries, or (hopefully) null if no errors were encountered 1535 */ 1536 protected TransactionError generateCostShareEncumbranceEntries(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { 1537 try{ 1538 // 3200-COST-SHARE-ENC to 3200-CSE-EXIT in the COBOL 1539 LOG.debug("generateCostShareEncumbranceEntries() started"); 1540 1541 OriginEntryFull costShareEncumbranceEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); 1542 1543 // First 28 characters of the description, padding to 28 if shorter) 1544 StringBuffer buffer = new StringBuffer((scrubbedEntry.getTransactionLedgerEntryDescription() + GeneralLedgerConstants.getSpaceTransactionLedgetEntryDescription()).substring(0, COST_SHARE_ENCUMBRANCE_ENTRY_MAXLENGTH)); 1545 1546 buffer.append("FR-"); 1547 buffer.append(costShareEncumbranceEntry.getChartOfAccountsCode()); 1548 buffer.append(costShareEncumbranceEntry.getAccountNumber()); 1549 1550 costShareEncumbranceEntry.setTransactionLedgerEntryDescription(buffer.toString()); 1551 1552 A21SubAccount scrubbedEntryA21SubAccount = accountingCycleCachingService.getA21SubAccount(scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getAccountNumber(), scrubbedEntry.getSubAccountNumber()); 1553 SystemOptions scrubbedEntryOption = accountingCycleCachingService.getSystemOptions(scrubbedEntry.getUniversityFiscalYear()); 1554 1555 costShareEncumbranceEntry.setChartOfAccountsCode(scrubbedEntryA21SubAccount.getCostShareChartOfAccountCode()); 1556 costShareEncumbranceEntry.setAccountNumber(scrubbedEntryA21SubAccount.getCostShareSourceAccountNumber()); 1557 costShareEncumbranceEntry.setSubAccountNumber(scrubbedEntryA21SubAccount.getCostShareSourceSubAccountNumber()); 1558 1559 if (!StringUtils.hasText(costShareEncumbranceEntry.getSubAccountNumber())) { 1560 costShareEncumbranceEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 1561 } 1562 1563 costShareEncumbranceEntry.setFinancialBalanceTypeCode(scrubbedEntryOption.getCostShareEncumbranceBalanceTypeCd()); 1564 setCostShareObjectCode(costShareEncumbranceEntry, scrubbedEntry); 1565 costShareEncumbranceEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 1566 costShareEncumbranceEntry.setTransactionLedgerEntrySequenceNumber(new Integer(0)); 1567 1568 if (!StringUtils.hasText(scrubbedEntry.getTransactionDebitCreditCode())) { 1569 if (scrubbedEntry.getTransactionLedgerEntryAmount().isPositive()) { 1570 costShareEncumbranceEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 1571 } 1572 else { 1573 costShareEncumbranceEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 1574 costShareEncumbranceEntry.setTransactionLedgerEntryAmount(scrubbedEntry.getTransactionLedgerEntryAmount().negated()); 1575 } 1576 } 1577 1578 costShareEncumbranceEntry.setTransactionDate(runDate); 1579 1580 costShareEncumbranceEntry.setTransactionScrubberOffsetGenerationIndicator(true); 1581 createOutputEntry(costShareEncumbranceEntry, OUTPUT_GLE_FILE_ps); 1582 scrubberReport.incrementCostShareEncumbranceGenerated(); 1583 1584 OriginEntryFull costShareEncumbranceOffsetEntry = new OriginEntryFull(costShareEncumbranceEntry); 1585 costShareEncumbranceOffsetEntry.setTransactionLedgerEntryDescription(offsetDescription); 1586 OffsetDefinition offset = accountingCycleCachingService.getOffsetDefinition(costShareEncumbranceEntry.getUniversityFiscalYear(), costShareEncumbranceEntry.getChartOfAccountsCode(), costShareEncumbranceEntry.getFinancialDocumentTypeCode(), costShareEncumbranceEntry.getFinancialBalanceTypeCode()); 1587 1588 if (offset != null) { 1589 if (offset.getFinancialObject() == null) { 1590 StringBuffer offsetKey = new StringBuffer(); 1591 offsetKey.append(offset.getUniversityFiscalYear()); 1592 offsetKey.append("-"); 1593 offsetKey.append(offset.getChartOfAccountsCode()); 1594 offsetKey.append("-"); 1595 offsetKey.append(offset.getFinancialObjectCode()); 1596 1597 LOG.debug("generateCostShareEncumbranceEntries() object code not found"); 1598 return new TransactionError(costShareEncumbranceEntry, new Message(configurationService.getPropertyString(KFSKeyConstants.ERROR_NO_OBJECT_FOR_OBJECT_ON_OFSD) + "(" + offsetKey.toString() + ")", Message.TYPE_FATAL)); 1599 } 1600 costShareEncumbranceOffsetEntry.setFinancialObjectCode(offset.getFinancialObjectCode()); 1601 costShareEncumbranceOffsetEntry.setFinancialObject(offset.getFinancialObject()); 1602 costShareEncumbranceOffsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 1603 } 1604 else { 1605 StringBuffer offsetKey = new StringBuffer("Cost share encumbrance "); 1606 offsetKey.append(costShareEncumbranceEntry.getUniversityFiscalYear()); 1607 offsetKey.append("-"); 1608 offsetKey.append(costShareEncumbranceEntry.getChartOfAccountsCode()); 1609 offsetKey.append("-"); 1610 offsetKey.append(costShareEncumbranceEntry.getFinancialDocumentTypeCode()); 1611 offsetKey.append("-"); 1612 offsetKey.append(costShareEncumbranceEntry.getFinancialBalanceTypeCode()); 1613 1614 LOG.debug("generateCostShareEncumbranceEntries() offset not found"); 1615 return new TransactionError(costShareEncumbranceEntry, new Message(configurationService.getPropertyString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_NOT_FOUND) + "(" + offsetKey.toString() + ")", Message.TYPE_FATAL)); 1616 } 1617 1618 costShareEncumbranceOffsetEntry.setFinancialObjectTypeCode(offset.getFinancialObject().getFinancialObjectTypeCode()); 1619 1620 if (costShareEncumbranceEntry.isCredit()) { 1621 costShareEncumbranceOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 1622 } 1623 else { 1624 costShareEncumbranceOffsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 1625 } 1626 1627 costShareEncumbranceOffsetEntry.setTransactionDate(runDate); 1628 costShareEncumbranceOffsetEntry.setOrganizationDocumentNumber(null); 1629 costShareEncumbranceOffsetEntry.setProjectCode(KFSConstants.getDashProjectCode()); 1630 costShareEncumbranceOffsetEntry.setOrganizationReferenceId(null); 1631 costShareEncumbranceOffsetEntry.setReferenceFinancialDocumentTypeCode(null); 1632 costShareEncumbranceOffsetEntry.setReferenceFinancialSystemOriginationCode(null); 1633 costShareEncumbranceOffsetEntry.setReferenceFinancialDocumentNumber(null); 1634 costShareEncumbranceOffsetEntry.setReversalDate(null); 1635 costShareEncumbranceOffsetEntry.setTransactionEncumbranceUpdateCode(null); 1636 1637 costShareEncumbranceOffsetEntry.setTransactionScrubberOffsetGenerationIndicator(true); 1638 1639 try { 1640 flexibleOffsetAccountService.updateOffset(costShareEncumbranceOffsetEntry); 1641 } 1642 catch (InvalidFlexibleOffsetException e) { 1643 Message m = new Message(e.getMessage(), Message.TYPE_FATAL); 1644 LOG.debug("generateCostShareEncumbranceEntries() Cost Share Encumbrance Flexible Offset Error: " + e.getMessage()); 1645 return new TransactionError(costShareEncumbranceOffsetEntry, m); 1646 } 1647 1648 createOutputEntry(costShareEncumbranceOffsetEntry, OUTPUT_GLE_FILE_ps); 1649 scrubberReport.incrementCostShareEncumbranceGenerated(); 1650 } catch (IOException ioe) { 1651 LOG.error("generateCostShareEncumbranceEntries() Stopped: " + ioe.getMessage()); 1652 throw new RuntimeException("generateCostShareEncumbranceEntries() Stopped: " + ioe.getMessage(), ioe); 1653 } 1654 LOG.debug("generateCostShareEncumbranceEntries() returned successfully"); 1655 return null; 1656 } 1657 1658 /** 1659 * Sets the proper cost share object code in an entry and its offset 1660 * 1661 * @param costShareEntry GL Entry for cost share 1662 * @param originEntry Scrubbed GL Entry that this is based on 1663 */ 1664 public void setCostShareObjectCode(OriginEntryFull costShareEntry, OriginEntryInformation originEntry) { 1665 ObjectCode originEntryFinancialObject = accountingCycleCachingService.getObjectCode(originEntry.getUniversityFiscalYear(), originEntry.getChartOfAccountsCode(), originEntry.getFinancialObjectCode()); 1666 1667 if (originEntryFinancialObject == null) { 1668 addTransactionError(configurationService.getPropertyString(KFSKeyConstants.ERROR_OBJECT_CODE_NOT_FOUND), originEntry.getFinancialObjectCode(), Message.TYPE_FATAL); 1669 } 1670 1671 String originEntryObjectLevelCode = (originEntryFinancialObject == null) ? "" : originEntryFinancialObject.getFinancialObjectLevelCode(); 1672 1673 String financialOriginEntryObjectCode = originEntry.getFinancialObjectCode(); 1674 //String originEntryObjectCode = scrubberProcessObjectCodeOverride.getOriginEntryObjectCode(originEntryObjectLevelCode, financialOriginEntryObjectCode); 1675 1676 // General rules 1677 String param = parameterService.getParameterValue(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.COST_SHARE_OBJECT_CODE_BY_LEVEL_PARM_NM, originEntryObjectLevelCode); 1678 if (param == null) { 1679 param = parameterService.getParameterValue(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.COST_SHARE_OBJECT_CODE_BY_LEVEL_PARM_NM, "DEFAULT"); 1680 if (param == null) { 1681 throw new RuntimeException("Unable to determine cost sharing object code from object level. Default entry missing."); 1682 } 1683 } 1684 financialOriginEntryObjectCode = param; 1685 1686 // Lookup the new object code 1687 ObjectCode objectCode = accountingCycleCachingService.getObjectCode(costShareEntry.getUniversityFiscalYear(), costShareEntry.getChartOfAccountsCode(), financialOriginEntryObjectCode); 1688 if (objectCode != null) { 1689 costShareEntry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode()); 1690 costShareEntry.setFinancialObjectCode(financialOriginEntryObjectCode); 1691 } 1692 else { 1693 addTransactionError(configurationService.getPropertyString(KFSKeyConstants.ERROR_COST_SHARE_OBJECT_NOT_FOUND), costShareEntry.getFinancialObjectCode(), Message.TYPE_FATAL); 1694 } 1695 } 1696 1697 /** 1698 * The purpose of this method is to build the actual offset transaction. It does this by performing the following steps: 1. 1699 * Getting the offset object code and offset subobject code from the GL Offset Definition Table. 2. For the offset object code 1700 * it needs to get the associated object type, object subtype, and object active code. 1701 * 1702 * @param scrubbedEntry entry to determine if an offset is needed for 1703 * @return true if an offset would be needed for this entry, false otherwise 1704 */ 1705 protected boolean generateOffset(OriginEntryInformation scrubbedEntry, ScrubberReportData scrubberReport) { 1706 OriginEntryFull offsetEntry = new OriginEntryFull(); 1707 try{ 1708 // This code is 3000-OFFSET to SET-OBJECT-2004 in the Cobol 1709 LOG.debug("generateOffset() started"); 1710 1711 // There was no previous unit of work so we need no offset 1712 if (scrubbedEntry == null) { 1713 return true; 1714 } 1715 1716 // If there was an error, don't generate an offset since the record was pulled 1717 // and the rest of the document's records will be demerged 1718 if (unitOfWork.errorsFound == true) { 1719 return true; 1720 } 1721 1722 // If the offset amount is zero, don't bother to lookup the offset definition ... 1723 if (unitOfWork.offsetAmount.isZero()) { 1724 return true; 1725 } 1726 1727 ParameterEvaluator docTypeRule = parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.OFFSET_DOC_TYPE_CODES, scrubbedEntry.getFinancialDocumentTypeCode()); 1728 if (!docTypeRule.evaluationSucceeds()) { 1729 return true; 1730 } 1731 1732 // do nothing if flexible offset is enabled and scrubber offset indicator of the document 1733 // type code is turned off in the document type table 1734 if (flexibleOffsetAccountService.getEnabled() && !shouldScrubberGenerateOffsetsForDocType(scrubbedEntry.getFinancialDocumentTypeCode())) { 1735 return true; 1736 } 1737 1738 // Create an offset 1739 offsetEntry = OriginEntryFull.copyFromOriginEntryable(scrubbedEntry); 1740 offsetEntry.setTransactionLedgerEntryDescription(offsetDescription); 1741 1742 //of course this method should go elsewhere, not in ScrubberValidator! 1743 OffsetDefinition offsetDefinition = accountingCycleCachingService.getOffsetDefinition(scrubbedEntry.getUniversityFiscalYear(), scrubbedEntry.getChartOfAccountsCode(), scrubbedEntry.getFinancialDocumentTypeCode(), scrubbedEntry.getFinancialBalanceTypeCode()); 1744 if (offsetDefinition != null) { 1745 if (offsetDefinition.getFinancialObject() == null) { 1746 StringBuffer offsetKey = new StringBuffer(offsetDefinition.getUniversityFiscalYear()); 1747 offsetKey.append("-"); 1748 offsetKey.append(offsetDefinition.getChartOfAccountsCode()); 1749 offsetKey.append("-"); 1750 offsetKey.append(offsetDefinition.getFinancialObjectCode()); 1751 1752 putTransactionError(offsetEntry, configurationService.getPropertyString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_OBJECT_CODE_NOT_FOUND), offsetKey.toString(), Message.TYPE_FATAL); 1753 1754 createOutputEntry(offsetEntry, OUTPUT_ERR_FILE_ps); 1755 scrubberReport.incrementErrorRecordWritten(); 1756 return false; 1757 } 1758 1759 offsetEntry.setFinancialObject(offsetDefinition.getFinancialObject()); 1760 offsetEntry.setFinancialObjectCode(offsetDefinition.getFinancialObjectCode()); 1761 1762 offsetEntry.setFinancialSubObject(null); 1763 offsetEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 1764 } 1765 else { 1766 StringBuffer sb = new StringBuffer("Unit of work offset "); 1767 sb.append(scrubbedEntry.getUniversityFiscalYear()); 1768 sb.append("-"); 1769 sb.append(scrubbedEntry.getChartOfAccountsCode()); 1770 sb.append("-"); 1771 sb.append(scrubbedEntry.getFinancialDocumentTypeCode()); 1772 sb.append("-"); 1773 sb.append(scrubbedEntry.getFinancialBalanceTypeCode()); 1774 1775 putTransactionError(offsetEntry, configurationService.getPropertyString(KFSKeyConstants.ERROR_OFFSET_DEFINITION_NOT_FOUND), sb.toString(), Message.TYPE_FATAL); 1776 1777 createOutputEntry(offsetEntry, OUTPUT_ERR_FILE_ps); 1778 scrubberReport.incrementErrorRecordWritten(); 1779 return false; 1780 } 1781 1782 offsetEntry.setFinancialObjectTypeCode(offsetEntry.getFinancialObject().getFinancialObjectTypeCode()); 1783 offsetEntry.setTransactionLedgerEntryAmount(unitOfWork.offsetAmount); 1784 1785 if (unitOfWork.offsetAmount.isPositive()) { 1786 offsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 1787 } 1788 else { 1789 offsetEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 1790 offsetEntry.setTransactionLedgerEntryAmount(unitOfWork.offsetAmount.negated()); 1791 } 1792 1793 offsetEntry.setOrganizationDocumentNumber(null); 1794 offsetEntry.setOrganizationReferenceId(null); 1795 offsetEntry.setReferenceFinancialDocumentTypeCode(null); 1796 offsetEntry.setReferenceFinancialSystemOriginationCode(null); 1797 offsetEntry.setReferenceFinancialDocumentNumber(null); 1798 offsetEntry.setTransactionEncumbranceUpdateCode(null); 1799 offsetEntry.setProjectCode(KFSConstants.getDashProjectCode()); 1800 offsetEntry.setTransactionDate(runDate); 1801 1802 try { 1803 flexibleOffsetAccountService.updateOffset(offsetEntry); 1804 } 1805 catch (InvalidFlexibleOffsetException e) { 1806 LOG.debug("generateOffset() Offset Flexible Offset Error: " + e.getMessage()); 1807 putTransactionError(offsetEntry, e.getMessage(), "", Message.TYPE_FATAL); 1808 return true; 1809 } 1810 1811 createOutputEntry(offsetEntry, OUTPUT_GLE_FILE_ps); 1812 scrubberReport.incrementOffsetEntryGenerated(); 1813 1814 } catch (IOException ioe) { 1815 LOG.error("generateOffset() Stopped: " + ioe.getMessage()); 1816 throw new RuntimeException("generateOffset() Stopped: " + ioe.getMessage(), ioe); 1817 } 1818 1819 return true; 1820 } 1821 1822 1823 protected void createOutputEntry(OriginEntryInformation entry, PrintStream ps) throws IOException { 1824 try { 1825 ps.printf("%s\n", entry.getLine()); 1826 } catch (Exception e) { 1827 throw new IOException(e.toString()); 1828 } 1829 } 1830 1831 protected void createOutputEntry(String line, PrintStream ps) throws IOException { 1832 try { 1833 ps.printf("%s\n", line); 1834 } catch (Exception e) { 1835 throw new IOException(e.toString()); 1836 } 1837 } 1838 1839 /** 1840 * Add an error message to the list of messages for this transaction 1841 * 1842 * @param errorMessage Error message 1843 * @param errorValue Value that is in error 1844 * @param type Type of error (Fatal or Warning) 1845 */ 1846 protected void addTransactionError(String errorMessage, String errorValue, int type) { 1847 transactionErrors.add(new Message(errorMessage + " (" + errorValue + ")", type)); 1848 } 1849 1850 /** 1851 * Puts a transaction error into this instance's collection of errors 1852 * 1853 * @param s a transaction that caused a scrubber error 1854 * @param errorMessage the message of what caused the error 1855 * @param errorValue the value in error 1856 * @param type the type of error 1857 */ 1858 protected void putTransactionError(Transaction s, String errorMessage, String errorValue, int type) { 1859 Message m = new Message(errorMessage + "(" + errorValue + ")", type); 1860 scrubberReportWriterService.writeError(s, m); 1861 } 1862 1863 /** 1864 * Determines if the scrubber should generate offsets for the given document type 1865 * @param docTypeCode the document type code to check if it generates scrubber offsets 1866 * @return true if the scrubber should generate offsets for this doc type, false otherwise 1867 */ 1868 protected boolean shouldScrubberGenerateOffsetsForDocType(String docTypeCode) { 1869 return parameterService.getParameterEvaluator(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupRules.DOCUMENT_TYPES_REQUIRING_FLEXIBLE_OFFSET_BALANCING_ENTRIES, docTypeCode).evaluationSucceeds(); 1870 } 1871 1872 /** 1873 * A class to hold the current unit of work the scrubber is using 1874 */ 1875 class UnitOfWorkInfo { 1876 // Unit of work key 1877 public Integer univFiscalYr = 0; 1878 public String finCoaCd = ""; 1879 public String accountNbr = ""; 1880 public String subAcctNbr = ""; 1881 public String finBalanceTypCd = ""; 1882 public String fdocTypCd = ""; 1883 public String fsOriginCd = ""; 1884 public String fdocNbr = ""; 1885 public Date fdocReversalDt = new Date(dateTimeService.getCurrentDate().getTime()); 1886 public String univFiscalPrdCd = ""; 1887 1888 // Data about unit of work 1889 public boolean errorsFound = false; 1890 public KualiDecimal offsetAmount = KualiDecimal.ZERO; 1891 public String scrbFinCoaCd; 1892 public String scrbAccountNbr; 1893 1894 /** 1895 * Constructs a ScrubberProcess.UnitOfWorkInfo instance 1896 */ 1897 public UnitOfWorkInfo() { 1898 } 1899 1900 /** 1901 * Constructs a ScrubberProcess.UnitOfWorkInfo instance 1902 * @param e an origin entry belonging to this unit of work 1903 */ 1904 public UnitOfWorkInfo(OriginEntryInformation e) { 1905 univFiscalYr = e.getUniversityFiscalYear(); 1906 finCoaCd = e.getChartOfAccountsCode(); 1907 accountNbr = e.getAccountNumber(); 1908 subAcctNbr = e.getSubAccountNumber(); 1909 finBalanceTypCd = e.getFinancialBalanceTypeCode(); 1910 fdocTypCd = e.getFinancialDocumentTypeCode(); 1911 fsOriginCd = e.getFinancialSystemOriginationCode(); 1912 fdocNbr = e.getDocumentNumber(); 1913 fdocReversalDt = e.getFinancialDocumentReversalDate(); 1914 univFiscalPrdCd = e.getUniversityFiscalPeriodCode(); 1915 } 1916 1917 /** 1918 * Determines if an entry belongs to this unit of work 1919 * 1920 * @param e the entry to check 1921 * @return true if it belongs to this unit of work, false otherwise 1922 */ 1923 public boolean isSameUnitOfWork(OriginEntryInformation e) { 1924 // Compare the key fields 1925 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()); 1926 } 1927 1928 /** 1929 * Converts this unit of work info to a String 1930 * @return a String representation of this UnitOfWorkInfo 1931 * @see java.lang.Object#toString() 1932 */ 1933 public String toString() { 1934 return univFiscalYr + finCoaCd + accountNbr + subAcctNbr + finBalanceTypCd + fdocTypCd + fsOriginCd + fdocNbr + fdocReversalDt + univFiscalPrdCd; 1935 } 1936 1937 /** 1938 * Generates the beginning of an OriginEntryFull, based on the unit of work info 1939 * 1940 * @return a partially initialized OriginEntryFull 1941 */ 1942 public OriginEntryFull getOffsetTemplate() { 1943 OriginEntryFull e = new OriginEntryFull(); 1944 e.setUniversityFiscalYear(univFiscalYr); 1945 e.setChartOfAccountsCode(finCoaCd); 1946 e.setAccountNumber(accountNbr); 1947 e.setSubAccountNumber(subAcctNbr); 1948 e.setFinancialBalanceTypeCode(finBalanceTypCd); 1949 e.setFinancialDocumentTypeCode(fdocTypCd); 1950 e.setFinancialSystemOriginationCode(fsOriginCd); 1951 e.setDocumentNumber(fdocNbr); 1952 e.setFinancialDocumentReversalDate(fdocReversalDt); 1953 e.setUniversityFiscalPeriodCode(univFiscalPrdCd); 1954 return e; 1955 } 1956 } 1957 1958 /** 1959 * An internal class to hold errors encountered by the scrubber 1960 */ 1961 class TransactionError { 1962 public Transaction transaction; 1963 public Message message; 1964 1965 /** 1966 * Constructs a ScrubberProcess.TransactionError instance 1967 * @param t the transaction that had the error 1968 * @param m a message about the error 1969 */ 1970 public TransactionError(Transaction t, Message m) { 1971 transaction = t; 1972 message = m; 1973 } 1974 } 1975 1976 /** 1977 * This method modifies the run date if it is before the cutoff time specified by the RunTimeService See 1978 * KULRNE-70 This method is public to facilitate unit testing 1979 * 1980 * @param currentDate the date the scrubber should report as having run on 1981 * @return the run date 1982 */ 1983 public Date calculateRunDate(java.util.Date currentDate) { 1984 return new Date(runDateService.calculateRunDate(currentDate).getTime()); 1985 } 1986 1987 protected boolean checkingBypassEntry (String financialBalanceTypeCode, String desc, DemergerReportData demergerReport){ 1988 String transactionType = getTransactionType(financialBalanceTypeCode, desc); 1989 1990 if (TRANSACTION_TYPE_COST_SHARE_ENCUMBRANCE.equals(transactionType)) { 1991 demergerReport.incrementCostShareEncumbranceTransactionsBypassed(); 1992 return true; 1993 } 1994 else if (TRANSACTION_TYPE_OFFSET.equals(transactionType)) { 1995 demergerReport.incrementOffsetTransactionsBypassed(); 1996 return true; 1997 } 1998 else if (TRANSACTION_TYPE_CAPITALIZATION.equals(transactionType)) { 1999 demergerReport.incrementCapitalizationTransactionsBypassed(); 2000 return true; 2001 } 2002 else if (TRANSACTION_TYPE_LIABILITY.equals(transactionType)) { 2003 demergerReport.incrementLiabilityTransactionsBypassed(); 2004 return true; 2005 } 2006 else if (TRANSACTION_TYPE_TRANSFER.equals(transactionType)) { 2007 demergerReport.incrementTransferTransactionsBypassed(); 2008 return true; 2009 } 2010 else if (TRANSACTION_TYPE_COST_SHARE.equals(transactionType)) { 2011 demergerReport.incrementCostShareTransactionsBypassed(); 2012 return true; 2013 } 2014 2015 return false; 2016 } 2017 2018 2019 protected String checkAndSetTransactionTypeCostShare (String financialBalanceTypeCode, String desc, String currentValidLine){ 2020 2021 // Read all the transactions in the valid group and update the cost share transactions 2022 String transactionType = getTransactionType(financialBalanceTypeCode, desc); 2023 if (TRANSACTION_TYPE_COST_SHARE.equals(transactionType)) { 2024 OriginEntryFull transaction = new OriginEntryFull(); 2025 transaction.setFromTextFileForBatch(currentValidLine, 0); 2026 2027 transaction.setFinancialDocumentTypeCode(KFSConstants.TRANSFER_FUNDS); 2028 transaction.setFinancialSystemOriginationCode(KFSConstants.SubAccountType.COST_SHARE); 2029 StringBuffer docNbr = new StringBuffer(COST_SHARE_CODE); 2030 2031 docNbr.append(desc.substring(36, 38)); 2032 docNbr.append("/"); 2033 docNbr.append(desc.substring(38, 40)); 2034 transaction.setDocumentNumber(docNbr.toString()); 2035 transaction.setTransactionLedgerEntryDescription(desc.substring(0, DEMERGER_TRANSACTION_LEDGET_ENTRY_DESCRIPTION)); 2036 2037 currentValidLine = transaction.getLine(); 2038 } 2039 2040 return currentValidLine; 2041 2042 } 2043 2044 2045 /** 2046 * Generates the scrubber listing report for the GLCP document 2047 * @param documentNumber the document number of the GLCP document 2048 */ 2049 protected void generateScrubberTransactionListingReport(String documentNumber, String inputFileName) { 2050 try { 2051 scrubberListingReportWriterService.setDocumentNumber(documentNumber); 2052 ((WrappingBatchService) scrubberListingReportWriterService).initialize(); 2053 new TransactionListingReport().generateReport(scrubberListingReportWriterService, new OriginEntryFileIterator(new File(inputFileName))); 2054 } finally { 2055 ((WrappingBatchService) scrubberListingReportWriterService).destroy(); 2056 } 2057 } 2058 2059 /** 2060 * Generates the scrubber report that lists out the input origin entries with blank balance type codes. 2061 */ 2062 protected void generateScrubberBlankBalanceTypeCodeReport(String inputFileName) { 2063 OriginEntryFilter blankBalanceTypeFilter = new OriginEntryFilter() { 2064 /** 2065 * @see org.kuali.kfs.gl.batch.service.impl.FilteringOriginEntryFileIterator.OriginEntryFilter#accept(org.kuali.kfs.gl.businessobject.OriginEntryFull) 2066 */ 2067 public boolean accept(OriginEntryFull originEntry) { 2068 BalanceType originEntryBalanceType = accountingCycleCachingService.getBalanceType(originEntry.getFinancialBalanceTypeCode()); 2069 return ObjectUtils.isNull(originEntryBalanceType); 2070 } 2071 }; 2072 Iterator<OriginEntryFull> blankBalanceOriginEntries = new FilteringOriginEntryFileIterator(new File(inputFileName), blankBalanceTypeFilter); 2073 new TransactionListingReport().generateReport(scrubberBadBalanceListingReportWriterService, blankBalanceOriginEntries); 2074 } 2075 2076 protected void generateDemergerRemovedTransactionsReport(String errorFileName) { 2077 OriginEntryFileIterator removedTransactions = new OriginEntryFileIterator(new File(errorFileName)); 2078 new TransactionListingReport().generateReport(demergerRemovedTransactionsListingReportWriterService, removedTransactions); 2079 } 2080 2081 protected void handleTransactionError(Transaction errorTransaction, Message message) { 2082 if (collectorMode) { 2083 List<Message> messages = scrubberReportErrors.get(errorTransaction); 2084 if (messages == null) { 2085 messages = new ArrayList<Message>(); 2086 scrubberReportErrors.put(errorTransaction, messages); 2087 } 2088 messages.add(message); 2089 } 2090 else { 2091 scrubberReportWriterService.writeError(errorTransaction, message); 2092 } 2093 } 2094 2095 protected void handleTransactionErrors(Transaction errorTransaction, List<Message> messages) { 2096 if (collectorMode) { 2097 for (Message message : messages) { 2098 handleTransactionError(errorTransaction, message); 2099 } 2100 } 2101 else { 2102 if (LOG.isDebugEnabled()) { 2103 LOG.debug("Errors on transaction: "+errorTransaction); 2104 for (Message message: messages) { 2105 LOG.debug(message); 2106 } 2107 } 2108 scrubberReportWriterService.writeError(errorTransaction, messages); 2109 } 2110 } 2111 2112 protected void handleEndOfScrubberReport(ScrubberReportData scrubberReport) { 2113 if (!collectorMode) { 2114 scrubberReportWriterService.writeStatisticLine("UNSCRUBBED RECORDS READ %,9d", scrubberReport.getNumberOfUnscrubbedRecordsRead()); 2115 scrubberReportWriterService.writeStatisticLine("SCRUBBED RECORDS WRITTEN %,9d", scrubberReport.getNumberOfScrubbedRecordsWritten()); 2116 scrubberReportWriterService.writeStatisticLine("ERROR RECORDS WRITTEN %,9d", scrubberReport.getNumberOfErrorRecordsWritten()); 2117 scrubberReportWriterService.writeStatisticLine("OFFSET ENTRIES GENERATED %,9d", scrubberReport.getNumberOfOffsetEntriesGenerated()); 2118 scrubberReportWriterService.writeStatisticLine("CAPITALIZATION ENTRIES GENERATED %,9d", scrubberReport.getNumberOfCapitalizationEntriesGenerated()); 2119 scrubberReportWriterService.writeStatisticLine("LIABILITY ENTRIES GENERATED %,9d", scrubberReport.getNumberOfLiabilityEntriesGenerated()); 2120 scrubberReportWriterService.writeStatisticLine("PLANT INDEBTEDNESS ENTRIES GENERATED %,9d", scrubberReport.getNumberOfPlantIndebtednessEntriesGenerated()); 2121 scrubberReportWriterService.writeStatisticLine("COST SHARE ENTRIES GENERATED %,9d", scrubberReport.getNumberOfCostShareEntriesGenerated()); 2122 scrubberReportWriterService.writeStatisticLine("COST SHARE ENC ENTRIES GENERATED %,9d", scrubberReport.getNumberOfCostShareEncumbrancesGenerated()); 2123 scrubberReportWriterService.writeStatisticLine("TOTAL OUTPUT RECORDS WRITTEN %,9d", scrubberReport.getTotalNumberOfRecordsWritten()); 2124 scrubberReportWriterService.writeStatisticLine("EXPIRED ACCOUNTS FOUND %,9d", scrubberReport.getNumberOfExpiredAccountsFound()); 2125 } 2126 } 2127 2128 protected void handleDemergerSaveValidEntry(String entryString) { 2129 if (collectorMode) { 2130 OriginEntryInformation tempEntry = new OriginEntryFull(entryString); 2131 ledgerSummaryReport.summarizeEntry(tempEntry); 2132 } 2133 } 2134 2135 /** 2136 * Sets the batchFileDirectoryName attribute value. 2137 * @param batchFileDirectoryName The batchFileDirectoryName to set. 2138 */ 2139 public void setBatchFileDirectoryName(String batchFileDirectoryName) { 2140 this.batchFileDirectoryName = batchFileDirectoryName; 2141 } 2142 2143 /** 2144 * Gets the transferDescription attribute. 2145 * @return Returns the transferDescription. 2146 */ 2147 public String getTransferDescription() { 2148 return transferDescription; 2149 } 2150 2151 /** 2152 * Sets the transferDescription attribute value. 2153 * @param transferDescription The transferDescription to set. 2154 */ 2155 public void setTransferDescription(String transferDescription) { 2156 this.transferDescription = transferDescription; 2157 } 2158 2159 /** 2160 * Sets the dateTimeService attribute value. 2161 * @param dateTimeService The dateTimeService to set. 2162 */ 2163 public void setDateTimeService(DateTimeService dateTimeService) { 2164 this.dateTimeService = dateTimeService; 2165 } 2166 2167 /** 2168 * Sets the lOG attribute value. 2169 * @param log The lOG to set. 2170 */ 2171 public static void setLOG(org.apache.log4j.Logger log) { 2172 LOG = log; 2173 } 2174 2175 /** 2176 * Sets the flexibleOffsetAccountService attribute value. 2177 * @param flexibleOffsetAccountService The flexibleOffsetAccountService to set. 2178 */ 2179 public void setFlexibleOffsetAccountService(FlexibleOffsetAccountService flexibleOffsetAccountService) { 2180 this.flexibleOffsetAccountService = flexibleOffsetAccountService; 2181 } 2182 2183 /** 2184 * Sets the configurationService attribute value. 2185 * @param configurationService The configurationService to set. 2186 */ 2187 public void setConfigurationService(KualiConfigurationService configurationService) { 2188 this.configurationService = configurationService; 2189 } 2190 2191 /** 2192 * Sets the persistenceService attribute value. 2193 * @param persistenceService The persistenceService to set. 2194 */ 2195 public void setPersistenceService(PersistenceService persistenceService) { 2196 this.persistenceService = persistenceService; 2197 } 2198 2199 /** 2200 * Sets the scrubberValidator attribute value. 2201 * @param scrubberValidator The scrubberValidator to set. 2202 */ 2203 public void setScrubberValidator(ScrubberValidator scrubberValidator) { 2204 this.scrubberValidator = scrubberValidator; 2205 } 2206 2207 /** 2208 * Sets the accountingCycleCachingService attribute value. 2209 * @param accountingCycleCachingService The accountingCycleCachingService to set. 2210 */ 2211 public void setAccountingCycleCachingService(AccountingCycleCachingService accountingCycleCachingService) { 2212 this.accountingCycleCachingService = accountingCycleCachingService; 2213 } 2214 2215 /** 2216 * Sets the scrubberReportWriterService attribute value. 2217 * @param scrubberReportWriterService The scrubberReportWriterService to set. 2218 */ 2219 public void setScrubberReportWriterService(DocumentNumberAwareReportWriterService scrubberReportWriterService) { 2220 this.scrubberReportWriterService = scrubberReportWriterService; 2221 } 2222 2223 /** 2224 * Sets the scrubberLedgerReportWriterService attribute value. 2225 * @param scrubberLedgerReportWriterService The scrubberLedgerReportWriterService to set. 2226 */ 2227 public void setScrubberLedgerReportWriterService(DocumentNumberAwareReportWriterService scrubberLedgerReportWriterService) { 2228 this.scrubberLedgerReportWriterService = scrubberLedgerReportWriterService; 2229 } 2230 2231 /** 2232 * Sets the scrubberListingReportWriterService attribute value. 2233 * @param scrubberListingReportWriterService The scrubberListingReportWriterService to set. 2234 */ 2235 public void setScrubberListingReportWriterService(DocumentNumberAwareReportWriterService scrubberListingReportWriterService) { 2236 this.scrubberListingReportWriterService = scrubberListingReportWriterService; 2237 } 2238 2239 /** 2240 * Sets the scrubberBadBalanceListingReportWriterService attribute value. 2241 * @param scrubberBadBalanceListingReportWriterService The scrubberBadBalanceListingReportWriterService to set. 2242 */ 2243 public void setScrubberBadBalanceListingReportWriterService(ReportWriterService scrubberBadBalanceListingReportWriterService) { 2244 this.scrubberBadBalanceListingReportWriterService = scrubberBadBalanceListingReportWriterService; 2245 } 2246 2247 /** 2248 * Sets the demergerRemovedTransactionsListingReportWriterService attribute value. 2249 * @param demergerRemovedTransactionsListingReportWriterService The demergerRemovedTransactionsListingReportWriterService to set. 2250 */ 2251 public void setDemergerRemovedTransactionsListingReportWriterService(ReportWriterService demergerRemovedTransactionsListingReportWriterService) { 2252 this.demergerRemovedTransactionsListingReportWriterService = demergerRemovedTransactionsListingReportWriterService; 2253 } 2254 2255 /** 2256 * Sets the demergerReportWriterService attribute value. 2257 * @param demergerReportWriterService The demergerReportWriterService to set. 2258 */ 2259 public void setDemergerReportWriterService(ReportWriterService demergerReportWriterService) { 2260 this.demergerReportWriterService = demergerReportWriterService; 2261 } 2262 2263 /** 2264 * Sets the preScrubberService attribute value. 2265 * @param preScrubberService The preScrubberService to set. 2266 */ 2267 public void setPreScrubberService(PreScrubberService preScrubberService) { 2268 this.preScrubberService = preScrubberService; 2269 } 2270 2271 /** 2272 * Sets the parameterService attribute value. 2273 * @param parameterService The parameterService to set. 2274 */ 2275 public void setParameterService(ParameterService parameterService) { 2276 this.parameterService = parameterService; 2277 } 2278 2279 /** 2280 * Sets the runDateService attribute value. 2281 * @param runDateService The runDateService to set. 2282 */ 2283 public void setRunDateService(RunDateService runDateService) { 2284 this.runDateService = runDateService; 2285 } 2286 2287 /** 2288 * Gets the flexibleOffsetAccountService attribute. 2289 * @return Returns the flexibleOffsetAccountService. 2290 */ 2291 public FlexibleOffsetAccountService getFlexibleOffsetAccountService() { 2292 return flexibleOffsetAccountService; 2293 } 2294 2295 /** 2296 * Gets the dateTimeService attribute. 2297 * @return Returns the dateTimeService. 2298 */ 2299 public DateTimeService getDateTimeService() { 2300 return dateTimeService; 2301 } 2302 2303 /** 2304 * Gets the configurationService attribute. 2305 * @return Returns the configurationService. 2306 */ 2307 public KualiConfigurationService getConfigurationService() { 2308 return configurationService; 2309 } 2310 2311 /** 2312 * Gets the persistenceService attribute. 2313 * @return Returns the persistenceService. 2314 */ 2315 public PersistenceService getPersistenceService() { 2316 return persistenceService; 2317 } 2318 2319 /** 2320 * Gets the scrubberValidator attribute. 2321 * @return Returns the scrubberValidator. 2322 */ 2323 public ScrubberValidator getScrubberValidator() { 2324 return scrubberValidator; 2325 } 2326 2327 /** 2328 * Gets the runDateService attribute. 2329 * @return Returns the runDateService. 2330 */ 2331 public RunDateService getRunDateService() { 2332 return runDateService; 2333 } 2334 2335 /** 2336 * Gets the accountingCycleCachingService attribute. 2337 * @return Returns the accountingCycleCachingService. 2338 */ 2339 public AccountingCycleCachingService getAccountingCycleCachingService() { 2340 return accountingCycleCachingService; 2341 } 2342 2343 /** 2344 * Gets the scrubberReportWriterService attribute. 2345 * @return Returns the scrubberReportWriterService. 2346 */ 2347 public DocumentNumberAwareReportWriterService getScrubberReportWriterService() { 2348 return scrubberReportWriterService; 2349 } 2350 2351 /** 2352 * Gets the scrubberLedgerReportWriterService attribute. 2353 * @return Returns the scrubberLedgerReportWriterService. 2354 */ 2355 public DocumentNumberAwareReportWriterService getScrubberLedgerReportWriterService() { 2356 return scrubberLedgerReportWriterService; 2357 } 2358 2359 /** 2360 * Gets the scrubberListingReportWriterService attribute. 2361 * @return Returns the scrubberListingReportWriterService. 2362 */ 2363 public DocumentNumberAwareReportWriterService getScrubberListingReportWriterService() { 2364 return scrubberListingReportWriterService; 2365 } 2366 2367 /** 2368 * Gets the scrubberBadBalanceListingReportWriterService attribute. 2369 * @return Returns the scrubberBadBalanceListingReportWriterService. 2370 */ 2371 public ReportWriterService getScrubberBadBalanceListingReportWriterService() { 2372 return scrubberBadBalanceListingReportWriterService; 2373 } 2374 2375 /** 2376 * Gets the demergerRemovedTransactionsListingReportWriterService attribute. 2377 * @return Returns the demergerRemovedTransactionsListingReportWriterService. 2378 */ 2379 public ReportWriterService getDemergerRemovedTransactionsListingReportWriterService() { 2380 return demergerRemovedTransactionsListingReportWriterService; 2381 } 2382 2383 /** 2384 * Gets the demergerReportWriterService attribute. 2385 * @return Returns the demergerReportWriterService. 2386 */ 2387 public ReportWriterService getDemergerReportWriterService() { 2388 return demergerReportWriterService; 2389 } 2390 2391 /** 2392 * Gets the preScrubberService attribute. 2393 * @return Returns the preScrubberService. 2394 */ 2395 public PreScrubberService getPreScrubberService() { 2396 return preScrubberService; 2397 } 2398 2399 /** 2400 * Gets the parameterService attribute. 2401 * @return Returns the parameterService. 2402 */ 2403 public ParameterService getParameterService() { 2404 return parameterService; 2405 } 2406 2407 /** 2408 * Sets the preScrubberReportWriterService attribute value. 2409 * @param preScrubberReportWriterService The preScrubberReportWriterService to set. 2410 */ 2411 public void setPreScrubberReportWriterService(DocumentNumberAwareReportWriterService preScrubberReportWriterService) { 2412 this.preScrubberReportWriterService = preScrubberReportWriterService; 2413 } 2414 2415 /** 2416 * Sets the businessObjectService attribute value. 2417 * @param businessObjectService The businessObjectService to set. 2418 */ 2419 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 2420 this.businessObjectService = businessObjectService; 2421 } 2422 2423 }