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