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.module.endow.batch.service.impl;
017    
018    import java.io.File;
019    import java.io.FileNotFoundException;
020    import java.io.IOException;
021    import java.io.PrintStream;
022    import java.math.BigDecimal;
023    import java.util.ArrayList;
024    import java.util.Collection;
025    
026    import org.apache.commons.lang.StringUtils;
027    import org.kuali.kfs.gl.businessobject.OriginEntryFull;
028    import org.kuali.kfs.gl.businessobject.Transaction;
029    import org.kuali.kfs.module.endow.EndowConstants;
030    import org.kuali.kfs.module.endow.EndowParameterKeyConstants;
031    import org.kuali.kfs.module.endow.batch.GeneralLedgerInterfaceBatchProcessStep;
032    import org.kuali.kfs.module.endow.batch.dataaccess.GLInterfaceBatchProcessDao;
033    import org.kuali.kfs.module.endow.batch.service.GeneralLedgerInterfaceBatchProcessService;
034    import org.kuali.kfs.module.endow.businessobject.EndowmentAccountingLineBase;
035    import org.kuali.kfs.module.endow.businessobject.GLInterfaceBatchExceptionReportHeader;
036    import org.kuali.kfs.module.endow.businessobject.GLInterfaceBatchExceptionTableRowValues;
037    import org.kuali.kfs.module.endow.businessobject.GLInterfaceBatchStatisticsReportDetailTableRow;
038    import org.kuali.kfs.module.endow.businessobject.GLInterfaceBatchTotalsProcessedReportHeader;
039    import org.kuali.kfs.module.endow.businessobject.GLInterfaceBatchTotalsProcessedTableRowValues;
040    import org.kuali.kfs.module.endow.businessobject.GlInterfaceBatchProcessKemLine;
041    import org.kuali.kfs.module.endow.dataaccess.EndowmentAccountingLineBaseDao;
042    import org.kuali.kfs.module.endow.dataaccess.GLLinkDao;
043    import org.kuali.kfs.module.endow.dataaccess.TransactionArchiveDao;
044    import org.kuali.kfs.module.endow.document.service.KEMService;
045    import org.kuali.kfs.sys.KFSConstants;
046    import org.kuali.kfs.sys.service.ReportWriterService;
047    import org.kuali.rice.kns.service.ParameterService;
048    import org.kuali.rice.kns.util.KualiDecimal;
049    import org.springframework.transaction.annotation.Transactional;
050    
051    /**
052     * This class implements the GeneralLedgerInterfaceBatchProcessService.
053     */
054    @Transactional
055    public class GeneralLedgerInterfaceBatchProcessServiceImpl implements GeneralLedgerInterfaceBatchProcessService {
056        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(GeneralLedgerInterfaceBatchProcessServiceImpl.class);
057        
058        protected String batchFileDirectoryName;
059        
060        protected KEMService kemService;
061        protected GLLinkDao gLLinkDao;
062        protected TransactionArchiveDao transactionArchiveDao;
063        protected EndowmentAccountingLineBaseDao endowmentAccountingLineBaseDao;
064        protected GLInterfaceBatchProcessDao gLInterfaceBatchProcessDao;
065        protected ParameterService parameterService;
066        
067        //report writer services for statistics, totals processed, and exception reports
068        protected ReportWriterService gLInterfaceBatchStatisticsReportsWriterService;
069        protected ReportWriterService gLInterfaceBatchTotalProcessedReportsWriterService;
070        protected ReportWriterService gLInterfaceBatchExceptionReportsWriterService;
071        
072        //report headers..bos
073        protected GLInterfaceBatchExceptionReportHeader gLInterfaceBatchExceptionReportHeader;
074        protected GLInterfaceBatchTotalsProcessedReportHeader gLInterfaceBatchTotalProcessedReportHeader;
075        
076        //Exception Report Table Row value and Row Message only...bos
077        protected GLInterfaceBatchExceptionTableRowValues gLInterfaceBatchExceptionTableRowValues;
078        protected GLInterfaceBatchExceptionTableRowValues gLInterfaceBatchExceptionRowReason;    
079        
080        //Totals Processed report's table row..details, subtotal at chart, subtotal at document type and grand total lines
081        protected GLInterfaceBatchTotalsProcessedTableRowValues gLInterfaceBatchTotalsProcessedTableRowValues;
082        //statics table row values...bos
083        protected GLInterfaceBatchStatisticsReportDetailTableRow gLInterfaceBatchStatisticsReportDetailTableRow;
084        
085        //the properties to totals processed at chart/object level..sub totals.
086        protected BigDecimal chartObjectDebitAmountSubTotal = BigDecimal.ZERO;
087        protected BigDecimal chartObjectCreditAmountSubTotal = BigDecimal.ZERO;
088        protected long chartObjectNumberOfRecordsSubTotal = 0;
089        
090        //the properties to totals processed at chart level..sub totals.
091        protected BigDecimal chartDebitAmountSubTotal = BigDecimal.ZERO;
092        protected BigDecimal chartCreditAmountSubTotal = BigDecimal.ZERO;
093        protected long chartNumberOfRecordsSubTotal = 0;
094        
095        //the properties to totals processed at Document Type level..sub totals.
096        protected BigDecimal documentTypeDebitAmountSubTotal = BigDecimal.ZERO;
097        protected BigDecimal documentTypeCreditAmountSubTotal = BigDecimal.ZERO;
098        protected long documentTypeNumberOfRecordsSubTotal = 0;
099        
100        //the properties to totals processed at Document Type level..Grand totals.
101        protected BigDecimal documentTypeDebitAmountGrandTotal = BigDecimal.ZERO;
102        protected BigDecimal documentTypeCreditAmountGrandTotal = BigDecimal.ZERO;
103        protected long documentTypeNumberOfRecordsGrandTotal = 0;    
104        
105        protected String previousDocumentTypeCode = null;
106        protected String previousChartCode = null;
107        protected String previousObjectCode = null;
108    
109        protected boolean documentTypeWritten = false ;
110        protected boolean statisticsHeaderWritten = false;
111        
112        /**
113         * Constructs a GeneralLedgerInterfaceBatchProcessServiceImpl instance
114         */
115        public GeneralLedgerInterfaceBatchProcessServiceImpl() {
116            //report writer headers
117            gLInterfaceBatchExceptionReportHeader = new GLInterfaceBatchExceptionReportHeader();
118            gLInterfaceBatchTotalProcessedReportHeader = new GLInterfaceBatchTotalsProcessedReportHeader();
119            
120            //exception report detail and a reason lines.
121            gLInterfaceBatchExceptionTableRowValues = new GLInterfaceBatchExceptionTableRowValues();
122            gLInterfaceBatchExceptionRowReason = new GLInterfaceBatchExceptionTableRowValues();  
123            
124            //Totals processed report....This one will be used to write all the rows in totals procesed report.
125            gLInterfaceBatchTotalsProcessedTableRowValues = new GLInterfaceBatchTotalsProcessedTableRowValues();
126            
127            //statistics report...
128            gLInterfaceBatchStatisticsReportDetailTableRow = new GLInterfaceBatchStatisticsReportDetailTableRow();
129        }
130    
131        /**
132         * The process is intended to serve to consolidate KEM activity for the day into  
133         * valid general ledger debits and credits to update the institution's records.
134         * @see oorg.kuali.kfs.module.endow.batch.service.GeneralLedgerInterfaceBatchProcessService#processKEMActivityToCreateGLEntries
135         * return boolean true if successful else false
136         */
137        public boolean processKEMActivityToCreateGLEntries() {
138            LOG.info("processKEMActivityToCreateGLEntries() started.");
139            
140            boolean success = true;
141            
142            writeReportHeaders();
143            
144            //main job to process KEM activity...
145            success = processKEMActivity();
146            
147            LOG.info("processKEMActivityToCreateGLEntries() exited.");
148            
149            return success;
150        }
151        
152        /**
153         * process the KEM Activity transactions to create gl entries in the origin entry file
154         */
155        public boolean processKEMActivity() {
156            LOG.info("processKEMActivity() started.");
157            
158            boolean success = true;
159            previousDocumentTypeCode = null;
160            previousChartCode = null;
161            previousObjectCode = null;
162            
163            PrintStream OUTPUT_KEM_TO_GL_DATA_FILE_ps = createActivityOriginEntryFullStream();
164            
165            String combineTransactions = parameterService.getParameterValue(GeneralLedgerInterfaceBatchProcessStep.class, EndowParameterKeyConstants.GLInterfaceBatchProcess.COMBINE_ENDOWMENT_GL_ENTRIES_IND);
166            java.util.Date postedDate = kemService.getCurrentDate();
167            
168            Collection<GLInterfaceBatchStatisticsReportDetailTableRow> statisticsReportRows = new ArrayList<GLInterfaceBatchStatisticsReportDetailTableRow>();
169            
170            Collection<GlInterfaceBatchProcessKemLine> transactionArchives = new ArrayList<GlInterfaceBatchProcessKemLine>();
171            
172            //get all the available document types names sorted
173            Collection<String> documentTypes = gLInterfaceBatchProcessDao.findDocumentTypes();
174    
175            for (String documentType : documentTypes) {
176                if (!EndowConstants.DocumentTypeNames.ENDOWMENT_CORPUS_ADJUSTMENT.equalsIgnoreCase(documentType) &&
177                        !EndowConstants.DocumentTypeNames.ENDOWMENT_UNIT_SHARE_ADJUSTMENT.equalsIgnoreCase(documentType)) {
178                    //add a new statisticsReportRow to the collection...
179                    GLInterfaceBatchStatisticsReportDetailTableRow statisticsDataRow = new GLInterfaceBatchStatisticsReportDetailTableRow();
180                    statisticsDataRow.setDocumentType(documentType);
181                    
182                    if (EndowConstants.YES.equalsIgnoreCase(combineTransactions)) {
183                        //combine the entries...GL lines based on chart/account/object code
184                        transactionArchives = gLInterfaceBatchProcessDao.getAllKemCombinedTransactionsByDocumentType(documentType, postedDate);
185                    }
186                    else {
187                        //single transaction gl lines...
188                        transactionArchives = gLInterfaceBatchProcessDao.getAllKemTransactionsByDocumentType(documentType, postedDate);
189                    }
190                    
191                    if (transactionArchives.size() > 0) {
192                        if (previousDocumentTypeCode == null) {
193                            previousDocumentTypeCode = documentType;
194                        }
195                        success = createGlEntriesForTransactionArchives(documentType, transactionArchives, OUTPUT_KEM_TO_GL_DATA_FILE_ps, postedDate, statisticsDataRow);
196                    }
197                    
198                    //add statistics row to the collection
199                    statisticsReportRows.add(statisticsDataRow);
200                    
201                    if (transactionArchives.size() > 0) {
202                        processDocumentTypeTotals();
203                    }
204                }
205            }
206            
207            //grand total line...
208            writeTotalsProcessedGrandTotalsLine();
209            
210            OUTPUT_KEM_TO_GL_DATA_FILE_ps.close();
211            
212            //write the statistics report now...
213            writeStatisticsReport(statisticsReportRows);
214            
215            LOG.info("processKEMActivity() exited.");
216            
217            return success;
218        }
219        
220        /**
221         * Writes the reports headers for totals processed, waived and accrued fee, and exceptions reports.
222         */
223        protected void writeReportHeaders() {
224            //writes the exception report header
225            gLInterfaceBatchExceptionReportsWriterService.writeNewLines(1);
226            gLInterfaceBatchExceptionReportsWriterService.writeTableHeader(gLInterfaceBatchExceptionReportHeader);
227    
228            //writes the Totals Processed report header....
229            gLInterfaceBatchTotalProcessedReportsWriterService.writeNewLines(1);
230            gLInterfaceBatchTotalProcessedReportsWriterService.writeTableHeader(gLInterfaceBatchTotalProcessedReportHeader);
231        }
232        
233        /**
234         * create the main data file in the stating\gl\originEntry folder
235         */
236        PrintStream createActivityOriginEntryFullStream() {
237            try{
238                PrintStream OUTPUT_KEM_TO_GL_FILE_ps = new PrintStream(batchFileDirectoryName + File.separator + EndowConstants.KemToGLInterfaceBatchProcess.KEM_TO_GL_ACTIVITY_OUTPUT_DATA_FILE + EndowConstants.KemToGLInterfaceBatchProcess.DATA_FILE_SUFFIX);
239                return OUTPUT_KEM_TO_GL_FILE_ps;
240                
241            } catch (FileNotFoundException e1) {
242                e1.printStackTrace();
243                throw new RuntimeException("createActivityOriginEntryFullStream Stopped: " + e1.getMessage(), e1);
244            }
245        }
246    
247        /**
248         * For the transaction archives this method creates GL entries into the output file.
249         * @param documentType
250         * @param transactionArchives transaction archive records sorted by document type name
251         * @param postedDate
252         * @param statisticsDataRow to collect the statistics about GL entries, exception entries
253         * @param OUTPUT_KEM_TO_GL_DATA_FILE_ps GL origin entry  file
254         * @return success true if origin entry  files are created, false if files are not created.
255         */
256        public boolean createGlEntriesForTransactionArchives(String documentType, Collection<GlInterfaceBatchProcessKemLine> transactionArchives, 
257                                                             PrintStream OUTPUT_KEM_TO_GL_DATA_FILE_ps, 
258                                                             java.util.Date postedDate, GLInterfaceBatchStatisticsReportDetailTableRow statisticsDataRow) {
259            boolean success = true;
260            
261            for (GlInterfaceBatchProcessKemLine transactionArchive : transactionArchives) {
262                if (previousChartCode == null && previousObjectCode == null) {
263                    previousChartCode = transactionArchive.getChartCode();
264                    previousObjectCode = transactionArchive.getObjectCode();
265                }
266                //process cash activity
267                if (transactionArchive.getSubTypeCode().equalsIgnoreCase(EndowConstants.TransactionSubTypeCode.CASH)) {
268                    //process the cash entry record...
269                    success &= createCashEntry(transactionArchive, OUTPUT_KEM_TO_GL_DATA_FILE_ps, postedDate, statisticsDataRow);
270                }
271                
272                //process non-cash activity
273                if (transactionArchive.getSubTypeCode().equalsIgnoreCase(EndowConstants.TransactionSubTypeCode.NON_CASH)) {
274                    //process the non-cash entry record...
275                    success &= createNonCashEntry(transactionArchive, OUTPUT_KEM_TO_GL_DATA_FILE_ps, postedDate, statisticsDataRow);
276                }
277                
278                // if GLET or EGLT then create unique document number accounting lines gl entries.....
279                if (transactionArchive.getTypeCode().equalsIgnoreCase(EndowConstants.DocumentTypeNames.ENDOWMENT_TO_GENERAL_LEDGER_TRANSFER) || 
280                        transactionArchive.getTypeCode().equalsIgnoreCase(EndowConstants.DocumentTypeNames.GENERAL_LEDGER_TO_ENDOWMENT_TRANSFER)) {
281                    //process the GLET or EGLT records..
282                    success &= createGLEntriesForEGLTOrGLET(transactionArchive, OUTPUT_KEM_TO_GL_DATA_FILE_ps, postedDate, statisticsDataRow);
283                }
284            }
285            
286            return success;
287        }
288        
289        /**
290         * method to create cash entry GL record
291         * @param transactionArchive,OUTPUT_KEM_TO_GL_DATA_FILE_ps, postedDate, statisticsDataRow
292         * @return true if successful, else false
293         */
294        protected boolean createCashEntry(GlInterfaceBatchProcessKemLine transactionArchive, PrintStream OUTPUT_KEM_TO_GL_DATA_FILE_ps,
295                                          java.util.Date postedDate, GLInterfaceBatchStatisticsReportDetailTableRow statisticsDataRow) {
296            boolean success = true;
297            
298            OriginEntryFull oef = createOriginEntryFull(transactionArchive, postedDate, statisticsDataRow);
299            
300            try {
301                createOutputEntry(oef, OUTPUT_KEM_TO_GL_DATA_FILE_ps);
302                statisticsDataRow.increaseGLEntriesGeneratedCount();
303                updateTotalsProcessed(transactionArchive);            
304            } catch (Exception ex) {
305                //write the error details to the exception report...
306                statisticsDataRow.increaseNumberOfExceptionsCount();
307                writeExceptionRecord(transactionArchive, ex.getMessage());            
308                return false;
309            }
310            
311            //need to create an net gain/loss entry...if document type name = EAD....
312            if (transactionArchive.getTypeCode().equalsIgnoreCase(EndowConstants.DocumentTypeNames.ENDOWMENT_ASSET_DECREASE)) {
313                if ((transactionArchive.getLongTermGainLoss().add(transactionArchive.getShortTermGainLoss())).compareTo(BigDecimal.ZERO) != 0) {
314                    success = createGainLossEntry(oef, transactionArchive, OUTPUT_KEM_TO_GL_DATA_FILE_ps, statisticsDataRow);
315                }
316            }
317            
318            return success;
319        }
320    
321        /**
322         * method to create non-cash entry GL record
323         * @param transactionArchive,OUTPUT_KEM_TO_GL_DATA_FILE_ps, postedDate
324         * @return true if successful, else false
325         */
326        protected boolean createNonCashEntry(GlInterfaceBatchProcessKemLine transactionArchive, PrintStream OUTPUT_KEM_TO_GL_DATA_FILE_ps, java.util.Date postedDate, GLInterfaceBatchStatisticsReportDetailTableRow statisticsDataRow) {
327            boolean success = true;
328            
329            OriginEntryFull oef = createOriginEntryFull(transactionArchive, postedDate, statisticsDataRow);
330            BigDecimal transactionAmount = getTransactionAmount(transactionArchive);
331            
332            try {
333                createOutputEntry(oef, OUTPUT_KEM_TO_GL_DATA_FILE_ps);
334                statisticsDataRow.increaseGLEntriesGeneratedCount();
335                updateTotalsProcessed(transactionArchive);             
336            } catch (Exception ex) {
337                //write the error details to the exception report...
338                statisticsDataRow.increaseNumberOfExceptionsCount();
339                writeExceptionRecord(transactionArchive, ex.getMessage());            
340                return false;
341            }
342            
343            //create the offset or (loss/gain entry for EAD) document types where subtype is Non-Cash
344            if (!EndowConstants.DocumentTypeNames.ENDOWMENT_CORPORATE_REORGANZATION.equalsIgnoreCase(transactionArchive.getTypeCode())) {
345                success = createOffsetEntry(oef, transactionArchive, OUTPUT_KEM_TO_GL_DATA_FILE_ps, statisticsDataRow);
346            }
347            
348            return success;
349        }
350    
351        /**
352         * method to create a gain/loss record when document type = EAD...
353         * @param oef OriginEntryFull 
354         * @param transactionArchive
355         * @param OUTPUT_KEM_TO_GL_DATA_FILE_ps the output file
356         * @param statisticsDataRow
357         * @return success true if successfully created offset or gain loss entry else false
358         */
359        protected boolean createGainLossEntry(OriginEntryFull oef, GlInterfaceBatchProcessKemLine transactionArchive, PrintStream OUTPUT_KEM_TO_GL_DATA_FILE_ps, GLInterfaceBatchStatisticsReportDetailTableRow statisticsDataRow) {
360            boolean success = true;
361            
362            //need to create an net gain/loss entry...if document type name = EAD....
363            if (transactionArchive.getTypeCode().equalsIgnoreCase(EndowConstants.DocumentTypeNames.ENDOWMENT_ASSET_DECREASE)) {
364                oef.setFinancialObjectCode(parameterService.getParameterValue(GeneralLedgerInterfaceBatchProcessStep.class, EndowParameterKeyConstants.GLInterfaceBatchProcess.CASH_SALE_GAIN_LOSS_OBJECT_CODE));
365                BigDecimal transactionAmount = transactionArchive.getShortTermGainLoss().add(transactionArchive.getLongTermGainLoss());
366                oef.setTransactionLedgerEntryAmount(new KualiDecimal(transactionAmount.abs()));
367                oef.setTransactionDebitCreditCode(getTransactionDebitCreditCodeForOffSetEntry(transactionAmount));
368                try {
369                    createOutputEntry(oef, OUTPUT_KEM_TO_GL_DATA_FILE_ps);
370                    statisticsDataRow.increaseGLEntriesGeneratedCount();
371                    
372                    GlInterfaceBatchProcessKemLine transactionArchiveLossGain = new GlInterfaceBatchProcessKemLine();
373                    transactionArchiveLossGain.setTypeCode(transactionArchive.getTypeCode());
374                    transactionArchiveLossGain.setChartCode(transactionArchive.getChartCode());
375                    transactionArchiveLossGain.setObjectCode(oef.getFinancialObjectCode());
376                    transactionArchiveLossGain.setShortTermGainLoss(transactionArchive.getShortTermGainLoss());
377                    transactionArchiveLossGain.setLongTermGainLoss(transactionArchive.getLongTermGainLoss());
378                    transactionArchiveLossGain.setSubTypeCode(transactionArchive.getSubTypeCode());
379                    transactionArchiveLossGain.setHoldingCost(transactionArchive.getHoldingCost());
380                    transactionArchiveLossGain.setTransactionArchiveIncomeAmount(transactionArchive.getTransactionArchiveIncomeAmount());
381                    transactionArchiveLossGain.setTransactionArchivePrincipalAmount(transactionArchive.getTransactionArchivePrincipalAmount());
382                    
383                    updateTotalsProcessed(transactionArchiveLossGain);                 
384                } catch (Exception ex) {
385                    //write the error details to the exception report...
386                    statisticsDataRow.increaseNumberOfExceptionsCount();
387                    writeExceptionRecord(transactionArchive, ex.getMessage());            
388                    success = false;
389                }
390            }
391            
392            return success;
393        }
394        
395        /**
396         * method to create an offset record when document type is NON-CASH
397         * @param oef OriginEntryFull 
398         * @param transactionArchive
399         * @param OUTPUT_KEM_TO_GL_DATA_FILE_ps the output file
400         * @param statisticsDataRow
401         * @return success true if successfully created offset or gain loss entry else false
402         */
403        protected boolean createOffsetEntry(OriginEntryFull oef, GlInterfaceBatchProcessKemLine transactionArchive, PrintStream OUTPUT_KEM_TO_GL_DATA_FILE_ps, GLInterfaceBatchStatisticsReportDetailTableRow statisticsDataRow) {
404            boolean success = true;
405            
406            oef.setFinancialObjectCode(transactionArchive.getNonCashOffsetObjectCode());
407            
408            BigDecimal transactionAmount = transactionArchive.getHoldingCost();
409            oef.setTransactionLedgerEntryAmount(new KualiDecimal(transactionAmount.abs()));
410            oef.setTransactionDebitCreditCode(getTransactionDebitCreditCodeForOffSetEntry(transactionAmount));
411            try {
412                createOutputEntry(oef, OUTPUT_KEM_TO_GL_DATA_FILE_ps);
413                statisticsDataRow.increaseGLEntriesGeneratedCount();
414                    
415                GlInterfaceBatchProcessKemLine transactionArchiveLossGain = new GlInterfaceBatchProcessKemLine();
416                transactionArchiveLossGain.setTypeCode(transactionArchive.getTypeCode());
417                transactionArchiveLossGain.setChartCode(transactionArchive.getChartCode());
418                transactionArchiveLossGain.setObjectCode(oef.getFinancialObjectCode());
419                transactionArchiveLossGain.setShortTermGainLoss(transactionArchive.getShortTermGainLoss());
420                transactionArchiveLossGain.setLongTermGainLoss(transactionArchive.getLongTermGainLoss());
421                transactionArchiveLossGain.setSubTypeCode(transactionArchive.getSubTypeCode());
422                transactionArchiveLossGain.setHoldingCost(transactionArchive.getHoldingCost());
423                transactionArchiveLossGain.setTransactionArchiveIncomeAmount(transactionArchive.getTransactionArchiveIncomeAmount());
424                transactionArchiveLossGain.setTransactionArchivePrincipalAmount(transactionArchive.getTransactionArchivePrincipalAmount());
425                    
426                updateTotalsProcessed(transactionArchiveLossGain);                 
427            } catch (Exception ex) {
428                //write the error details to the exception report...
429                statisticsDataRow.increaseNumberOfExceptionsCount();
430                writeExceptionRecord(transactionArchive, ex.getMessage());            
431                success = false;
432            }
433            
434            return success;
435        }
436        
437        /**
438         * method to create cash entry GL record for each transaction archive financial doc number
439         * @param transactionArchive,OUTPUT_KEM_TO_GL_DATA_FILE_ps, postedDate
440         * @return true if successful, else false
441         */
442        protected boolean createGLEntriesForEGLTOrGLET(GlInterfaceBatchProcessKemLine transactionArchive, PrintStream OUTPUT_KEM_TO_GL_DATA_FILE_ps, java.util.Date postedDate, GLInterfaceBatchStatisticsReportDetailTableRow statisticsDataRow) {
443            boolean success = true;
444            
445            Collection<EndowmentAccountingLineBase> endowmentAccountingLines = endowmentAccountingLineBaseDao.getAllEndowmentAccountingLines(transactionArchive.getDocumentNumber());
446            for (EndowmentAccountingLineBase endowmentAccountingLineBase : endowmentAccountingLines) {
447                OriginEntryFull oef = new OriginEntryFull();
448                
449                oef.setChartOfAccountsCode(endowmentAccountingLineBase.getChartOfAccountsCode());
450                oef.setAccountNumber(endowmentAccountingLineBase.getAccountNumber());
451                oef.setSubAccountNumber(endowmentAccountingLineBase.getSubAccountNumber());
452                oef.setFinancialObjectCode(endowmentAccountingLineBase.getFinancialObjectCode());
453                oef.setFinancialSubObjectCode(endowmentAccountingLineBase.getFinancialSubObjectCode());
454                oef.setFinancialDocumentTypeCode(transactionArchive.getTypeCode());
455                oef.setFinancialSystemOriginationCode(EndowConstants.KemToGLInterfaceBatchProcess.SYSTEM_ORIGINATION_CODE_FOR_ENDOWMENT);
456                oef.setDocumentNumber(transactionArchive.getDocumentNumber());
457                oef.setTransactionLedgerEntryDescription(getTransactionDescription(transactionArchive, postedDate));
458                BigDecimal transactionAmount = getTransactionAmount(transactionArchive);
459                oef.setTransactionLedgerEntryAmount(endowmentAccountingLineBase.getAmount());
460                if (endowmentAccountingLineBase.getFinancialDocumentLineTypeCode().equalsIgnoreCase(EndowConstants.TRANSACTION_LINE_TYPE_SOURCE)) {
461                    oef.setTransactionDebitCreditCode(EndowConstants.KemToGLInterfaceBatchProcess.DEBIT_CODE);    
462                }
463                else {
464                    oef.setTransactionDebitCreditCode(EndowConstants.KemToGLInterfaceBatchProcess.CREDIT_CODE);    
465                }
466                oef.setProjectCode(endowmentAccountingLineBase.getProjectCode());
467                oef.setOrganizationReferenceId(endowmentAccountingLineBase.getOrganizationReferenceId());
468                
469                try {
470                    createOutputEntry(oef, OUTPUT_KEM_TO_GL_DATA_FILE_ps);
471                    statisticsDataRow.increaseGLEntriesGeneratedCount();
472                    updateTotalsProcessed(transactionArchive);                 
473                } catch (Exception ex) {
474                    //write the error details to the exception report...
475                    statisticsDataRow.increaseNumberOfExceptionsCount();
476                    writeExceptionRecord(transactionArchive, ex.getMessage());            
477                    return false;
478                }
479            } //end of for loop
480            
481            return success;
482        }
483        
484        /**
485         * method to create origin entry and populate the fields
486         * @param transactionArchive, postedDate
487         * @return oef
488         */
489        protected OriginEntryFull createOriginEntryFull(GlInterfaceBatchProcessKemLine transactionArchive,
490                                                        java.util.Date postedDate, GLInterfaceBatchStatisticsReportDetailTableRow statisticsDataRow) {
491    
492            OriginEntryFull oef = new OriginEntryFull();
493    
494            try {
495                oef.setChartOfAccountsCode(transactionArchive.getChartCode());
496                oef.setAccountNumber(transactionArchive.getAccountNumber());
497                oef.setFinancialObjectCode(transactionArchive.getObjectCode());
498                oef.setFinancialDocumentTypeCode(transactionArchive.getTypeCode());
499                oef.setFinancialSystemOriginationCode(EndowConstants.KemToGLInterfaceBatchProcess.SYSTEM_ORIGINATION_CODE_FOR_ENDOWMENT);
500                oef.setDocumentNumber(transactionArchive.getDocumentNumber());
501                oef.setTransactionLedgerEntryDescription(getTransactionDescription(transactionArchive, postedDate));
502                BigDecimal transactionAmount = getTransactionAmount(transactionArchive);
503                oef.setTransactionLedgerEntryAmount(new KualiDecimal(transactionAmount.abs()));
504                oef.setTransactionDebitCreditCode(getTransactionDebitCreditCode(transactionArchive.getTypeCode(), transactionAmount, transactionArchive.getSubTypeCode()));
505            }
506            catch (Exception ex) {
507                statisticsDataRow.increaseNumberOfExceptionsCount();
508                writeExceptionRecord(transactionArchive, ex.getMessage());            
509            }
510            
511            return oef;
512        }
513        /**
514         * method to get transaction description
515         * @param transactionArchive
516         * @return transaction description
517         */
518        protected String getTransactionDescription(GlInterfaceBatchProcessKemLine transactionArchive, java.util.Date postedDate) {
519            String actityType = null;
520            
521            if (transactionArchive.getSubTypeCode().equalsIgnoreCase(EndowConstants.TransactionSubTypeCode.CASH)) {
522                actityType = EndowConstants.KemToGLInterfaceBatchProcess.SUB_TYPE_CASH;
523            }
524            else {
525                actityType = EndowConstants.KemToGLInterfaceBatchProcess.SUB_TYPE_NON_CASH;   
526            }
527            
528            return ("Net " + transactionArchive.getTypeCode() + " " + actityType + " Activity on " + postedDate.toString());
529        }
530    
531        /**
532         * method to get transaction amount
533         * @param transactionArchive
534         * @return transaction amount
535         */
536        protected BigDecimal getTransactionAmount(GlInterfaceBatchProcessKemLine transactionArchive) {
537            BigDecimal transactionAmount = BigDecimal.ZERO;
538            
539            if (transactionArchive.getSubTypeCode().equalsIgnoreCase(EndowConstants.TransactionSubTypeCode.CASH)) {
540                if (transactionArchive.getTypeCode().equalsIgnoreCase(EndowConstants.DocumentTypeNames.ENDOWMENT_ASSET_DECREASE)) {
541                    transactionAmount = transactionArchive.getHoldingCost();
542                } 
543                else {
544                    transactionAmount = transactionArchive.getTransactionArchiveIncomeAmount().add(transactionArchive.getTransactionArchivePrincipalAmount());
545                }
546            }
547            else {
548                transactionAmount = transactionArchive.getHoldingCost();
549            }
550            
551            return transactionAmount;
552        }
553        
554        /**
555         * method to get transaction debit/credit code
556         * @param transactionAmount
557         * @param subTypeCode
558         * @return transaction debit or credit code
559         */
560        protected String getTransactionDebitCreditCode(String documentType, BigDecimal transactionAmount, String subTypeCode) {
561            if (subTypeCode.equalsIgnoreCase(EndowConstants.TransactionSubTypeCode.CASH)) {
562                if (transactionAmount.compareTo(BigDecimal.ZERO) == 1) {
563                    if (EndowConstants.DocumentTypeNames.ENDOWMENT_ASSET_DECREASE.equalsIgnoreCase(documentType)) {
564                        return (EndowConstants.KemToGLInterfaceBatchProcess.DEBIT_CODE);
565                    } else {
566                        return (EndowConstants.KemToGLInterfaceBatchProcess.CREDIT_CODE);
567                    }
568                }
569                else {
570                    if (EndowConstants.DocumentTypeNames.ENDOWMENT_ASSET_DECREASE.equalsIgnoreCase(documentType)) {
571                        return (EndowConstants.KemToGLInterfaceBatchProcess.CREDIT_CODE);   
572                    }
573                    else {
574                        return (EndowConstants.KemToGLInterfaceBatchProcess.DEBIT_CODE);
575                    }
576                }
577            }
578            else {
579                if (transactionAmount.compareTo(BigDecimal.ZERO) == 1) {
580                    return (EndowConstants.KemToGLInterfaceBatchProcess.DEBIT_CODE);
581                }
582                else {
583                    return (EndowConstants.KemToGLInterfaceBatchProcess.CREDIT_CODE);
584                }
585            }
586        }
587    
588        /**
589         * method to get transaction debit/credit code
590         * @param transactionAmount
591         * @return transaction debit or credit code
592         */
593        protected String getTransactionDebitCreditCodeForOffSetEntry(BigDecimal transactionAmount) {
594            if (transactionAmount.compareTo(BigDecimal.ZERO) == 1) {
595                return (EndowConstants.KemToGLInterfaceBatchProcess.CREDIT_CODE);
596            }
597            else {
598                return (EndowConstants.KemToGLInterfaceBatchProcess.DEBIT_CODE);
599            }
600        }
601        
602        protected void createOutputEntry(Transaction entry, PrintStream group) throws IOException {
603            OriginEntryFull oef = new OriginEntryFull();
604            
605            oef.copyFieldsFromTransaction(entry);
606            oef.setUniversityFiscalYear(null);
607            
608            try {
609                group.printf("%s\n", oef.getLine());
610            }
611            catch (Exception ex) {
612                throw new IOException(ex.toString());
613            }
614        }
615    
616        /**
617         * method to update the totals processed amount variables.
618         * If same chart and object code then update totals, else
619         * if chart is different then first write out the object level totals line, then add the
620         * chart totals and then write the chart level totals line.  If only different object code
621         * then write the object code level totals line and then add the totals to the chart
622         * level totals.
623         * @param transactionArchive
624         */
625        protected void updateTotalsProcessed(GlInterfaceBatchProcessKemLine transactionArchive) {
626            if (StringUtils.equals(previousChartCode, transactionArchive.getChartCode()) &&
627                    StringUtils.equals(previousObjectCode, transactionArchive.getObjectCode())) {
628                updateTotals(transactionArchive);
629            }
630            else {
631                if (!StringUtils.equals(previousChartCode, transactionArchive.getChartCode())) {
632                    writeTotalsProcessedObjectDetailTotalsLine(previousDocumentTypeCode, previousChartCode, previousObjectCode);
633                    addTotalsToChartTotals();
634                    previousObjectCode = transactionArchive.getObjectCode();
635                    
636                    updateTotals(transactionArchive);                
637                    
638                    writeTotalsProcessedChartDetailTotalsLine();
639                    addChartTotalsToDocumentTypeTotals();
640                    updateTotals(transactionArchive);   
641                    previousChartCode = transactionArchive.getChartCode();
642                }
643                else {
644                    if (!StringUtils.equals(previousObjectCode, transactionArchive.getObjectCode())) {
645                        //object code change..reset the total and add the object detail line
646                        //current detail totals to the sub totals...
647                        writeTotalsProcessedObjectDetailTotalsLine(previousDocumentTypeCode, previousChartCode, previousObjectCode);
648                        addTotalsToChartTotals();
649                        previousObjectCode = transactionArchive.getObjectCode();
650                        
651                        updateTotals(transactionArchive);                
652                    }
653                }
654            }
655        }
656        /**
657         * add debit and credit totals and number of lines processed to detail line.
658         * If object code equals to loss/gain object code, then total is short term loss/gai added to
659         * long term loss/gain amount else total amount is retrieved by calling
660         * method getTransactionAmount.  The debit or credit code is determined based on
661         * the totalAmount value.
662         * @param transactionArchive
663         */
664        protected void updateTotals(GlInterfaceBatchProcessKemLine transactionArchive) {
665            BigDecimal totalAmount =  BigDecimal.ZERO;
666            String debitCreditCode = null;
667            
668            String lossGainObjectCode = parameterService.getParameterValue(GeneralLedgerInterfaceBatchProcessStep.class, EndowParameterKeyConstants.GLInterfaceBatchProcess.CASH_SALE_GAIN_LOSS_OBJECT_CODE);
669            if (transactionArchive.getObjectCode().equalsIgnoreCase(lossGainObjectCode)) {
670                totalAmount = transactionArchive.getShortTermGainLoss().add(transactionArchive.getLongTermGainLoss());
671                debitCreditCode = getTransactionDebitCreditCodeForOffSetEntry(totalAmount);           
672            }
673            else {
674                totalAmount = getTransactionAmount(transactionArchive);
675                debitCreditCode = getTransactionDebitCreditCode(transactionArchive.getTypeCode(), totalAmount, transactionArchive.getSubTypeCode());            
676            }
677            
678            if (debitCreditCode.equalsIgnoreCase(EndowConstants.KemToGLInterfaceBatchProcess.DEBIT_CODE)) {
679                chartObjectDebitAmountSubTotal = chartObjectDebitAmountSubTotal.add(totalAmount);
680            }
681            if (debitCreditCode.equalsIgnoreCase(EndowConstants.KemToGLInterfaceBatchProcess.CREDIT_CODE)) {
682                chartObjectCreditAmountSubTotal = chartObjectCreditAmountSubTotal.add(totalAmount);
683            }
684            chartObjectNumberOfRecordsSubTotal += 1;
685        }
686        
687        /**
688         * write TotalsProcessedDetailTotalsLine method to write details total line.
689         * @param previousDocumentTypeCode
690         * @param feeMethodCode
691         * @param totalLinesGenerated
692         */
693        protected void writeTotalsProcessedObjectDetailTotalsLine(String previousDocumentTypeCode, String previousChartCode, String previousObjectCode) {
694            //to suppress duplicate document type value on the report. 
695            if (!documentTypeWritten) {
696                gLInterfaceBatchTotalsProcessedTableRowValues.setDocumentType(previousDocumentTypeCode);
697                documentTypeWritten = true;            
698            }
699            else {
700                gLInterfaceBatchTotalsProcessedTableRowValues.setDocumentType(null);
701            }
702            
703            gLInterfaceBatchTotalsProcessedTableRowValues.setChartCode(previousChartCode);
704            gLInterfaceBatchTotalsProcessedTableRowValues.setObjectCode(previousObjectCode);
705            gLInterfaceBatchTotalsProcessedTableRowValues.setDebitAmount(new KualiDecimal(chartObjectDebitAmountSubTotal));
706            gLInterfaceBatchTotalsProcessedTableRowValues.setCreditAmount(new KualiDecimal(chartObjectCreditAmountSubTotal));
707            gLInterfaceBatchTotalsProcessedTableRowValues.setNumberOfEntries(chartObjectNumberOfRecordsSubTotal);
708            
709            gLInterfaceBatchTotalProcessedReportsWriterService.writeTableRow(gLInterfaceBatchTotalsProcessedTableRowValues);
710        }
711        
712        /**
713         * write chart TotalsProcessedDetailTotalsLine method to write details total line.
714         */
715        protected void writeTotalsProcessedChartDetailTotalsLine() {
716            //need to write the header line with "-"s.
717            gLInterfaceBatchTotalProcessedReportsWriterService.writeFormattedMessageLine(getSepartorLine());
718            
719            gLInterfaceBatchTotalsProcessedTableRowValues.setDocumentType(null);
720            gLInterfaceBatchTotalsProcessedTableRowValues.setChartCode("Subtotal by Chart");
721            gLInterfaceBatchTotalsProcessedTableRowValues.setObjectCode(null);
722            gLInterfaceBatchTotalsProcessedTableRowValues.setDebitAmount(new KualiDecimal(chartDebitAmountSubTotal));
723            gLInterfaceBatchTotalsProcessedTableRowValues.setCreditAmount(new KualiDecimal(chartCreditAmountSubTotal));
724            gLInterfaceBatchTotalsProcessedTableRowValues.setNumberOfEntries(chartNumberOfRecordsSubTotal);
725            
726            gLInterfaceBatchTotalProcessedReportsWriterService.writeTableRow(gLInterfaceBatchTotalsProcessedTableRowValues);
727            gLInterfaceBatchTotalProcessedReportsWriterService.writeNewLines(1);
728        }
729    
730        /**
731         * write document type TotalsProcessedDetailTotalsLine method to write details total line.
732         */
733        protected void writeTotalsProcessedDocumentTypeDetailTotalsLine() {
734            //need to write the header line with "-"s.
735            gLInterfaceBatchTotalProcessedReportsWriterService.writeFormattedMessageLine(getSepartorLine());
736            
737            gLInterfaceBatchTotalsProcessedTableRowValues.setDocumentType("Subtotal by Document Type");
738            gLInterfaceBatchTotalsProcessedTableRowValues.setChartCode(null);
739            gLInterfaceBatchTotalsProcessedTableRowValues.setObjectCode(null);
740            gLInterfaceBatchTotalsProcessedTableRowValues.setDebitAmount(new KualiDecimal(documentTypeDebitAmountSubTotal));
741            gLInterfaceBatchTotalsProcessedTableRowValues.setCreditAmount(new KualiDecimal(documentTypeCreditAmountSubTotal));
742            gLInterfaceBatchTotalsProcessedTableRowValues.setNumberOfEntries(documentTypeNumberOfRecordsSubTotal);
743            gLInterfaceBatchTotalProcessedReportsWriterService.writeTableRow(gLInterfaceBatchTotalsProcessedTableRowValues);
744            gLInterfaceBatchTotalProcessedReportsWriterService.writeNewLines(1);
745        }
746        
747        /**
748         * method to write document type totals whenever document type changes.
749         * First write out any pending details row and then write the pending chart details before writing
750         * the document type level totals.
751         */
752        protected void processDocumentTypeTotals() {
753            //add to the grand total and write the document sub-totals....
754            writeTotalsProcessedObjectDetailTotalsLine(previousDocumentTypeCode, previousChartCode, previousObjectCode);
755            addTotalsToChartTotals();
756            documentTypeWritten = false ;
757            
758            writeTotalsProcessedChartDetailTotalsLine(); 
759            addChartTotalsToDocumentTypeTotals();
760            writeTotalsProcessedDocumentTypeDetailTotalsLine();
761            addDocumentTypeTotalsToGrandTotals();
762            previousChartCode = null;
763            previousObjectCode = null;
764            previousDocumentTypeCode = null;
765        }
766        
767        /**
768         * write document TotalsProcessedDetailTotalsLine method to write details total line.
769         */
770        protected void writeTotalsProcessedGrandTotalsLine() {
771            //need to write the header line with "-"s.
772            gLInterfaceBatchTotalProcessedReportsWriterService.writeFormattedMessageLine(getSepartorLine());
773    
774            gLInterfaceBatchTotalsProcessedTableRowValues.setDocumentType("Grand Total");
775            gLInterfaceBatchTotalsProcessedTableRowValues.setChartCode(null);
776            gLInterfaceBatchTotalsProcessedTableRowValues.setObjectCode(null);
777            gLInterfaceBatchTotalsProcessedTableRowValues.setDebitAmount(new KualiDecimal(documentTypeDebitAmountGrandTotal));
778            gLInterfaceBatchTotalsProcessedTableRowValues.setCreditAmount(new KualiDecimal(documentTypeCreditAmountGrandTotal));
779            gLInterfaceBatchTotalsProcessedTableRowValues.setNumberOfEntries(documentTypeNumberOfRecordsGrandTotal);
780            gLInterfaceBatchTotalProcessedReportsWriterService.writeTableRow(gLInterfaceBatchTotalsProcessedTableRowValues);
781            gLInterfaceBatchTotalProcessedReportsWriterService.writeNewLines(1);
782        }
783        
784        /**
785         * add totals to grand totals and reset document level totals...
786         */
787        protected void addDocumentTypeTotalsToGrandTotals() {
788            //the properties to totals processed at Document Type level..sub totals.
789            documentTypeDebitAmountGrandTotal = documentTypeDebitAmountGrandTotal.add(documentTypeDebitAmountSubTotal);
790            documentTypeCreditAmountGrandTotal = documentTypeCreditAmountGrandTotal.add(documentTypeCreditAmountSubTotal);
791            documentTypeNumberOfRecordsGrandTotal += documentTypeNumberOfRecordsSubTotal;    
792    
793            documentTypeDebitAmountSubTotal = BigDecimal.ZERO;
794            documentTypeCreditAmountSubTotal = BigDecimal.ZERO;
795            documentTypeNumberOfRecordsSubTotal = 0;
796        }
797        
798        /**
799         * add chart level totals to document type totals and reset the chart/object level totals.
800         */
801        protected void addChartTotalsToDocumentTypeTotals() {
802            //add to the document level subtotals....
803            documentTypeDebitAmountSubTotal = documentTypeDebitAmountSubTotal.add(chartDebitAmountSubTotal);
804            documentTypeCreditAmountSubTotal = documentTypeCreditAmountSubTotal.add(chartCreditAmountSubTotal);
805            documentTypeNumberOfRecordsSubTotal += chartNumberOfRecordsSubTotal;
806            
807            //the properties to totals processed at chart level..sub totals.
808            chartDebitAmountSubTotal = BigDecimal.ZERO;
809            chartCreditAmountSubTotal = BigDecimal.ZERO;
810            chartNumberOfRecordsSubTotal = 0;
811            
812            //reset the object level totals...
813            initializeChartObjectTotals();
814        }
815        
816        protected void addTotalsToChartTotals() {
817            //the properties to totals processed at chart level..sub totals.
818            chartDebitAmountSubTotal = chartDebitAmountSubTotal.add(chartObjectDebitAmountSubTotal);
819            chartCreditAmountSubTotal = chartCreditAmountSubTotal.add(chartObjectCreditAmountSubTotal);
820            chartNumberOfRecordsSubTotal += chartObjectNumberOfRecordsSubTotal;
821    
822            //reset the object level totals...
823            initializeChartObjectTotals();
824        }
825        
826        /**
827         * method to initialize object level totals....
828         */
829        protected void initializeChartObjectTotals() {
830            chartObjectDebitAmountSubTotal = BigDecimal.ZERO;
831            chartObjectCreditAmountSubTotal = BigDecimal.ZERO;
832            chartObjectNumberOfRecordsSubTotal = 0;
833        }
834        
835        /**
836         * method to write the statistics report....
837         * @param statisticsReportRows Collection of statistics detail rows
838         */
839        protected void writeStatisticsReport(Collection<GLInterfaceBatchStatisticsReportDetailTableRow> statisticsReportRows) {
840            //now print the statistics report.....
841            long totalNumberOfGLEntries = 0;
842            long totalNumberOfExceptions = 0;
843            
844            for (GLInterfaceBatchStatisticsReportDetailTableRow statisticsReportRow: statisticsReportRows) {
845                if (!statisticsHeaderWritten) {
846                    //write the header line....
847                    gLInterfaceBatchStatisticsReportsWriterService.writeStatisticLine("Document Type\t\tNumber of Gl Entries\t\tNumber of Exceptions");
848                    gLInterfaceBatchStatisticsReportsWriterService.writeStatisticLine("-------------\t\t--------------------\t\t--------------------");
849                    statisticsHeaderWritten = true;                
850                }
851                
852                totalNumberOfGLEntries += statisticsReportRow.getGLEntriesGenerated();
853                totalNumberOfExceptions += statisticsReportRow.getNumberOfExceptions();
854                gLInterfaceBatchStatisticsReportsWriterService.writeStatisticLine("%s\t\t\t\t%9d\t\t\t\t%9d", statisticsReportRow.getDocumentType(), statisticsReportRow.getGLEntriesGenerated(), statisticsReportRow.getNumberOfExceptions());
855            }
856            //writes the total line of the report....
857            gLInterfaceBatchStatisticsReportsWriterService.writeStatisticLine("             \t\t--------------------\t\t--------------------");
858            gLInterfaceBatchStatisticsReportsWriterService.writeStatisticLine("%s\t\t\t\t%9d\t\t\t\t%9d", "Total", totalNumberOfGLEntries, totalNumberOfExceptions);
859        }
860        
861        /**
862         * get the separator line - to write a header line in statistics report
863         * @return the separator line
864         */
865        public String getSepartorLine() {
866            int attributeLength = 0;
867            StringBuffer separatorLine = new StringBuffer();
868            GLInterfaceBatchTotalsProcessedReportHeader reportHeader = new GLInterfaceBatchTotalsProcessedReportHeader();
869            
870            attributeLength += reportHeader.getColumn1MaxLength();
871            attributeLength += reportHeader.getColumn2MaxLength();
872            attributeLength += reportHeader.getColumn3MaxLength();
873            separatorLine = separatorLine.append(StringUtils.rightPad(StringUtils.EMPTY, attributeLength, " ")).append("   ");
874            attributeLength = reportHeader.getColumn4MaxLength();
875            separatorLine = separatorLine.append(StringUtils.rightPad(StringUtils.EMPTY, attributeLength, KFSConstants.DASH)).append(" ");        
876            attributeLength = reportHeader.getColumn5MaxLength();
877            separatorLine = separatorLine.append(StringUtils.rightPad(StringUtils.EMPTY, attributeLength, KFSConstants.DASH)).append(" ");        
878            attributeLength = reportHeader.getColumn6MaxLength();
879            separatorLine = separatorLine.append(StringUtils.rightPad(StringUtils.EMPTY, attributeLength, KFSConstants.DASH)).append(" ");        
880    
881            return separatorLine.toString();
882        }
883    
884        /**
885         * writes out the table row values then writes the reason row and inserts a blank line
886         * @param transactionArchive
887         * @param reasonMessage the reason message
888         */
889        protected void writeExceptionRecord(GlInterfaceBatchProcessKemLine transactionArchive, String reasonMessage) {
890            gLInterfaceBatchExceptionTableRowValues.setDocumentType(transactionArchive.getTypeCode());
891            gLInterfaceBatchExceptionTableRowValues.setEDocNumber(transactionArchive.getDocumentNumber());
892            gLInterfaceBatchExceptionTableRowValues.setKEMID(transactionArchive.getKemid());
893            gLInterfaceBatchExceptionTableRowValues.setIncomeAmount(transactionArchive.getTransactionArchiveIncomeAmount());
894            gLInterfaceBatchExceptionTableRowValues.setPrincipalAmountt(transactionArchive.getTransactionArchivePrincipalAmount());
895            gLInterfaceBatchExceptionTableRowValues.setSecurityCost(transactionArchive.getHoldingCost());
896            gLInterfaceBatchExceptionTableRowValues.setLongTermGainLoss(transactionArchive.getLongTermGainLoss());
897            gLInterfaceBatchExceptionTableRowValues.setShortTermGainLoss(transactionArchive.getShortTermGainLoss());
898            gLInterfaceBatchExceptionReportsWriterService.writeTableRow(gLInterfaceBatchExceptionTableRowValues);            
899    
900            // now write the error message line...
901            gLInterfaceBatchExceptionTableRowValues.setDocumentType("Reason: " + reasonMessage);
902            gLInterfaceBatchExceptionTableRowValues.setEDocNumber(null);
903            gLInterfaceBatchExceptionTableRowValues.setKEMID(null);
904            gLInterfaceBatchExceptionTableRowValues.setIncomeAmount(null);
905            gLInterfaceBatchExceptionTableRowValues.setPrincipalAmountt(null);
906            gLInterfaceBatchExceptionTableRowValues.setSecurityCost(null);
907            gLInterfaceBatchExceptionTableRowValues.setLongTermGainLoss(null);
908            gLInterfaceBatchExceptionTableRowValues.setShortTermGainLoss(null);
909            gLInterfaceBatchExceptionReportsWriterService.writeTableRow(gLInterfaceBatchExceptionTableRowValues);            
910            gLInterfaceBatchExceptionReportsWriterService.writeNewLines(1);
911        }
912        
913        /**
914         * Gets the gLInterfaceBatchExceptionReportsWriterService attribute. 
915         * @return Returns the gLInterfaceBatchExceptionReportsWriterService.
916         */
917        protected ReportWriterService getgLInterfaceBatchExceptionReportsWriterService() {
918            return gLInterfaceBatchExceptionReportsWriterService;
919        }
920        
921        /**
922         * Sets the gLInterfaceBatchExceptionReportsWriterService attribute value.
923         * @param gLInterfaceBatchExceptionReportsWriterService The gLInterfaceBatchExceptionReportsWriterService to set.
924         */
925        public void setgLInterfaceBatchExceptionReportsWriterService(ReportWriterService gLInterfaceBatchExceptionReportsWriterService) {
926            this.gLInterfaceBatchExceptionReportsWriterService = gLInterfaceBatchExceptionReportsWriterService;
927        }
928    
929        /**
930         * Gets the gLInterfaceBatchTotalProcessedReportsWriterService attribute. 
931         * @return Returns the gLInterfaceBatchTotalProcessedReportsWriterService.
932         */
933        public ReportWriterService getgLInterfaceBatchTotalProcessedReportsWriterService() {
934            return gLInterfaceBatchTotalProcessedReportsWriterService;
935        }
936    
937        /**
938         * Sets the gLInterfaceBatchTotalProcessedReportsWriterService attribute value.
939         * @param gLInterfaceBatchTotalProcessedReportsWriterService The gLInterfaceBatchTotalProcessedReportsWriterService to set.
940         */
941        public void setgLInterfaceBatchTotalProcessedReportsWriterService(ReportWriterService gLInterfaceBatchTotalProcessedReportsWriterService) {
942            this.gLInterfaceBatchTotalProcessedReportsWriterService = gLInterfaceBatchTotalProcessedReportsWriterService;
943        }
944        
945        /**
946         * Gets the gLInterfaceBatchStatisticsReportsWriterService attribute. 
947         * @return Returns the gLInterfaceBatchStatisticsReportsWriterService.
948         */
949        public ReportWriterService getgLInterfaceBatchStatisticsReportsWriterService() {
950            return gLInterfaceBatchStatisticsReportsWriterService;
951        }
952    
953        /**
954         * Sets the gLInterfaceBatchStatisticsReportsWriterService attribute value.
955         * @param gLInterfaceBatchStatisticsReportsWriterService The gLInterfaceBatchStatisticsReportsWriterService to set.
956         */
957        public void setgLInterfaceBatchStatisticsReportsWriterService(ReportWriterService gLInterfaceBatchStatisticsReportsWriterService) {
958            this.gLInterfaceBatchStatisticsReportsWriterService = gLInterfaceBatchStatisticsReportsWriterService;
959        }
960        
961        /**
962         * Gets the kemService.
963         * @return kemService
964         */
965        protected KEMService getKemService() {
966            return kemService;
967        }
968    
969        /**
970         * Sets the kemService.
971         * @param kemService
972         */
973        public void setKemService(KEMService kemService) {
974            this.kemService = kemService;
975        }
976    
977        /**
978         * Sets the gLInterfaceBatchExceptionReportHeader attribute value.
979         * @param processFeeTransactionsExceptionReportHeader The processFeeTransactionsExceptionReportHeader to set.
980         */
981        public void setGLInterfaceBatchExceptionReportHeader(GLInterfaceBatchExceptionReportHeader gLInterfaceBatchExceptionReportHeader) {
982            this.gLInterfaceBatchExceptionReportHeader = gLInterfaceBatchExceptionReportHeader;
983        }
984    
985        /**
986         * Gets the processFeeTransactionsTotalProcessedReportHeader attribute. 
987         * @return Returns the processFeeTransactionsTotalProcessedReportHeader.
988         */
989        protected GLInterfaceBatchExceptionReportHeader getGLInterfaceBatchExceptionReportHeader() {
990            return gLInterfaceBatchExceptionReportHeader;
991        }
992    
993        /**
994         * Gets the gLInterfaceBatchExceptionTableRowValues attribute. 
995         * @return Returns the gLInterfaceBatchExceptionTableRowValues.
996         */
997        protected GLInterfaceBatchExceptionTableRowValues getGLInterfaceBatchExceptionTableRowValues() {
998            return gLInterfaceBatchExceptionTableRowValues;
999        }
1000    
1001        /**
1002         * Sets the gLInterfaceBatchExceptionTableRowValues attribute value.
1003         * @param gLInterfaceBatchExceptionTableRowValues The gLInterfaceBatchExceptionTableRowValues to set.
1004         */
1005        public void setGLInterfaceBatchExceptionTableRowValues(GLInterfaceBatchExceptionTableRowValues gLInterfaceBatchExceptionTableRowValues) {
1006            this.gLInterfaceBatchExceptionTableRowValues = gLInterfaceBatchExceptionTableRowValues;
1007        }
1008    
1009        /**
1010         * Gets the gLInterfaceBatchExceptionRowReason attribute. 
1011         * @return Returns the gLInterfaceBatchExceptionRowReason.
1012         */
1013        protected GLInterfaceBatchExceptionTableRowValues getGLInterfaceBatchExceptionRowReason() {
1014            return gLInterfaceBatchExceptionRowReason;
1015        }
1016    
1017        /**
1018         * Sets the gLInterfaceBatchExceptionRowReason attribute value.
1019         * @param gLInterfaceBatchExceptionRowReason The gLInterfaceBatchExceptionRowReason to set.
1020         */
1021        public void setGLInterfaceBatchExceptionRowReason(GLInterfaceBatchExceptionTableRowValues gLInterfaceBatchExceptionRowReason) {
1022            this.gLInterfaceBatchExceptionRowReason = gLInterfaceBatchExceptionRowReason;
1023        }
1024        
1025        /**
1026         * Gets the gLInterfaceBatchTotalsProcessedTableRowValues attribute. 
1027         * @return Returns the gLInterfaceBatchTotalsProcessedTableRowValues.
1028         */
1029        protected GLInterfaceBatchTotalsProcessedTableRowValues getGLInterfaceBatchTotalsProcessedTableRowValues() {
1030            return gLInterfaceBatchTotalsProcessedTableRowValues;
1031        }
1032    
1033        /**
1034         * Sets the gLInterfaceBatchTotalsProcessedTableRowValues attribute value.
1035         * @param gLInterfaceBatchTotalsProcessedTableRowValues The gLInterfaceBatchTotalsProcessedTableRowValues to set.
1036         */
1037        public void setGLInterfaceBatchTotalsProcessedTableRowValues(GLInterfaceBatchTotalsProcessedTableRowValues gLInterfaceBatchTotalsProcessedTableRowValues) {
1038            this.gLInterfaceBatchTotalsProcessedTableRowValues = gLInterfaceBatchTotalsProcessedTableRowValues;
1039        }
1040        
1041        /**
1042         * Gets the gLInterfaceBatchStatisticsReportDetailTableRow attribute. 
1043         * @return Returns the gLInterfaceBatchStatisticsReportDetailTableRow.
1044         */
1045        protected GLInterfaceBatchStatisticsReportDetailTableRow getGLInterfaceBatchStatisticsReportDetailTableRow() {
1046            return gLInterfaceBatchStatisticsReportDetailTableRow;
1047        }
1048    
1049        /**
1050         * Sets the gLInterfaceBatchStatisticsReportDetailTableRow attribute value.
1051         * @param gLInterfaceBatchStatisticsReportDetailTableRow The gLInterfaceBatchStatisticsTableRowValues to set.
1052         */
1053        public void setGLInterfaceBatchStatisticsReportDetailTableRow(GLInterfaceBatchStatisticsReportDetailTableRow gLInterfaceBatchStatisticsReportDetailTableRow) {
1054            this.gLInterfaceBatchStatisticsReportDetailTableRow = gLInterfaceBatchStatisticsReportDetailTableRow;
1055        }
1056        
1057        /**
1058         * Gets the transactionArchiveDao attribute. 
1059         * @return Returns the transactionArchiveDao.
1060         */
1061        protected TransactionArchiveDao getTransactionArchiveDao() {
1062            return transactionArchiveDao;
1063        }
1064    
1065        /**
1066         * Sets the transactionArchiveDao attribute value.
1067         * @param transactionArchiveDao The transactionArchiveDao to set.
1068         */
1069        public void setTransactionArchiveDao(TransactionArchiveDao transactionArchiveDao) {
1070            this.transactionArchiveDao = transactionArchiveDao;
1071        }
1072        
1073        /**
1074         * This method sets the batchFileDirectoryName
1075         * @param batchFileDirectoryName
1076         */
1077        public void setBatchFileDirectoryName(String batchFileDirectoryName) {
1078            this.batchFileDirectoryName = batchFileDirectoryName;
1079        }
1080    
1081        /**
1082         * Gets the parameterService attribute.
1083         * 
1084         * @return Returns the parameterService.
1085         */    
1086        protected ParameterService getParameterService() {
1087            return parameterService;
1088        }
1089    
1090        /**
1091         * Sets the parameterService attribute value.
1092         * 
1093         * @param parameterService The parameterService to set.
1094         */    
1095        public void setParameterService(ParameterService parameterService) {
1096            this.parameterService = parameterService;
1097        }
1098        
1099        /**
1100         * Gets the endowmentAccountingLineBaseDao attribute. 
1101         * @return Returns the endowmentAccountingLineBaseDao.
1102         */
1103        protected EndowmentAccountingLineBaseDao getEndowmentAccountingLineBaseDao() {
1104            return endowmentAccountingLineBaseDao;
1105        }
1106    
1107        /**
1108         * Sets the endowmentAccountingLineBaseDao attribute value.
1109         * @param endowmentAccountingLineBaseDao The endowmentAccountingLineBaseDao to set.
1110         */
1111        public void setEndowmentAccountingLineBaseDao(EndowmentAccountingLineBaseDao endowmentAccountingLineBaseDao) {
1112            this.endowmentAccountingLineBaseDao = endowmentAccountingLineBaseDao;
1113        }
1114        
1115        /**
1116         * Gets the gLInterfaceBatchProcessDao attribute. 
1117         * @return Returns the gLInterfaceBatchProcessDao.
1118         */
1119        public GLInterfaceBatchProcessDao getgLInterfaceBatchProcessDao() {
1120            return gLInterfaceBatchProcessDao;
1121        }
1122    
1123        /**
1124         * Sets the gLInterfaceBatchProcessDao attribute value.
1125         * @param gLInterfaceBatchProcessDao The gLInterfaceBatchProcessDao to set.
1126         */
1127        public void setgLInterfaceBatchProcessDao(GLInterfaceBatchProcessDao gLInterfaceBatchProcessDao) {
1128            this.gLInterfaceBatchProcessDao = gLInterfaceBatchProcessDao;
1129        }
1130        
1131        /**
1132         * gets attribute gLLinkDao
1133         * @return gLLinkDao
1134         */
1135        protected GLLinkDao getgLLinkDao() {
1136            return gLLinkDao;
1137        }
1138        
1139        /**
1140         * sets attribute gLLinkDao
1141         */
1142        public void setgLLinkDao(GLLinkDao gLLinkDao) {
1143            this.gLLinkDao = gLLinkDao;
1144        }
1145    }
1146