View Javadoc
1   /*
2    * Copyright 2007-2009 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.gl.batch.service.impl;
17  
18  import java.io.File;
19  import java.io.FilenameFilter;
20  import java.math.BigDecimal;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.kuali.ole.gl.GeneralLedgerConstants;
29  import org.kuali.ole.gl.batch.PosterBalancingStep;
30  import org.kuali.ole.gl.batch.service.BalancingService;
31  import org.kuali.ole.gl.businessobject.AccountBalance;
32  import org.kuali.ole.gl.businessobject.AccountBalanceHistory;
33  import org.kuali.ole.gl.businessobject.Balance;
34  import org.kuali.ole.gl.businessobject.BalanceHistory;
35  import org.kuali.ole.gl.businessobject.Encumbrance;
36  import org.kuali.ole.gl.businessobject.EncumbranceHistory;
37  import org.kuali.ole.gl.businessobject.Entry;
38  import org.kuali.ole.gl.businessobject.EntryHistory;
39  import org.kuali.ole.gl.businessobject.LedgerBalanceHistory;
40  import org.kuali.ole.gl.businessobject.OriginEntryFull;
41  import org.kuali.ole.gl.businessobject.OriginEntryInformation;
42  import org.kuali.ole.gl.dataaccess.AccountBalanceDao;
43  import org.kuali.ole.gl.dataaccess.BalancingDao;
44  import org.kuali.ole.gl.dataaccess.EncumbranceDao;
45  import org.kuali.ole.sys.FileUtil;
46  import org.kuali.ole.sys.OLEConstants;
47  import org.kuali.ole.sys.OLEKeyConstants;
48  import org.kuali.ole.sys.OLEPropertyConstants;
49  import org.kuali.ole.sys.Message;
50  import org.kuali.rice.core.api.util.type.KualiDecimal;
51  import org.kuali.rice.krad.util.ObjectUtils;
52  import org.springframework.transaction.annotation.Transactional;
53  
54  /**
55   * Service implementation of BalancingService of GL balancing
56   */
57  @Transactional
58  public class BalancingServiceImpl extends BalancingServiceBaseImpl<EntryHistory, BalanceHistory> implements BalancingService {
59      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BalancingServiceImpl.class);
60  
61      protected BalancingDao balancingDao;
62      protected AccountBalanceDao accountBalanceDao;
63      protected EncumbranceDao encumbranceDao;
64  
65      protected File posterInputFile = null;
66      protected File posterErrorOutputFile = null;
67  
68      protected File reversalInputFile = null;
69      protected File reversalErrorOutputFile = null;
70  
71      protected File icrInputFile = null;
72      protected File icrErrorOutputFile = null;
73  
74  
75      @Override
76      public boolean runBalancing() {
77          // clear out the file cache, otherwise, it won't update the history tables with the latest poster files
78          // therefore, it will use the files that were first used when the balancing job was run when the JVM started, and that'll
79          // cause out of balance errors
80          clearPosterFileCache();
81          return super.runBalancing();
82      }
83  
84      /**
85       * @see org.kuali.ole.gl.batch.service.BalancingService#getPosterInputFile()
86       */
87      @Override
88      public File getPosterInputFile() {
89          // avoid running scanning logic on file system
90          if (posterInputFile != null) {
91              return posterInputFile;
92          }
93          return posterInputFile = getFile(
94                  GeneralLedgerConstants.BatchFileSystem.POSTER_INPUT_FILE,
95                  GeneralLedgerConstants.BatchFileSystem.EXTENSION);
96      }
97  
98      /**
99       * @see org.kuali.ole.gl.batch.service.BalancingService#getPosterErrorOutputFile()
100      */
101     @Override
102     public File getPosterErrorOutputFile() {
103         // avoid running scanning logic on file system
104         if (posterErrorOutputFile != null) {
105             return posterErrorOutputFile;
106         }
107         return posterErrorOutputFile = getFile(
108                 GeneralLedgerConstants.BatchFileSystem.POSTER_ERROR_OUTPUT_FILE,
109                 GeneralLedgerConstants.BatchFileSystem.EXTENSION);
110     }
111 
112     /**
113      * @see org.kuali.ole.gl.batch.service.BalancingService#getReversalInputFile()
114      */
115     @Override
116     public File getReversalInputFile(){
117         if (reversalInputFile != null) {
118             return reversalInputFile;
119         }
120         return reversalInputFile = getFile(
121                 GeneralLedgerConstants.BatchFileSystem.REVERSAL_POSTER_VALID_OUTPUT_FILE,
122                 GeneralLedgerConstants.BatchFileSystem.EXTENSION);
123     }
124 
125     /**
126      * @see org.kuali.ole.gl.batch.service.BalancingService#getReversalErrorOutputFile()
127      */
128     @Override
129     public File getReversalErrorOutputFile(){
130         if (reversalErrorOutputFile != null) {
131             return reversalErrorOutputFile;
132         }
133         return reversalErrorOutputFile = getFile(
134                 GeneralLedgerConstants.BatchFileSystem.REVERSAL_POSTER_ERROR_OUTPUT_FILE,
135                 GeneralLedgerConstants.BatchFileSystem.EXTENSION);
136     }
137 
138     /**
139      * @see org.kuali.ole.gl.batch.service.BalancingService#getICRInputFile()
140      */
141     @Override
142     public File getICRInputFile(){
143         if (icrInputFile != null) {
144             return icrInputFile;
145         }
146         return icrInputFile = getFile(
147                 GeneralLedgerConstants.BatchFileSystem.ICR_POSTER_INPUT_FILE,
148                 GeneralLedgerConstants.BatchFileSystem.EXTENSION);
149     }
150 
151     /**
152      * @see org.kuali.ole.gl.batch.service.BalancingService#getICRErrorOutputFile()
153      */
154     @Override
155     public File getICRErrorOutputFile(){
156         if (icrErrorOutputFile != null) {
157             return icrErrorOutputFile;
158         }
159         return icrErrorOutputFile = getFile(
160                 GeneralLedgerConstants.BatchFileSystem.ICR_POSTER_ERROR_OUTPUT_FILE,
161                 GeneralLedgerConstants.BatchFileSystem.EXTENSION);
162     }
163 
164     public File getFile(final String fileName, final String fileExtension){
165         FilenameFilter filenameFilter = new FilenameFilter() {
166             @Override
167             public boolean accept(File dir, String name) {
168                 return (name.startsWith(fileName) && name.endsWith(fileExtension));
169             }
170         };
171         return FileUtil.getNewestFile(new File(batchFileDirectoryName), filenameFilter);
172     }
173 
174     /**
175      * @see org.kuali.ole.gl.batch.service.BalancingService#getPastFiscalYearsToConsider()
176      */
177     @Override
178     public int getPastFiscalYearsToConsider() {
179         return Integer.parseInt(parameterService.getParameterValueAsString(PosterBalancingStep.class, GeneralLedgerConstants.Balancing.NUMBER_OF_PAST_FISCAL_YEARS_TO_INCLUDE));
180     }
181 
182     /**
183      * @see org.kuali.ole.gl.batch.service.BalancingService#getComparisonFailuresToPrintPerReport()
184      */
185     @Override
186     public int getComparisonFailuresToPrintPerReport() {
187         return Integer.parseInt(parameterService.getParameterValueAsString(PosterBalancingStep.class, GeneralLedgerConstants.Balancing.NUMBER_OF_COMPARISON_FAILURES_TO_PRINT_PER_REPORT));
188     }
189 
190     /**
191      * @see org.kuali.ole.gl.batch.service.BalancingService#getShortTableLabel(java.lang.String)
192      */
193     @Override
194     public String getShortTableLabel(String businessObjectName) {
195         Map<String, String> names = new HashMap<String, String>();
196         names.put((Entry.class).getSimpleName(), kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ENTRY_LABEL));
197         names.put((EntryHistory.class).getSimpleName(), kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ENTRY_LABEL));
198         names.put((Balance.class).getSimpleName(), kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_BALANCE_LABEL));
199         names.put((BalanceHistory.class).getSimpleName(), kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_BALANCE_LABEL));
200         names.put((AccountBalance.class).getSimpleName(), kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ACCOUNT_BALANCE_LABEL));
201         names.put((AccountBalanceHistory.class).getSimpleName(), kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ACCOUNT_BALANCE_LABEL));
202         names.put((Encumbrance.class).getSimpleName(), kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ENCUMBRANCE_LABEL));
203         names.put((EncumbranceHistory.class).getSimpleName(), kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ENCUMBRANCE_LABEL));
204 
205         return names.get(businessObjectName) == null ? kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_UNKNOWN_LABEL) : names.get(businessObjectName);
206     }
207 
208     /**
209      * @see org.kuali.ole.gl.batch.service.BalancingService#getOriginEntry(java.lang.String, int)
210      */
211     @Override
212     public OriginEntryInformation getOriginEntry(String inputLine, int lineNumber) {
213         // We need a OriginEntryFull because that's what updateBalanceHistory is looking for
214         OriginEntryFull originEntry = new OriginEntryFull();
215         originEntry.setFromTextFileForBatch(inputLine, lineNumber);
216 
217         return originEntry;
218     }
219 
220     /**
221      * @see org.kuali.ole.gl.batch.service.BalancingService#updateEntryHistory(org.kuali.ole.gl.businessobject.OriginEntryInformation)
222      * @see org.kuali.ole.gl.batch.service.impl.PostEntry#post(org.kuali.ole.gl.businessobject.Transaction, int, java.util.Date)
223      */
224     @Override
225     public void updateEntryHistory(Integer postMode, OriginEntryInformation originEntry) {
226         // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end?
227         EntryHistory entryHistory = new EntryHistory(originEntry);
228 
229         EntryHistory retrievedEntryHistory = (EntryHistory) businessObjectService.retrieve(entryHistory);
230         if(ObjectUtils.isNotNull(retrievedEntryHistory)) {
231             entryHistory = retrievedEntryHistory;
232         }
233 
234         entryHistory.addAmount(originEntry.getTransactionLedgerEntryAmount());
235 
236         businessObjectService.save(entryHistory);
237     }
238 
239     /**
240      * @see org.kuali.ole.gl.batch.service.BalancingService#updateBalanceHistory(org.kuali.ole.gl.businessobject.OriginEntryInformation)
241      * @see org.kuali.ole.gl.batch.service.impl.PostBalance#post(org.kuali.ole.gl.businessobject.Transaction, int, java.util.Date)
242      */
243     @Override
244     public void updateBalanceHistory(Integer postMode, OriginEntryInformation originEntry) {
245         // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end?
246         OriginEntryFull originEntryFull = (OriginEntryFull) originEntry;
247         BalanceHistory balanceHistory = new BalanceHistory(originEntryFull);
248 
249         BalanceHistory retrievedBalanceHistory = (BalanceHistory) businessObjectService.retrieve(balanceHistory);
250         if(ObjectUtils.isNotNull(retrievedBalanceHistory)) {
251             balanceHistory = retrievedBalanceHistory;
252         }
253 
254         KualiDecimal amount = originEntryFull.getTransactionLedgerEntryAmount();
255 
256         // Make sure the amount update properly recognized debit / credit logic. This is modeled after PostBalance#post
257         originEntryFull.refreshReferenceObject(OLEPropertyConstants.BALANCE_TYPE);
258         originEntryFull.refreshReferenceObject(OLEPropertyConstants.OBJECT_TYPE);
259         if (originEntryFull.getBalanceType().isFinancialOffsetGenerationIndicator()) {
260             if (!originEntryFull.getTransactionDebitCreditCode().equals(originEntryFull.getObjectType().getFinObjectTypeDebitcreditCd())) {
261                 amount = amount.negated();
262             }
263         }
264 
265         balanceHistory.addAmount(originEntryFull.getUniversityFiscalPeriodCode(), amount);
266 
267         businessObjectService.save(balanceHistory);
268     }
269 
270     /**
271      * @see org.kuali.ole.gl.batch.service.BalancingService#getBalance(org.kuali.ole.gl.businessobject.LedgerBalanceHistory)
272      */
273     @Override
274     public Balance getBalance(LedgerBalanceHistory ledgerBalanceHistory) {
275         Balance balance = new Balance((BalanceHistory) ledgerBalanceHistory);
276         return (Balance) businessObjectService.retrieve(balance);
277     }
278 
279     /**
280      * @see org.kuali.ole.gl.batch.service.BalancingService#clearPosterFileCache()
281      */
282     @Override
283     public void clearPosterFileCache() {
284         this.posterInputFile = null;
285         this.posterErrorOutputFile = null;
286         this.reversalInputFile = null;
287         this.reversalErrorOutputFile = null;
288         this.icrInputFile = null;
289         this.icrErrorOutputFile = null;
290     }
291 
292     /**
293      * @see org.kuali.ole.gl.batch.service.impl.BalancingServiceBaseImpl#customPopulateHistoryTables(java.lang.Integer)
294      */
295     @Override
296     public void customPopulateHistoryTables(Integer fiscalYear) {
297         balancingDao.populateAccountBalancesHistory(fiscalYear);
298         balancingDao.populateEncumbranceHistory(fiscalYear);
299     }
300 
301     /**
302      * @see org.kuali.ole.gl.batch.service.impl.BalancingServiceBaseImpl#doesCustomHistoryExist(java.lang.Integer)
303      */
304     @Override
305     protected boolean doesCustomHistoryExist(Integer fiscalYear) {
306         return (this.getHistoryCount(fiscalYear, AccountBalanceHistory.class) > 0 &&
307                 this.getHistoryCount(fiscalYear, EncumbranceHistory.class) > 0);
308     }
309 
310     /**
311      * @see org.kuali.ole.gl.batch.service.impl.BalancingServiceBaseImpl#deleteCustomHistory(java.lang.Integer)
312      */
313     @Override
314     protected void deleteCustomHistory(Integer fiscalYear) {
315         deleteHistory(fiscalYear, AccountBalanceHistory.class);
316         deleteHistory(fiscalYear, EncumbranceHistory.class);
317 
318         reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_OBSOLETE_FISCAL_YEAR_DATA_DELETED), (AccountBalanceHistory.class).getSimpleName(), (EncumbranceHistory.class).getSimpleName(), fiscalYear);
319         reportWriterService.writeNewLines(1);
320     }
321 
322     /**
323      * @see org.kuali.ole.gl.batch.service.impl.BalancingServiceBaseImpl#updateCustomHistory(org.kuali.ole.gl.businessobject.OriginEntryInformation)
324      */
325     @Override
326     protected void updateCustomHistory(Integer postMode, OriginEntryInformation originEntry) {
327         this.updateAccountBalanceHistory(originEntry);
328         this.updateEncumbranceHistory(originEntry);
329     }
330 
331 
332     /**
333      * Update the account balance history table
334      * @param originEntry representing the update details
335      * @see org.kuali.ole.gl.batch.service.impl.PostAccountBalance#post(org.kuali.ole.gl.businessobject.Transaction, int, java.util.Date)
336      */
337     protected void updateAccountBalanceHistory(OriginEntryInformation originEntry) {
338         OriginEntryFull originEntryFull = (OriginEntryFull) originEntry;
339 
340         // As taken from PostAccountBalance#post: only post transactions where: balance type code is AC or CB or where object type
341         // isn't FB and
342         // balance type code is EX, IE, PE and CE
343         originEntryFull.refreshReferenceObject(OLEPropertyConstants.OPTION);
344         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()))) {
345             // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end?
346             AccountBalanceHistory accountBalanceHistory = new AccountBalanceHistory(originEntry);
347 
348             AccountBalanceHistory retrievedAccountBalanceHistory = (AccountBalanceHistory) businessObjectService.retrieve(accountBalanceHistory);
349             if(ObjectUtils.isNotNull(retrievedAccountBalanceHistory)) {
350                 accountBalanceHistory = retrievedAccountBalanceHistory;
351             }
352 
353             // Following is a copy of PostAccountBalance.updateAccountBalanceReturn since the blancing process is to do this
354             // independently
355             if (accountBalanceHistory.addAmount(originEntryFull)) {
356                 businessObjectService.save(accountBalanceHistory);
357             }
358         }
359     }
360 
361     /**
362      *
363      * @see org.kuali.ole.gl.batch.service.BalancingService#clearBalanceHistory()
364      */
365 
366     @Override
367     public void clearHistories() {
368         Map<String, Object> fieldValues = new HashMap<String, Object>();
369         businessObjectService.deleteMatching(EntryHistory.class, fieldValues);
370         businessObjectService.deleteMatching(BalanceHistory.class, fieldValues);
371         businessObjectService.deleteMatching(EncumbranceHistory.class, fieldValues);
372         businessObjectService.deleteMatching(AccountBalanceHistory.class, fieldValues);
373 
374         reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_HISTORY_PURGED));
375     }
376 
377     /**
378      * @see org.kuali.ole.gl.batch.service.BalancingService#getFilenames()
379      */
380     @Override
381     public String getFilenames() {
382         return (this.posterInputFile == null ? null : this.posterInputFile.getName()) + "\n"
383           + (this.posterErrorOutputFile == null ? null : this.posterErrorOutputFile.getName()) + "\n"
384           + (this.reversalInputFile == null ? null : this.reversalInputFile.getName()) + "\n"
385           + (this.reversalErrorOutputFile == null ? null : this.reversalErrorOutputFile.getName()) + "\n"
386           + (this.icrInputFile == null ? null : this.icrInputFile.getName()) + "\n"
387           + (this.icrErrorOutputFile == null ? null : this.icrErrorOutputFile.getName());
388     }
389 
390     /**
391      * Compares entries in the Balance and BalanceHistory tables to ensure the amounts match.
392      * @return count is compare failures
393      */
394     @Override
395     protected Integer compareBalanceHistory() {
396         Integer countComparisionFailures = 0;
397 
398 
399         String balanceTable = persistenceStructureService.getTableName(Balance.class);
400         String historyTable = persistenceStructureService.getTableName(balanceHistoryPersistentClass);
401 
402         List<Balance> data = ledgerEntryBalanceCachingDao.compareBalanceHistory(balanceTable, historyTable, getFiscalYear());
403 
404         if (!data.isEmpty()) {
405             for (Iterator<Balance> itr = data.iterator(); itr.hasNext();) {
406                 BalanceHistory balance = createBalanceFromMap((Map<String, Object>)itr.next());
407                 countComparisionFailures++;
408                 if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) {
409                     reportWriterService.writeError(balance, new Message(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, balance.getClass().getSimpleName()));
410                 }
411             }
412         }
413 
414         return countComparisionFailures;
415     }
416 
417     /**
418      * Compares entries in the Entry and EntryHistory tables to ensure the amounts match.
419      * @return count is compare failures
420      */
421     @Override
422     protected Integer compareEntryHistory() {
423         Integer countComparisionFailures = 0;
424 
425         String entryTable = persistenceStructureService.getTableName(Entry.class);
426         String historyTable = persistenceStructureService.getTableName(entryHistoryPersistentClass);
427 
428         List<Entry> data = ledgerEntryBalanceCachingDao.compareEntryHistory(entryTable, historyTable, getFiscalYear());
429 
430         if (!data.isEmpty()) {
431             for (Iterator<Entry> itr = data.iterator(); itr.hasNext();) {
432                 EntryHistory entry = createEntryHistoryFromMap((Map<String, Object>)itr.next());
433                 countComparisionFailures++;
434                 if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) {
435                     reportWriterService.writeError(entry, new Message(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, entry.getClass().getSimpleName()));
436                 }
437 
438             }
439         }
440 
441         return countComparisionFailures;
442     }
443 
444     /**
445      * Update the encumbrance history table
446      * @param originEntry representing the update details
447      * @see org.kuali.ole.gl.batch.service.impl.PostEncumbrance#post(org.kuali.ole.gl.businessobject.Transaction, int, java.util.Date)
448      */
449     protected void updateEncumbranceHistory(OriginEntryInformation originEntry) {
450         OriginEntryFull originEntryFull = (OriginEntryFull) originEntry;
451 
452         // PostEncumbrance.verifyTransaction is not run because entries that fail that verification will be in the error poster file
453         // which entries
454         // are already ignored before being passed to this method.
455 
456         // As taken from PostEncumbrance#post: If the encumbrance update code is space or N, or the object type code is FB we don't
457         // need to post an encumbrance
458         originEntryFull.refreshReferenceObject(OLEPropertyConstants.OPTION);
459         if ((StringUtils.isBlank(originEntryFull.getTransactionEncumbranceUpdateCode())) || " ".equals(originEntryFull.getTransactionEncumbranceUpdateCode()) || OLEConstants.ENCUMB_UPDT_NO_ENCUMBRANCE_CD.equals(originEntryFull.getTransactionEncumbranceUpdateCode()) || originEntryFull.getOption().getFinObjectTypeFundBalanceCd().equals(originEntryFull.getFinancialObjectTypeCode())) {
460             return;
461         }
462 
463         EncumbranceHistory encumbranceHistory = new EncumbranceHistory(originEntryFull);
464         if (OLEConstants.ENCUMB_UPDT_REFERENCE_DOCUMENT_CD.equals(originEntryFull.getTransactionEncumbranceUpdateCode())) {
465             encumbranceHistory.setDocumentNumber(originEntryFull.getReferenceFinancialDocumentNumber());
466             encumbranceHistory.setOriginCode(originEntryFull.getReferenceFinancialSystemOriginationCode());
467             encumbranceHistory.setDocumentTypeCode(originEntryFull.getReferenceFinancialDocumentTypeCode());
468         }
469         // TODO Retrieve and update 1 by 1? Is a HashMap or cache better so that storing only occurs once at the end?
470         EncumbranceHistory retrievedEncumbranceHistory = (EncumbranceHistory) businessObjectService.retrieve(encumbranceHistory);
471 
472         if(ObjectUtils.isNotNull(retrievedEncumbranceHistory)) {
473             encumbranceHistory = retrievedEncumbranceHistory;
474         }
475 
476         // Following is a copy & paste of PostEncumbrance.updateEncumbrance since the balancing process is to do this independently
477         encumbranceHistory.addAmount(originEntryFull);
478 
479         businessObjectService.save(encumbranceHistory);
480     }
481 
482 
483 
484     /**
485      * @see org.kuali.ole.gl.batch.service.impl.BalancingServiceBaseImpl#customCompareHistory()
486      */
487     @Override
488     protected Map<String, Integer> customCompareHistory() {
489         Integer countAccountBalanceComparisionFailure = this.accountBalanceCompareHistory();
490         Integer countEncumbranceComparisionFailure = this.encumbranceCompareHistory();
491 
492         // Using LinkedHashMap because we want it ordered
493         Map<String, Integer> countMap = new LinkedHashMap<String, Integer>();
494         countMap.put((AccountBalanceHistory.class).getSimpleName(), countAccountBalanceComparisionFailure);
495         countMap.put((EncumbranceHistory.class).getSimpleName(), countEncumbranceComparisionFailure);
496 
497         return countMap;
498     }
499 
500     /**
501      * Does comparision, error printing and returns failure count for account balances
502      * @return failure count
503      */
504     protected Integer accountBalanceCompareHistory() {
505         Integer countComparisionFailures = 0;
506 
507         String accountBalanceTable = persistenceStructureService.getTableName(AccountBalance.class);
508         String historyTable = persistenceStructureService.getTableName(AccountBalanceHistory.class);
509 
510 
511         List<AccountBalance> data = ledgerEntryBalanceCachingDao.accountBalanceCompareHistory(accountBalanceTable, historyTable, getFiscalYear());
512 
513         if (!data.isEmpty()) {
514             for (Iterator<AccountBalance> itr = data.iterator(); itr.hasNext();) {
515                 AccountBalanceHistory accountBalanceHistory = createAccountBalanceHistoryFromMap((Map<String, Object>)itr.next());
516                 countComparisionFailures++;
517                 if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) {
518                     reportWriterService.writeError(accountBalanceHistory, new Message(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, accountBalanceHistory.getClass().getSimpleName()));
519                 }
520             }
521 
522         }
523         else {
524             reportWriterService.writeNewLines(1);
525             reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_FAILURE_COUNT), (AccountBalanceHistory.class).getSimpleName(), countComparisionFailures, this.getComparisonFailuresToPrintPerReport());
526         }
527         return countComparisionFailures;
528     }
529 
530     /**
531      * Does comparision, error printing and returns failure count for encumbrances
532      * @return failure count
533      */
534     protected Integer encumbranceCompareHistory() {
535         Integer countComparisionFailures = 0;
536 
537         String encumbranceTable = persistenceStructureService.getTableName(Encumbrance.class);
538         String historyTable = persistenceStructureService.getTableName(EncumbranceHistory.class);
539 
540         List<Encumbrance> data = ledgerEntryBalanceCachingDao.encumbranceCompareHistory(encumbranceTable, historyTable, getFiscalYear());
541 
542         if (!data.isEmpty()) {
543             for (Iterator<Encumbrance> itr = data.iterator(); itr.hasNext();) {
544                 EncumbranceHistory encumbranceHistory = createEncumbranceHistoryFromMap((Map<String, Object>)itr.next());
545                 countComparisionFailures++;
546                 if (countComparisionFailures <= this.getComparisonFailuresToPrintPerReport()) {
547                     reportWriterService.writeError(encumbranceHistory, new Message(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_RECORD_FAILED_BALANCING), Message.TYPE_WARNING, encumbranceHistory.getClass().getSimpleName()));
548                 }
549             }
550 
551         }
552         else {
553             reportWriterService.writeNewLines(1);
554             reportWriterService.writeFormattedMessageLine(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.MESSAGE_BATCH_BALANCING_FAILURE_COUNT), (EncumbranceHistory.class).getSimpleName(), countComparisionFailures, this.getComparisonFailuresToPrintPerReport());
555         }
556 
557 
558         countComparisionFailures = data.size();
559 
560         return countComparisionFailures;
561     }
562 
563     /**
564      * @see org.kuali.ole.gl.batch.service.impl.BalancingServiceBaseImpl#customPrintRowCountHistory()
565      */
566     @Override
567     protected void customPrintRowCountHistory(Integer fiscalYear) {
568         // Note that fiscal year is passed as null for the History tables because for those we shouldn't have data prior to the
569         // fiscal year anyway (and
570         // if we do it's a bug that should be discovered)
571         reportWriterService.writeStatisticLine(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ACCOUNT_BALANCE_ROW_COUNT_HISTORY), this.getShortTableLabel((AccountBalanceHistory.class).getSimpleName()), "(" + (AccountBalanceHistory.class).getSimpleName() + ")", this.getHistoryCount(null, AccountBalanceHistory.class));
572         reportWriterService.writeStatisticLine(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ACCOUNT_BALANCE_ROW_COUNT_PRODUCTION), this.getShortTableLabel((AccountBalance.class).getSimpleName()), accountBalanceDao.findCountGreaterOrEqualThan(fiscalYear));
573         reportWriterService.writeStatisticLine(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ENCUMBRANCE_ROW_COUNT_HISTORY), this.getShortTableLabel((EncumbranceHistory.class).getSimpleName()), "(" + (EncumbranceHistory.class).getSimpleName() + ")", this.getHistoryCount(null, EncumbranceHistory.class));
574         reportWriterService.writeStatisticLine(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.Balancing.REPORT_ENCUMBRANCE_ROW_COUNT_PRODUCTION), this.getShortTableLabel((Encumbrance.class).getSimpleName()), encumbranceDao.findCountGreaterOrEqualThan(fiscalYear));
575     }
576 
577     /**
578      * Sets the BalancingDao
579      * 
580      * @param balancingDao The BalancingDao to set.
581      */
582     public void setBalancingDao(BalancingDao balancingDao) {
583         this.balancingDao = balancingDao;
584     }
585 
586     /**
587      * Sets the AccountBalanceDao
588      * 
589      * @param accountBalanceDao The AccountBalanceDao to set.
590      */
591     public void setAccountBalanceDao(AccountBalanceDao accountBalanceDao) {
592         this.accountBalanceDao = accountBalanceDao;
593     }
594 
595     /**
596      * Sets the EncumbranceDao
597      * 
598      * @param encumbranceDao The EncumbranceDao to set.
599      */
600     public void setEncumbranceDao(EncumbranceDao encumbranceDao) {
601         this.encumbranceDao = encumbranceDao;
602     }
603 
604     protected BalanceHistory createBalanceFromMap(Map<String, Object> map) {
605         BalanceHistory balance = new BalanceHistory();
606         balance.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue());
607         balance.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE));
608         balance.setAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_NUMBER));
609         balance.setSubAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_ACCOUNT_NUMBER));
610         balance.setObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE));
611         balance.setSubObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_OBJECT_CODE));
612         balance.setBalanceTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE));
613         balance.setObjectTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_TYPE_CODE));
614 
615         balance.setAccountLineAnnualBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNTING_LINE_ACTUALS_BALANCE_AMOUNT)));
616         balance.setContractsGrantsBeginningBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.CONTRACT_AND_GRANTS_BEGINNING_BALANCE)));
617         balance.setBeginningBalanceLineAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.BEGINNING_BALANCE)));
618         balance.setMonth1Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_1_ACCT_AMT)));
619         balance.setMonth2Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_2_ACCT_AMT)));
620         balance.setMonth3Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_3_ACCT_AMT)));
621         balance.setMonth4Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_4_ACCT_AMT)));
622         balance.setMonth5Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_5_ACCT_AMT)));
623         balance.setMonth6Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_6_ACCT_AMT)));
624         balance.setMonth7Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_7_ACCT_AMT)));
625         balance.setMonth8Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_8_ACCT_AMT)));
626         balance.setMonth9Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_9_ACCT_AMT)));
627         balance.setMonth10Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_10_ACCT_AMT)));
628         balance.setMonth11Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_11_ACCT_AMT)));
629         balance.setMonth12Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_12_ACCT_AMT)));
630         balance.setMonth13Amount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.MONTH_13_ACCT_AMT)));
631 
632         return balance;
633 
634     }
635 
636     protected EntryHistory createEntryHistoryFromMap(Map<String, Object> map) {
637         EntryHistory entry = new EntryHistory();
638         entry.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue());
639         entry.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE));
640         entry.setFinancialObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE));
641         entry.setFinancialBalanceTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE));
642         entry.setUniversityFiscalPeriodCode((String)map.get(GeneralLedgerConstants.ColumnNames.FISCAL_PERIOD_CODE));
643         // entry.setFinancialObjectTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_TYPE_CODE));
644         entry.setTransactionDebitCreditCode((String)map.get(GeneralLedgerConstants.ColumnNames.TRANSACTION_DEBIT_CREDIT_CD));
645         entry.setTransactionLedgerEntryAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.TRANSACTION_LEDGER_ENTRY_AMOUNT)));
646 
647         return entry;
648 
649     }
650 
651     protected AccountBalanceHistory createAccountBalanceHistoryFromMap(Map<String, Object> map) {
652         // UNIV_FISCAL_YR, FIN_COA_CD, ACCOUNT_NBR, SUB_ACCT_NBR, FIN_OBJECT_CD, FIN_SUB_OBJ_CD, CURR_BDLN_BAL_AMT,
653         // ACLN_ACTLS_BAL_AMT, ACLN_ENCUM_BAL_AMT
654         AccountBalanceHistory accountBalanceHistory = new AccountBalanceHistory();
655         accountBalanceHistory.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue());
656         accountBalanceHistory.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE));
657         accountBalanceHistory.setAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_NUMBER));
658         accountBalanceHistory.setSubAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_ACCOUNT_NUMBER));
659         accountBalanceHistory.setObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE));
660         accountBalanceHistory.setSubObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_OBJECT_CODE));
661         accountBalanceHistory.setCurrentBudgetLineBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.CURRENT_BUDGET_LINE_BALANCE_AMOUNT)));
662         accountBalanceHistory.setAccountLineActualsBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_LINE_ACTUALS_BALANCE_AMOUNT)));
663         accountBalanceHistory.setAccountLineEncumbranceBalanceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_LINE_ENCUMBRANCE_BALANCE_AMOUNT)));
664 
665 
666         return accountBalanceHistory;
667     }
668 
669     protected EncumbranceHistory createEncumbranceHistoryFromMap(Map<String, Object> map) {
670         EncumbranceHistory encumbranceHistory = new EncumbranceHistory();
671         encumbranceHistory.setUniversityFiscalYear(((BigDecimal)(map.get(GeneralLedgerConstants.ColumnNames.UNIVERSITY_FISCAL_YEAR))).intValue());
672         encumbranceHistory.setChartOfAccountsCode((String)map.get(GeneralLedgerConstants.ColumnNames.CHART_OF_ACCOUNTS_CODE));
673         encumbranceHistory.setAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_NUMBER));
674         encumbranceHistory.setSubAccountNumber((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_ACCOUNT_NUMBER));
675         encumbranceHistory.setObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.OBJECT_CODE));
676         encumbranceHistory.setSubObjectCode((String)map.get(GeneralLedgerConstants.ColumnNames.SUB_OBJECT_CODE));
677         encumbranceHistory.setBalanceTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE));
678         encumbranceHistory.setDocumentTypeCode((String)map.get(GeneralLedgerConstants.ColumnNames.FINANCIAL_DOCUMENT_TYPE_CODE));
679         encumbranceHistory.setOriginCode((String)map.get(GeneralLedgerConstants.ColumnNames.ORIGINATION_CODE));
680         encumbranceHistory.setDocumentNumber((String)map.get(GeneralLedgerConstants.ColumnNames.DOCUMENT_NUMBER));
681         encumbranceHistory.setAccountLineEncumbranceAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_LINE_ENCUMBRANCE_AMOUNT)));
682         encumbranceHistory.setAccountLineEncumbranceClosedAmount(convertBigDecimalToKualiDecimal((BigDecimal)map.get(GeneralLedgerConstants.ColumnNames.ACCOUNT_LINE_ENCUMBRANCE_CLOSED_AMOUNT)));
683 
684 
685         return encumbranceHistory;
686     }
687 
688     protected KualiDecimal convertBigDecimalToKualiDecimal(BigDecimal biggy) {
689         if (ObjectUtils.isNull(biggy))
690             return new KualiDecimal(0);
691         else
692             return new KualiDecimal(biggy);
693 
694     }
695 
696 }