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.File;
019    import java.io.FilenameFilter;
020    import java.math.BigDecimal;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.LinkedHashMap;
024    import java.util.List;
025    import java.util.Map;
026    
027    import org.apache.commons.lang.StringUtils;
028    import org.kuali.kfs.gl.GeneralLedgerConstants;
029    import org.kuali.kfs.gl.batch.PosterBalancingStep;
030    import org.kuali.kfs.gl.batch.service.BalancingService;
031    import org.kuali.kfs.gl.batch.service.PosterService;
032    import org.kuali.kfs.gl.businessobject.AccountBalance;
033    import org.kuali.kfs.gl.businessobject.AccountBalanceHistory;
034    import org.kuali.kfs.gl.businessobject.Balance;
035    import org.kuali.kfs.gl.businessobject.BalanceHistory;
036    import org.kuali.kfs.gl.businessobject.Encumbrance;
037    import org.kuali.kfs.gl.businessobject.EncumbranceHistory;
038    import org.kuali.kfs.gl.businessobject.Entry;
039    import org.kuali.kfs.gl.businessobject.EntryHistory;
040    import org.kuali.kfs.gl.businessobject.LedgerBalanceHistory;
041    import org.kuali.kfs.gl.businessobject.OriginEntryFull;
042    import org.kuali.kfs.gl.businessobject.OriginEntryInformation;
043    import org.kuali.kfs.gl.dataaccess.AccountBalanceDao;
044    import org.kuali.kfs.gl.dataaccess.BalancingDao;
045    import org.kuali.kfs.gl.dataaccess.EncumbranceDao;
046    import org.kuali.kfs.sys.FileUtil;
047    import org.kuali.kfs.sys.KFSConstants;
048    import org.kuali.kfs.sys.KFSKeyConstants;
049    import org.kuali.kfs.sys.KFSPropertyConstants;
050    import org.kuali.kfs.sys.Message;
051    import org.kuali.rice.kns.util.KualiDecimal;
052    import org.kuali.rice.kns.util.ObjectUtils;
053    import org.springframework.transaction.annotation.Transactional;
054    
055    /**
056     * Service implementation of BalancingService of GL balancing
057     */
058    @Transactional
059    public class BalancingServiceImpl extends BalancingServiceBaseImpl<EntryHistory, BalanceHistory> implements BalancingService {
060        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BalancingServiceImpl.class);
061        
062        protected BalancingDao balancingDao;
063        protected AccountBalanceDao accountBalanceDao;
064        protected EncumbranceDao encumbranceDao;
065        
066        protected File posterInputFile = null;
067        protected File posterErrorOutputFile = null;
068    
069        protected File reversalInputFile = null;
070        protected File reversalErrorOutputFile = null;
071    
072        protected File icrInputFile = null;
073        protected File icrErrorOutputFile = null;
074    
075        
076        @Override
077        public boolean runBalancing() {
078            // clear out the file cache, otherwise, it won't update the history tables with the latest poster files
079            // therefore, it will use the files that were first used when the balancing job was run when the JVM started, and that'll cause out of balance errors
080            clearPosterFileCache();
081            return super.runBalancing();
082        }
083    
084        /**
085         * @see org.kuali.kfs.gl.batch.service.BalancingService#getPosterInputFile()
086         */
087        public File getPosterInputFile() {
088            // avoid running scanning logic on file system
089            if (posterInputFile != null) {
090                return posterInputFile;
091            }
092            return posterInputFile = getFile(
093                    GeneralLedgerConstants.BatchFileSystem.POSTER_INPUT_FILE, 
094                    GeneralLedgerConstants.BatchFileSystem.EXTENSION);
095        }
096    
097        /**
098         * @see org.kuali.kfs.gl.batch.service.BalancingService#getPosterErrorOutputFile()
099         */
100        public File getPosterErrorOutputFile() {
101            // avoid running scanning logic on file system
102            if (posterErrorOutputFile != null) {
103                return posterErrorOutputFile;
104            }
105            return posterErrorOutputFile = getFile(
106                    GeneralLedgerConstants.BatchFileSystem.POSTER_ERROR_OUTPUT_FILE, 
107                    GeneralLedgerConstants.BatchFileSystem.EXTENSION);
108        }
109        
110        /**
111         * @see org.kuali.kfs.gl.batch.service.BalancingService#getReversalInputFile()
112         */
113        public File getReversalInputFile(){
114            if (reversalInputFile != null) {
115                return reversalInputFile;
116            }
117            return reversalInputFile = getFile(
118                    GeneralLedgerConstants.BatchFileSystem.REVERSAL_POSTER_VALID_OUTPUT_FILE, 
119                    GeneralLedgerConstants.BatchFileSystem.EXTENSION);
120        }
121    
122        /**
123         * @see org.kuali.kfs.gl.batch.service.BalancingService#getReversalErrorOutputFile()
124         */
125        public File getReversalErrorOutputFile(){
126            if (reversalErrorOutputFile != null) {
127                return reversalErrorOutputFile;
128            }
129            return reversalErrorOutputFile = getFile(
130                    GeneralLedgerConstants.BatchFileSystem.REVERSAL_POSTER_ERROR_OUTPUT_FILE, 
131                    GeneralLedgerConstants.BatchFileSystem.EXTENSION);
132        }
133    
134        /**
135         * @see org.kuali.kfs.gl.batch.service.BalancingService#getICRInputFile()
136         */
137        public File getICRInputFile(){
138            if (icrInputFile != null) {
139                return icrInputFile;
140            }
141            return icrInputFile = getFile(
142                    GeneralLedgerConstants.BatchFileSystem.ICR_POSTER_INPUT_FILE, 
143                    GeneralLedgerConstants.BatchFileSystem.EXTENSION);
144        }
145    
146        /**
147         * @see org.kuali.kfs.gl.batch.service.BalancingService#getICRErrorOutputFile()
148         */
149        public File getICRErrorOutputFile(){
150            if (icrErrorOutputFile != null) {
151                return icrErrorOutputFile;
152            }
153            return icrErrorOutputFile = getFile(
154                    GeneralLedgerConstants.BatchFileSystem.ICR_POSTER_ERROR_OUTPUT_FILE, 
155                    GeneralLedgerConstants.BatchFileSystem.EXTENSION);
156        }
157        
158        public File getFile(final String fileName, final String fileExtension){
159            FilenameFilter filenameFilter = new FilenameFilter() {
160                public boolean accept(File dir, String name) {
161                    return (name.startsWith(fileName) && name.endsWith(fileExtension));
162                }
163            };
164            return FileUtil.getNewestFile(new File(batchFileDirectoryName), filenameFilter);
165        }
166        
167        /**
168         * @see org.kuali.kfs.gl.batch.service.BalancingService#getPastFiscalYearsToConsider()
169         */
170        public int getPastFiscalYearsToConsider() {
171            return Integer.parseInt(parameterService.getParameterValue(PosterBalancingStep.class, GeneralLedgerConstants.Balancing.NUMBER_OF_PAST_FISCAL_YEARS_TO_INCLUDE));
172        }
173        
174        /**
175         * @see org.kuali.kfs.gl.batch.service.BalancingService#getComparisonFailuresToPrintPerReport()
176         */
177        public int getComparisonFailuresToPrintPerReport() {
178            return Integer.parseInt(parameterService.getParameterValue(PosterBalancingStep.class, GeneralLedgerConstants.Balancing.NUMBER_OF_COMPARISON_FAILURES_TO_PRINT_PER_REPORT));
179        }
180        
181        /**
182         * @see org.kuali.kfs.gl.batch.service.BalancingService#getShortTableLabel(java.lang.String)
183         */
184        public String getShortTableLabel(String businessObjectName) {
185            Map<String, String> names = new HashMap<String, String>();
186            names.put((Entry.class).getSimpleName(), kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ENTRY_LABEL));
187            names.put((EntryHistory.class).getSimpleName(), kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ENTRY_LABEL));
188            names.put((Balance.class).getSimpleName(), kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_BALANCE_LABEL));
189            names.put((BalanceHistory.class).getSimpleName(), kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_BALANCE_LABEL));
190            names.put((AccountBalance.class).getSimpleName(), kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ACCOUNT_BALANCE_LABEL));
191            names.put((AccountBalanceHistory.class).getSimpleName(), kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ACCOUNT_BALANCE_LABEL));
192            names.put((Encumbrance.class).getSimpleName(), kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ENCUMBRANCE_LABEL));
193            names.put((EncumbranceHistory.class).getSimpleName(), kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ENCUMBRANCE_LABEL));
194            
195            return names.get(businessObjectName) == null ? kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_UNKNOWN_LABEL) : names.get(businessObjectName);
196        }
197        
198        /**
199         * @see org.kuali.kfs.gl.batch.service.BalancingService#getOriginEntry(java.lang.String, int)
200         */
201        public OriginEntryInformation getOriginEntry(String inputLine, int lineNumber) {
202            // We need a OriginEntryFull because that's what updateBalanceHistory is looking for
203            OriginEntryFull originEntry = new OriginEntryFull();
204            originEntry.setFromTextFileForBatch(inputLine, lineNumber);
205            
206            return originEntry;
207        }
208        
209        /**
210         * @see org.kuali.kfs.gl.batch.service.BalancingService#updateEntryHistory(org.kuali.kfs.gl.businessobject.OriginEntryInformation)
211         * @see org.kuali.kfs.gl.batch.service.impl.PostEntry#post(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date)
212         */
213        public void updateEntryHistory(Integer postMode, OriginEntryInformation originEntry) {
214            // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end?
215            EntryHistory entryHistory = new EntryHistory(originEntry);
216    
217            EntryHistory retrievedEntryHistory = (EntryHistory) businessObjectService.retrieve(entryHistory);
218            if(ObjectUtils.isNotNull(retrievedEntryHistory)) {
219                entryHistory = retrievedEntryHistory;
220            }
221            
222            entryHistory.addAmount(originEntry.getTransactionLedgerEntryAmount());
223            
224            businessObjectService.save(entryHistory);
225        }
226        
227        /**
228         * @see org.kuali.kfs.gl.batch.service.BalancingService#updateBalanceHistory(org.kuali.kfs.gl.businessobject.OriginEntryInformation)
229         * @see org.kuali.kfs.gl.batch.service.impl.PostBalance#post(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date)
230         */
231        public void updateBalanceHistory(Integer postMode, OriginEntryInformation originEntry) {
232            // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end?
233            OriginEntryFull originEntryFull = (OriginEntryFull) originEntry;
234            BalanceHistory balanceHistory = new BalanceHistory(originEntryFull);
235            
236            BalanceHistory retrievedBalanceHistory = (BalanceHistory) businessObjectService.retrieve(balanceHistory);
237            if(ObjectUtils.isNotNull(retrievedBalanceHistory)) {
238                balanceHistory = retrievedBalanceHistory;
239            }
240            
241            KualiDecimal amount = originEntryFull.getTransactionLedgerEntryAmount();
242    
243            // Make sure the amount update properly recognized debit / credit logic. This is modeled after PostBalance#post
244            originEntryFull.refreshReferenceObject(KFSPropertyConstants.BALANCE_TYPE);
245            originEntryFull.refreshReferenceObject(KFSPropertyConstants.OBJECT_TYPE);
246            if (originEntryFull.getBalanceType().isFinancialOffsetGenerationIndicator()) {
247                if (!originEntryFull.getTransactionDebitCreditCode().equals(originEntryFull.getObjectType().getFinObjectTypeDebitcreditCd())) {
248                    amount = amount.negated();
249                }
250            }
251    
252            balanceHistory.addAmount(originEntryFull.getUniversityFiscalPeriodCode(), amount);
253            
254            businessObjectService.save(balanceHistory);
255        }
256        
257        /**
258         * @see org.kuali.kfs.gl.batch.service.BalancingService#getBalance(org.kuali.kfs.gl.businessobject.LedgerBalanceHistory)
259         */
260        public Balance getBalance(LedgerBalanceHistory ledgerBalanceHistory) {
261            Balance balance = new Balance((BalanceHistory) ledgerBalanceHistory);
262            return (Balance) businessObjectService.retrieve(balance);
263        }
264        
265        /**
266         * @see org.kuali.kfs.gl.batch.service.BalancingService#clearPosterFileCache()
267         */
268        public void clearPosterFileCache() {
269            this.posterInputFile = null;
270            this.posterErrorOutputFile = null;
271        }
272        
273        /**
274         * @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceBaseImpl#customPopulateHistoryTables(java.lang.Integer)
275         */
276        @Override
277        public void customPopulateHistoryTables(Integer fiscalYear) {
278            balancingDao.populateAccountBalancesHistory(fiscalYear);
279            balancingDao.populateEncumbranceHistory(fiscalYear);
280        }
281        
282        /**
283         * @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceBaseImpl#doesCustomHistoryExist(java.lang.Integer)
284         */
285        @Override
286        protected boolean doesCustomHistoryExist(Integer fiscalYear) {
287            return (this.getHistoryCount(fiscalYear, AccountBalanceHistory.class) > 0 &&
288                    this.getHistoryCount(fiscalYear, EncumbranceHistory.class) > 0);
289        }
290        
291        /**
292         * @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceBaseImpl#deleteCustomHistory(java.lang.Integer)
293         */
294        @Override
295        protected void deleteCustomHistory(Integer fiscalYear) {
296            deleteHistory(fiscalYear, AccountBalanceHistory.class);
297            deleteHistory(fiscalYear, EncumbranceHistory.class);
298            
299            reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_OBSOLETE_FISCAL_YEAR_DATA_DELETED), (AccountBalanceHistory.class).getSimpleName(), (EncumbranceHistory.class).getSimpleName(), fiscalYear);
300            reportWriterService.writeNewLines(1);
301        }
302        
303        /**
304         * @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceBaseImpl#updateCustomHistory(org.kuali.kfs.gl.businessobject.OriginEntryInformation)
305         */
306        @Override
307        protected void updateCustomHistory(Integer postMode, OriginEntryInformation originEntry) {
308            this.updateAccountBalanceHistory(originEntry);
309            this.updateEncumbranceHistory(originEntry);
310        }
311        
312        
313        /**
314         * Update the account balance history table
315         * @param originEntry representing the update details
316         * @see org.kuali.kfs.gl.batch.service.impl.PostAccountBalance#post(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date)
317         */
318        protected void updateAccountBalanceHistory(OriginEntryInformation originEntry) {
319            OriginEntryFull originEntryFull = (OriginEntryFull) originEntry;
320            
321            // As taken from PostAccountBalance#post: only post transactions where: balance type code is AC or CB or where object type isn't FB and
322            // balance type code is EX, IE, PE and CE
323            originEntryFull.refreshReferenceObject(KFSPropertyConstants.OPTION);
324            if ((originEntryFull.getFinancialBalanceTypeCode().equals(originEntryFull.getOption().getActualFinancialBalanceTypeCd()) || originEntryFull.getFinancialBalanceTypeCode().equals(originEntryFull.getOption().getBudgetCheckingBalanceTypeCd())) || (originEntryFull.getFinancialBalanceTypeCode().equals(originEntryFull.getOption().getExtrnlEncumFinBalanceTypCd()) || originEntryFull.getFinancialBalanceTypeCode().equals(originEntryFull.getOption().getIntrnlEncumFinBalanceTypCd()) || originEntryFull.getFinancialBalanceTypeCode().equals(originEntryFull.getOption().getPreencumbranceFinBalTypeCd()) || originEntryFull.getFinancialBalanceTypeCode().equals(originEntryFull.getOption().getCostShareEncumbranceBalanceTypeCd())) && (!originEntryFull.getFinancialObjectTypeCode().equals(originEntryFull.getOption().getFinObjectTypeFundBalanceCd()))) {
325                // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end?
326                AccountBalanceHistory accountBalanceHistory = new AccountBalanceHistory(originEntry);
327        
328                AccountBalanceHistory retrievedAccountBalanceHistory = (AccountBalanceHistory) businessObjectService.retrieve(accountBalanceHistory);
329                if(ObjectUtils.isNotNull(retrievedAccountBalanceHistory)) {
330                    accountBalanceHistory = retrievedAccountBalanceHistory;
331                }
332                
333                // Following is a copy of PostAccountBalance.updateAccountBalanceReturn since the blancing process is to do this independently
334                if (accountBalanceHistory.addAmount(originEntryFull)) {
335                    businessObjectService.save(accountBalanceHistory);
336                }
337            }
338        }
339        
340        /**
341         * 
342         * @see org.kuali.kfs.gl.batch.service.BalancingService#clearBalanceHistory()
343         */
344       
345        public void clearHistories() {
346            Map<String, Object> fieldValues = new HashMap<String, Object>();
347            businessObjectService.deleteMatching(EntryHistory.class, fieldValues);
348            businessObjectService.deleteMatching(BalanceHistory.class, fieldValues);
349            businessObjectService.deleteMatching(EncumbranceHistory.class, fieldValues);
350            businessObjectService.deleteMatching(AccountBalanceHistory.class, fieldValues);
351            
352            reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_HISTORY_PURGED));
353    
354            
355        }
356        
357        /**
358         * Compares entries in the Balance and BalanceHistory tables to ensure the amounts match.
359         * @return count is compare failures
360         */
361        protected Integer compareBalanceHistory() {
362            Integer countComparisionFailures = 0;
363            
364            List data = ledgerEntryBalanceCachingDao.compareBalanceHistory(Balance.class, balanceHistoryPersistentClass, getPastFiscalYearsToConsider());
365    
366            if (!data.isEmpty()) {
367                for (Iterator itr = data.iterator(); itr.hasNext();) {
368                    BalanceHistory balance = createBalanceFromMap((Map)itr.next());
369                    countComparisionFailures++;
370                    if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) {
371                        reportWriterService.writeError(balance, new Message(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, balance.getClass().getSimpleName()));
372                    }
373                }
374            }
375    
376            return countComparisionFailures;
377        }
378        
379        /**
380         * Compares entries in the Entry and EntryHistory tables to ensure the amounts match.
381         * @return count is compare failures
382         */
383        protected Integer compareEntryHistory() {
384            Integer countComparisionFailures = 0;
385            
386            List data = ledgerEntryBalanceCachingDao.compareEntryHistory(Entry.class, entryHistoryPersistentClass, getPastFiscalYearsToConsider());
387            
388            if (!data.isEmpty()) {
389                for (Iterator itr = data.iterator(); itr.hasNext();) {
390                    EntryHistory entry = createEntryHistoryFromMap((Map)itr.next());
391                    countComparisionFailures++;
392                    if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) {
393                      reportWriterService.writeError(entry, new Message(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, entry.getClass().getSimpleName()));
394                    }
395                    
396                }
397            }
398            
399            return countComparisionFailures;
400        }
401        
402        /**
403         * Update the encumbrance history table
404         * @param originEntry representing the update details
405         * @see org.kuali.kfs.gl.batch.service.impl.PostEncumbrance#post(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date)
406         */
407        protected void updateEncumbranceHistory(OriginEntryInformation originEntry) {
408            OriginEntryFull originEntryFull = (OriginEntryFull) originEntry;
409            
410            // PostEncumbrance.verifyTransaction is not run because entries that fail that verification will be in the error poster file which entries
411            // are already ignored before being passed to this method.
412            
413            // As taken from PostEncumbrance#post: If the encumbrance update code is space or N, or the object type code is FB we don't need to post an encumbrance
414            originEntryFull.refreshReferenceObject(KFSPropertyConstants.OPTION);
415            if ((StringUtils.isBlank(originEntryFull.getTransactionEncumbranceUpdateCode())) || " ".equals(originEntryFull.getTransactionEncumbranceUpdateCode()) || KFSConstants.ENCUMB_UPDT_NO_ENCUMBRANCE_CD.equals(originEntryFull.getTransactionEncumbranceUpdateCode()) || originEntryFull.getOption().getFinObjectTypeFundBalanceCd().equals(originEntryFull.getFinancialObjectTypeCode())) {
416                return;
417            }
418            
419            EncumbranceHistory encumbranceHistory = new EncumbranceHistory(originEntryFull);
420            if (KFSConstants.ENCUMB_UPDT_REFERENCE_DOCUMENT_CD.equals(originEntryFull.getTransactionEncumbranceUpdateCode())) {
421                encumbranceHistory.setDocumentNumber(originEntryFull.getReferenceFinancialDocumentNumber());
422                encumbranceHistory.setOriginCode(originEntryFull.getReferenceFinancialSystemOriginationCode());
423                encumbranceHistory.setDocumentTypeCode(originEntryFull.getReferenceFinancialDocumentTypeCode());
424            }
425            // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end?
426            EncumbranceHistory retrievedEncumbranceHistory = (EncumbranceHistory) businessObjectService.retrieve(encumbranceHistory);
427            
428            if(ObjectUtils.isNotNull(retrievedEncumbranceHistory)) {
429                encumbranceHistory = retrievedEncumbranceHistory;
430            }
431            
432            // Following is a copy & paste of PostEncumbrance.updateEncumbrance since the balancing process is to do this independently
433            encumbranceHistory.addAmount(originEntryFull);
434            
435            businessObjectService.save(encumbranceHistory);
436        }
437        
438        
439        
440        /**
441         * @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceBaseImpl#customCompareHistory()
442         */
443        @Override
444        protected Map<String, Integer> customCompareHistory() {
445            Integer countAccountBalanceComparisionFailure = this.accountBalanceCompareHistory();
446            Integer countEncumbranceComparisionFailure = this.encumbranceCompareHistory();
447            
448            // Using LinkedHashMap because we want it ordered
449            Map<String, Integer> countMap = new LinkedHashMap<String, Integer>();
450            countMap.put((AccountBalanceHistory.class).getSimpleName(), countAccountBalanceComparisionFailure);
451            countMap.put((EncumbranceHistory.class).getSimpleName(), countEncumbranceComparisionFailure);
452            
453            return countMap;
454        }
455        
456        /**
457         * Does comparision, error printing and returns failure count for account balances
458         * @return failure count
459         */
460        protected Integer accountBalanceCompareHistory() {
461            Integer countComparisionFailures = 0;
462            
463            List data = ledgerEntryBalanceCachingDao.accountBalanceCompareHistory(AccountBalance.class, AccountBalanceHistory.class, getPastFiscalYearsToConsider());
464    
465            if (!data.isEmpty()) {
466                for (Iterator itr = data.iterator(); itr.hasNext();) {
467                    AccountBalanceHistory accountBalanceHistory = createAccountBalanceHistoryFromMap((Map)itr.next());
468                    countComparisionFailures++;
469                    if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) {
470                        reportWriterService.writeError(accountBalanceHistory, new Message(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, accountBalanceHistory.getClass().getSimpleName()));
471                    }
472                }
473                
474            } else {
475                reportWriterService.writeNewLines(1);
476                reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_FAILURE_COUNT), (AccountBalanceHistory.class).getSimpleName(), countComparisionFailures, this.getComparisonFailuresToPrintPerReport());
477            }
478            return countComparisionFailures;
479        }
480        
481        /**
482         * Does comparision, error printing and returns failure count for encumbrances
483         * @return failure count
484         */
485        protected Integer encumbranceCompareHistory() {
486            Integer countComparisionFailures = 0;
487            
488            List data = ledgerEntryBalanceCachingDao.encumbranceCompareHistory(Encumbrance.class, EncumbranceHistory.class, getPastFiscalYearsToConsider());
489            
490            if (!data.isEmpty()) {
491                for (Iterator itr = data.iterator(); itr.hasNext();) {
492                    EncumbranceHistory encumbranceHistory = createEncumbranceHistoryFromMap((Map)itr.next());
493                    countComparisionFailures++;
494                    if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) {
495                        reportWriterService.writeError(encumbranceHistory, new Message(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, encumbranceHistory.getClass().getSimpleName()));
496                    }
497                }
498                
499            } else {
500                reportWriterService.writeNewLines(1);
501                reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_FAILURE_COUNT), (EncumbranceHistory.class).getSimpleName(), countComparisionFailures, this.getComparisonFailuresToPrintPerReport());
502            }
503            
504            
505            countComparisionFailures = data.size();
506    
507            return countComparisionFailures;
508        }
509        
510        /**
511         * @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceBaseImpl#customPrintRowCountHistory()
512         */
513        @Override
514        protected void customPrintRowCountHistory(Integer fiscalYear){
515            // Note that fiscal year is passed as null for the History tables because for those we shouldn't have data prior to the fiscal year anyway (and
516            // if we do it's a bug that should be discovered)
517            reportWriterService.writeStatisticLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ACCOUNT_BALANCE_ROW_COUNT_HISTORY), this.getShortTableLabel((AccountBalanceHistory.class).getSimpleName()), "(" + (AccountBalanceHistory.class).getSimpleName() + ")", this.getHistoryCount(null, AccountBalanceHistory.class));
518            reportWriterService.writeStatisticLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ACCOUNT_BALANCE_ROW_COUNT_PRODUCTION), this.getShortTableLabel((AccountBalance.class).getSimpleName()), accountBalanceDao.findCountGreaterOrEqualThan(fiscalYear));
519            reportWriterService.writeStatisticLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ENCUMBRANCE_ROW_COUNT_HISTORY), this.getShortTableLabel((EncumbranceHistory.class).getSimpleName()), "(" + (EncumbranceHistory.class).getSimpleName() + ")", this.getHistoryCount(null, EncumbranceHistory.class));
520            reportWriterService.writeStatisticLine(kualiConfigurationService.getPropertyString(KFSKeyConstants.Balancing.REPORT_ENCUMBRANCE_ROW_COUNT_PRODUCTION), this.getShortTableLabel((Encumbrance.class).getSimpleName()), encumbranceDao.findCountGreaterOrEqualThan(fiscalYear));
521        }
522        
523        /**
524         * Sets the BalancingDao
525         * 
526         * @param balancingDao The BalancingDao to set.
527         */
528        public void setBalancingDao(BalancingDao balancingDao) {
529            this.balancingDao = balancingDao;
530        }
531        
532        /**
533         * Sets the AccountBalanceDao
534         * 
535         * @param accountBalanceDao The AccountBalanceDao to set.
536         */
537        public void setAccountBalanceDao(AccountBalanceDao accountBalanceDao) {
538            this.accountBalanceDao = accountBalanceDao;
539        }
540        
541        /**
542         * Sets the EncumbranceDao
543         * 
544         * @param encumbranceDao The EncumbranceDao to set.
545         */
546        public void setEncumbranceDao(EncumbranceDao encumbranceDao) {
547            this.encumbranceDao = encumbranceDao;
548        }
549        
550        protected BalanceHistory createBalanceFromMap(Map<String, Object> map) {
551            BalanceHistory balance = new BalanceHistory();
552            balance.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue());
553            balance.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE));
554            balance.setAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_NUMBER));
555            balance.setSubAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_ACCOUNT_NUMBER));
556            balance.setObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE));
557            balance.setSubObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_OBJECT_CODE));
558            balance.setBalanceTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE));
559            balance.setObjectTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_TYPE_CODE));
560            
561            balance.setAccountLineAnnualBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNTING_LINE_ACTUALS_BALANCE_AMOUNT)));
562            balance.setContractsGrantsBeginningBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.CONTRACT_AND_GRANTS_BEGINNING_BALANCE)));
563            balance.setBeginningBalanceLineAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.BEGINNING_BALANCE)));
564            balance.setMonth1Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_1_ACCT_AMT)));
565            balance.setMonth2Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_2_ACCT_AMT)));
566            balance.setMonth3Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_3_ACCT_AMT)));
567            balance.setMonth4Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_4_ACCT_AMT)));
568            balance.setMonth5Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_5_ACCT_AMT)));
569            balance.setMonth6Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_6_ACCT_AMT)));
570            balance.setMonth7Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_7_ACCT_AMT)));
571            balance.setMonth8Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_8_ACCT_AMT)));
572            balance.setMonth9Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_9_ACCT_AMT)));
573            balance.setMonth10Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_10_ACCT_AMT)));
574            balance.setMonth11Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_11_ACCT_AMT)));
575            balance.setMonth12Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_12_ACCT_AMT)));
576            balance.setMonth13Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_13_ACCT_AMT)));
577            
578            return balance;
579            
580        }
581        
582        protected EntryHistory createEntryHistoryFromMap(Map<String, Object> map) {
583            EntryHistory entry = new EntryHistory();
584            entry.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue());
585            entry.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE));
586            entry.setFinancialObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE));
587            entry.setFinancialBalanceTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE));
588            entry.setUniversityFiscalPeriodCode((String)map.get(GeneralLedgerConstants.ColumnNames.FISCAL_PERIOD_CODE));
589           // entry.setFinancialObjectTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_TYPE_CODE));
590            entry.setTransactionDebitCreditCode((String)map.get(GeneralLedgerConstants.ColumnNames.TRANSACTION_DEBIT_CREDIT_CD));
591            entry.setTransactionLedgerEntryAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.TRANSACTION_LEDGER_ENTRY_AMOUNT)));
592            
593            return entry;
594            
595        }
596        
597        protected AccountBalanceHistory createAccountBalanceHistoryFromMap(Map<String, Object> map) {
598            //UNIV_FISCAL_YR, FIN_COA_CD, ACCOUNT_NBR, SUB_ACCT_NBR, FIN_OBJECT_CD, FIN_SUB_OBJ_CD, CURR_BDLN_BAL_AMT, ACLN_ACTLS_BAL_AMT, ACLN_ENCUM_BAL_AMT 
599            AccountBalanceHistory accountBalanceHistory = new AccountBalanceHistory();
600            accountBalanceHistory.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue());
601            accountBalanceHistory.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE));
602            accountBalanceHistory.setAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_NUMBER));
603            accountBalanceHistory.setSubAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_ACCOUNT_NUMBER));
604            accountBalanceHistory.setObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE));
605            accountBalanceHistory.setSubObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_OBJECT_CODE));
606            accountBalanceHistory.setCurrentBudgetLineBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.CURRENT_BUDGET_LINE_BALANCE_AMOUNT)));
607            accountBalanceHistory.setAccountLineActualsBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_LINE_ACTUALS_BALANCE_AMOUNT)));
608            accountBalanceHistory.setAccountLineEncumbranceBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_LINE_ENCUMBRANCE_BALANCE_AMOUNT)));
609    
610            
611            return accountBalanceHistory;
612        }
613        
614        protected EncumbranceHistory createEncumbranceHistoryFromMap(Map<String, Object> map) {
615            EncumbranceHistory encumbranceHistory = new EncumbranceHistory();
616            encumbranceHistory.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue());
617            encumbranceHistory.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE));
618            encumbranceHistory.setAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_NUMBER));
619            encumbranceHistory.setSubAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_ACCOUNT_NUMBER));
620            encumbranceHistory.setObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE));
621            encumbranceHistory.setSubObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_OBJECT_CODE));
622            encumbranceHistory.setBalanceTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE));
623            encumbranceHistory.setDocumentTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.FINANCIAL_DOCUMENT_TYPE_CODE));
624            encumbranceHistory.setOriginCode((String)map.get(GeneralLedgerConstants.ColumnNames.ORIGINATION_CODE));
625            encumbranceHistory.setDocumentNumber((String)map.get(GeneralLedgerConstants.ColumnNames.DOCUMENT_NUMBER));
626            encumbranceHistory.setAccountLineEncumbranceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_LINE_ENCUMBRANCE_AMOUNT)));
627            encumbranceHistory.setAccountLineEncumbranceClosedAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_LINE_ENCUMBRANCE_CLOSED_AMOUNT)));
628    
629            
630            return encumbranceHistory;
631        }
632        
633        protected KualiDecimal convertBigDecimalToKualiDecimal(BigDecimal biggy) {
634            if (ObjectUtils.isNull(biggy))
635                return new KualiDecimal(0);   
636            else 
637                return new KualiDecimal(biggy);
638        
639        }
640        
641    }