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