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.sql.Date;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.kuali.kfs.coa.businessobject.Account;
027    import org.kuali.kfs.coa.service.AccountService;
028    import org.kuali.kfs.gl.GeneralLedgerConstants;
029    import org.kuali.kfs.gl.batch.SufficientFundsAccountUpdateStep;
030    import org.kuali.kfs.gl.batch.service.SufficientFundsAccountUpdateService;
031    import org.kuali.kfs.gl.businessobject.Balance;
032    import org.kuali.kfs.gl.businessobject.SufficientFundBalances;
033    import org.kuali.kfs.gl.businessobject.SufficientFundRebuild;
034    import org.kuali.kfs.gl.dataaccess.BalanceDao;
035    import org.kuali.kfs.gl.dataaccess.SufficientFundBalancesDao;
036    import org.kuali.kfs.gl.dataaccess.SufficientFundRebuildDao;
037    import org.kuali.kfs.gl.service.SufficientFundsService;
038    import org.kuali.kfs.sys.KFSConstants;
039    import org.kuali.kfs.sys.KFSKeyConstants;
040    import org.kuali.kfs.sys.KFSPropertyConstants;
041    import org.kuali.kfs.sys.Message;
042    import org.kuali.kfs.sys.businessobject.SystemOptions;
043    import org.kuali.kfs.sys.context.SpringContext;
044    import org.kuali.kfs.sys.dataaccess.OptionsDao;
045    import org.kuali.kfs.sys.service.ReportWriterService;
046    import org.kuali.rice.kns.service.BusinessObjectService;
047    import org.kuali.rice.kns.service.DateTimeService;
048    import org.kuali.rice.kns.service.KualiConfigurationService;
049    import org.kuali.rice.kns.service.ParameterService;
050    import org.kuali.rice.kns.util.KualiDecimal;
051    import org.springframework.transaction.annotation.Transactional;
052    
053    /**
054     * The default implementation of SufficientFundsAccountUpdateService
055     */
056    @Transactional
057    public class SufficientFundsAccountUpdateServiceImpl implements SufficientFundsAccountUpdateService {
058        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SufficientFundsAccountUpdateServiceImpl.class);
059    
060        private DateTimeService dateTimeService;
061        private KualiConfigurationService kualiConfigurationService;
062        private BalanceDao balanceDao;
063        private SufficientFundBalancesDao sufficientFundBalancesDao;
064        private SufficientFundRebuildDao sufficientFundRebuildDao;
065        private SufficientFundsService sufficientFundsService;
066        private OptionsDao optionsDao;
067        private AccountService accountService;
068        private ReportWriterService reportWriterService;
069        private BusinessObjectService boService;
070    
071        private Date runDate;
072        private SystemOptions options;
073    
074        Map batchError;
075        List reportSummary;
076        List<Message> transactionErrors;
077    
078        private Integer universityFiscalYear;
079        private int sfrbRecordsConvertedCount = 0;
080        private int sfrbRecordsReadCount = 0;
081        private int sfrbRecordsDeletedCount = 0;
082        private int sfrbNotDeletedCount = 0;
083        private int sfblDeletedCount = 0;
084        private int sfblInsertedCount = 0;
085        private int sfblUpdatedCount = 0;
086        private int warningCount = 0;
087    
088    
089        private SufficientFundBalances currentSfbl = null;
090    
091        /**
092         * Constructs a SufficientFundsAccountUpdateServiceImpl instance
093         */
094        public SufficientFundsAccountUpdateServiceImpl() {
095            super();
096        }
097    
098        /**
099         * Returns the fiscal year, set in a parameter, of sufficient funds to rebuild
100         * 
101         * @return the fiscal year
102         */
103        protected Integer getFiscalYear() {
104            String val = SpringContext.getBean(ParameterService.class).getParameterValue(SufficientFundsAccountUpdateStep.class, GeneralLedgerConstants.FISCAL_YEAR_PARM);
105            return Integer.parseInt(val);
106        }
107    
108        /**
109         * Rebuilds all necessary sufficient funds balances.
110         * @see org.kuali.kfs.gl.batch.service.SufficientFundsAccountUpdateService#rebuildSufficientFunds()
111         */
112        public void rebuildSufficientFunds() { // driver
113            List <SufficientFundRebuild> rebuildSfrbList = new ArrayList<SufficientFundRebuild>(); 
114            
115            LOG.debug("rebuildSufficientFunds() started");
116    
117            universityFiscalYear = getFiscalYear();
118            initService();
119            
120            //need to add time info - batch util?
121            runDate = dateTimeService.getCurrentSqlDate();
122            
123            // Get all the O types and convert them to A types
124            if (LOG.isDebugEnabled()) {
125                LOG.debug("rebuildSufficientFunds() Converting O types to A types");
126            }
127            Map criteria = new HashMap();
128            criteria.put(KFSPropertyConstants.ACCOUNT_FINANCIAL_OBJECT_TYPE_CODE, KFSConstants.SF_TYPE_OBJECT);
129            
130            for (Iterator iter = boService.findMatching(SufficientFundRebuild.class, criteria).iterator(); iter.hasNext();) {
131                SufficientFundRebuild sfrb = (SufficientFundRebuild) iter.next();
132                ++sfrbRecordsReadCount;
133    
134                transactionErrors = new ArrayList<Message>();
135    
136                convertOtypeToAtypes(sfrb);
137    
138                if (transactionErrors.size() > 0) {
139                    reportWriterService.writeError(sfrb, transactionErrors);
140                    rebuildSfrbList.add(sfrb);
141                }
142              }
143            criteria.clear();
144            
145            // Get all the A types and process them
146            LOG.debug("rebuildSufficientFunds() Calculating SF balances for all A types");
147            
148            criteria.put(KFSPropertyConstants.ACCOUNT_FINANCIAL_OBJECT_TYPE_CODE, KFSConstants.SF_TYPE_ACCOUNT);
149    
150            for (Iterator iter = boService.findMatching(SufficientFundRebuild.class, criteria).iterator(); iter.hasNext();) {
151                SufficientFundRebuild sfrb = (SufficientFundRebuild) iter.next();
152                ++sfrbRecordsReadCount;
153    
154                transactionErrors = new ArrayList<Message>();
155    
156                calculateSufficientFundsByAccount(sfrb);
157    
158                if (transactionErrors.size() > 0) {
159                    reportWriterService.writeError(sfrb, transactionErrors);
160                    rebuildSfrbList.add(sfrb);
161                }
162    
163            }
164            sufficientFundRebuildDao.purgeSufficientFundRebuild();
165            boService.save( rebuildSfrbList);
166    
167            // Look at all the left over rows. There shouldn't be any left if all are O's and A's without error.
168            // Write out error messages for any that aren't A or O
169            LOG.debug("rebuildSufficientFunds() Handle any non-A and non-O types");
170            for (Iterator iter = boService.findAll(SufficientFundRebuild.class).iterator(); iter.hasNext();) {
171                SufficientFundRebuild sfrb = (SufficientFundRebuild) iter.next();
172    
173                if ((!KFSConstants.SF_TYPE_ACCOUNT.equals(sfrb.getAccountFinancialObjectTypeCode())) && (!KFSConstants.SF_TYPE_OBJECT.equals(sfrb.getAccountFinancialObjectTypeCode()))) {
174                    ++sfrbRecordsReadCount;
175                    transactionErrors = new ArrayList<Message>();
176                    addTransactionError(kualiConfigurationService.getPropertyString(KFSKeyConstants.ERROR_INVALID_SF_OBJECT_TYPE_CODE));
177                    ++warningCount;
178                    ++sfrbNotDeletedCount;
179                    reportWriterService.writeError(sfrb, transactionErrors);
180                }
181            }
182    
183            // write out report and errors
184            if (LOG.isDebugEnabled()) {
185                LOG.debug("rebuildSufficientFunds() Create report");
186            }
187            
188            // write out statistics
189            reportWriterService.writeStatisticLine("                                   SFRB RECORDS CONVERTED FROM OBJECT TO ACCOUNT  %,9d\n", sfrbRecordsConvertedCount);
190            reportWriterService.writeStatisticLine("                                   POST CONVERSION SFRB RECORDS READ              %,9d\n", sfrbRecordsReadCount);
191            reportWriterService.writeStatisticLine("                                   SFRB RECORDS DELETED                           %,9d\n", sfrbRecordsDeletedCount);
192            reportWriterService.writeStatisticLine("                                   SFRB RECORDS KEPT DUE TO ERRORS                %,9d\n", sfrbNotDeletedCount);
193            reportWriterService.writeStatisticLine("                                   SFBL RECORDS DELETED                           %,9d\n", sfblDeletedCount);
194            reportWriterService.writeStatisticLine("                                   SFBL RECORDS ADDED                             %,9d\n", sfblInsertedCount);
195            reportWriterService.writeStatisticLine("                                   SFBL RECORDS UDPATED                           %,9d\n", sfblUpdatedCount);
196        }
197    
198        /**
199         * Initializes the process at the beginning of a run.
200         */
201        protected void initService() {
202            batchError = new HashMap();
203            reportSummary = new ArrayList();
204    
205            runDate = new Date(dateTimeService.getCurrentDate().getTime());
206    
207            options = optionsDao.getByPrimaryId(universityFiscalYear);
208    
209            if (options == null) {
210                throw new IllegalStateException(kualiConfigurationService.getPropertyString(KFSKeyConstants.ERROR_UNIV_DATE_NOT_FOUND));
211            }
212        }
213    
214        /**
215         * Given an O SF rebuild type, it will look up all of the matching balances in the table and add each account it finds as an A
216         * SF rebuild type.
217         * 
218         * @param sfrb the sufficient fund rebuild record to convert
219         */
220        public void convertOtypeToAtypes(SufficientFundRebuild sfrb) {
221            ++sfrbRecordsConvertedCount;
222            Collection fundBalances = sufficientFundBalancesDao.getByObjectCode(universityFiscalYear, sfrb.getChartOfAccountsCode(), sfrb.getAccountNumberFinancialObjectCode());
223            Map criteria = new HashMap();
224            
225            for (Iterator fundBalancesIter = fundBalances.iterator(); fundBalancesIter.hasNext();) {
226                SufficientFundBalances sfbl = (SufficientFundBalances) fundBalancesIter.next();
227                criteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, sfbl.getChartOfAccountsCode());
228                criteria.put(KFSPropertyConstants.ACCOUNT_FINANCIAL_OBJECT_TYPE_CODE, KFSConstants.SF_TYPE_ACCOUNT);
229                criteria.put(KFSPropertyConstants.ACCOUNT_NUMBER_FINANCIAL_OBJECT_CODE, sfbl.getAccountNumber());
230                
231                SufficientFundRebuild altSfrb = (SufficientFundRebuild)boService.findByPrimaryKey(SufficientFundRebuild.class, criteria);
232                if (altSfrb == null) {
233                    altSfrb = new SufficientFundRebuild();
234                    altSfrb.setAccountFinancialObjectTypeCode(KFSConstants.SF_TYPE_ACCOUNT);
235                    altSfrb.setAccountNumberFinancialObjectCode(sfbl.getAccountNumber());
236                    altSfrb.setChartOfAccountsCode(sfbl.getChartOfAccountsCode());
237                    boService.save(altSfrb);
238                }
239                criteria.clear();
240            }
241        }
242    
243        /**
244         * Updates sufficient funds balances for the given account
245         * 
246         * @param sfrb the sufficient fund rebuild record, with a chart and account number
247         */
248        public void calculateSufficientFundsByAccount(SufficientFundRebuild sfrb) {
249            Account sfrbAccount = accountService.getByPrimaryId(sfrb.getChartOfAccountsCode(), sfrb.getAccountNumberFinancialObjectCode());
250            if (sfrbAccount == null) {
251                String msg = "Account found in SufficientFundsRebuild table that is not in Accounts table [" + sfrb.getChartOfAccountsCode() + "-" + sfrb.getAccountNumberFinancialObjectCode() + "].";
252                LOG.error(msg);
253                throw new RuntimeException(msg);
254            }
255            if ((sfrbAccount.getAccountSufficientFundsCode() != null) 
256                    && (KFSConstants.SF_TYPE_ACCOUNT.equals(sfrbAccount.getAccountSufficientFundsCode()) 
257                            || KFSConstants.SF_TYPE_CASH_AT_ACCOUNT.equals(sfrbAccount.getAccountSufficientFundsCode()) 
258                            || KFSConstants.SF_TYPE_CONSOLIDATION.equals(sfrbAccount.getAccountSufficientFundsCode()) 
259                            || KFSConstants.SF_TYPE_LEVEL.equals(sfrbAccount.getAccountSufficientFundsCode()) 
260                            || KFSConstants.SF_TYPE_OBJECT.equals(sfrbAccount.getAccountSufficientFundsCode()) 
261                            || KFSConstants.SF_TYPE_NO_CHECKING.equals(sfrbAccount.getAccountSufficientFundsCode()))) {
262                ++sfrbRecordsDeletedCount;
263                 sfblDeletedCount += sufficientFundBalancesDao.deleteByAccountNumber(universityFiscalYear, sfrb.getChartOfAccountsCode(), sfrbAccount.getAccountNumber());
264    
265                if (KFSConstants.SF_TYPE_NO_CHECKING.equalsIgnoreCase(sfrbAccount.getAccountSufficientFundsCode())) {
266                    // nothing to do here, no errors either, just return
267                    return;
268                }
269    
270                Iterator balancesIterator = balanceDao.findAccountBalances(universityFiscalYear, sfrb.getChartOfAccountsCode(), sfrb.getAccountNumberFinancialObjectCode(), sfrbAccount.getAccountSufficientFundsCode());
271    
272                if (balancesIterator == null) {
273                    addTransactionError(kualiConfigurationService.getPropertyString(KFSKeyConstants.ERROR_BALANCE_NOT_FOUND_FOR) + universityFiscalYear + ")");
274                    ++warningCount;
275                    ++sfrbNotDeletedCount;
276                    return;
277                }
278    
279                String currentFinObjectCd = "";
280                while (balancesIterator.hasNext()) {
281                    Balance balance = (Balance) balancesIterator.next();
282                    String tempFinObjectCd = sufficientFundsService.getSufficientFundsObjectCode(balance.getFinancialObject(), sfrbAccount.getAccountSufficientFundsCode());
283    
284                    if (!tempFinObjectCd.equals(currentFinObjectCd)) {
285                        // we have a change or are on the last record, write out the data if there is any
286                        currentFinObjectCd = tempFinObjectCd;
287    
288                        if (currentSfbl != null && amountsAreNonZero(currentSfbl)) {
289                            sufficientFundBalancesDao.save(currentSfbl);
290                            ++sfblInsertedCount;
291                        }
292    
293                        currentSfbl = new SufficientFundBalances();
294                        currentSfbl.setUniversityFiscalYear(universityFiscalYear);
295                        currentSfbl.setChartOfAccountsCode(sfrb.getChartOfAccountsCode());
296                        currentSfbl.setAccountNumber(sfrbAccount.getAccountNumber());
297                        currentSfbl.setFinancialObjectCode(currentFinObjectCd);
298                        currentSfbl.setAccountSufficientFundsCode(sfrbAccount.getAccountSufficientFundsCode());
299                        currentSfbl.setAccountActualExpenditureAmt(KualiDecimal.ZERO);
300                        currentSfbl.setAccountEncumbranceAmount(KualiDecimal.ZERO);
301                        currentSfbl.setCurrentBudgetBalanceAmount(KualiDecimal.ZERO);
302                    }
303    
304                    if (sfrbAccount.isForContractsAndGrants()) {
305                        balance.setAccountLineAnnualBalanceAmount(balance.getAccountLineAnnualBalanceAmount().add(balance.getContractsGrantsBeginningBalanceAmount()));
306                    }
307    
308                    if (KFSConstants.SF_TYPE_CASH_AT_ACCOUNT.equals(sfrbAccount.getAccountSufficientFundsCode())) {
309                        processCash(sfrbAccount, balance);
310                     }
311                    else {
312                        processObjectOrAccount(sfrbAccount, balance);
313                     }
314                }
315    
316                // save the last one
317                if (currentSfbl != null && amountsAreNonZero(currentSfbl)) {
318                    sufficientFundBalancesDao.save(currentSfbl);
319                    ++sfblInsertedCount;
320                }
321             }
322            else {
323                addTransactionError(kualiConfigurationService.getPropertyString(KFSKeyConstants.ERROR_INVALID_ACCOUNT_SF_CODE_FOR));
324                ++warningCount;
325                ++sfrbNotDeletedCount;
326                return;
327            }
328        }
329    
330        /**
331         * Determines if all sums associated with a sufficient funds balance are zero
332         * 
333         * @param sfbl the sufficient funds balance to check
334         * @return true if all sums in the balance are zero, false otherwise
335         */
336        protected boolean amountsAreNonZero(SufficientFundBalances sfbl) {
337            boolean zero = true;
338            zero &= KualiDecimal.ZERO.equals(sfbl.getAccountActualExpenditureAmt());
339            zero &= KualiDecimal.ZERO.equals(sfbl.getAccountEncumbranceAmount());
340            zero &= KualiDecimal.ZERO.equals(sfbl.getCurrentBudgetBalanceAmount());
341            return !zero;
342        }
343    
344        /**
345         * Determines how best to process the given balance
346         * 
347         * @param sfrbAccount the account of the current sufficient funds balance rebuild record
348         * @param balance the cash encumbrance balance to update the sufficient funds balance with
349         */
350        protected void processObjectOrAccount(Account sfrbAccount, Balance balance) {
351            if (options.getFinObjTypeExpenditureexpCd().equals(balance.getObjectTypeCode()) || options.getFinObjTypeExpendNotExpCode().equals(balance.getObjectTypeCode()) || options.getFinObjTypeExpNotExpendCode().equals(balance.getObjectTypeCode()) || options.getFinancialObjectTypeTransferExpenseCd().equals(balance.getObjectTypeCode())) {
352                if (options.getActualFinancialBalanceTypeCd().equals(balance.getBalanceTypeCode())) {
353                    processObjtAcctActual(balance);
354                }
355                else if (options.getExtrnlEncumFinBalanceTypCd().equals(balance.getBalanceTypeCode()) || options.getIntrnlEncumFinBalanceTypCd().equals(balance.getBalanceTypeCode()) || options.getPreencumbranceFinBalTypeCd().equals(balance.getBalanceTypeCode()) || options.getCostShareEncumbranceBalanceTypeCd().equals(balance.getBalanceTypeCode())) {
356                    processObjtAcctEncmbrnc(balance);
357                }
358                else if (options.getBudgetCheckingBalanceTypeCd().equals(balance.getBalanceTypeCode())) {
359                    processObjtAcctBudget(balance);
360                }
361            }
362        }
363    
364        /**
365         * Updates the current sufficient fund balance record with a non-cash actual balance
366         * 
367         * @param balance the cash encumbrance balance to update the sufficient funds balance with
368         */
369        protected void processObjtAcctActual(Balance balance) {
370            currentSfbl.setAccountActualExpenditureAmt(currentSfbl.getAccountActualExpenditureAmt().add(balance.getAccountLineAnnualBalanceAmount()));
371        }
372    
373        /**
374         * Updates the current sufficient fund balance record with a non-cash encumbrance balance
375         * 
376         * @param balance the cash encumbrance balance to update the sufficient funds balance with
377         */
378        protected void processObjtAcctEncmbrnc(Balance balance) {
379            currentSfbl.setAccountEncumbranceAmount(currentSfbl.getAccountEncumbranceAmount().add(balance.getAccountLineAnnualBalanceAmount()));
380            currentSfbl.setAccountEncumbranceAmount(currentSfbl.getAccountEncumbranceAmount().add(balance.getBeginningBalanceLineAmount()));
381        }
382    
383        /**
384         * Updates the current sufficient fund balance record with a non-cash budget balance
385         * 
386         * @param balance the cash encumbrance balance to update the sufficient funds balance with
387         */
388        protected void processObjtAcctBudget(Balance balance) {
389            currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().add(balance.getAccountLineAnnualBalanceAmount()));
390            currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().add(balance.getBeginningBalanceLineAmount()));
391        }
392    
393        /**
394         * Determines how best to process a cash balance
395         * 
396         * @param sfrbAccount the account of the current sufficient funds balance record
397         * @param balance the cash encumbrance balance to update the sufficient funds balance with
398         */
399        protected void processCash(Account sfrbAccount, Balance balance) {
400            if (balance.getBalanceTypeCode().equals(options.getActualFinancialBalanceTypeCd())) {
401                if (balance.getObjectCode().equals(sfrbAccount.getChartOfAccounts().getFinancialCashObjectCode()) || balance.getObjectCode().equals(sfrbAccount.getChartOfAccounts().getFinAccountsPayableObjectCode())) {
402                    processCashActual(sfrbAccount, balance);
403                }
404            }
405            else if (balance.getBalanceTypeCode().equals(options.getExtrnlEncumFinBalanceTypCd()) || balance.getBalanceTypeCode().equals(options.getIntrnlEncumFinBalanceTypCd()) || balance.getBalanceTypeCode().equals(options.getPreencumbranceFinBalTypeCd()) || options.getCostShareEncumbranceBalanceTypeCd().equals(balance.getBalanceTypeCode())) {
406                if (balance.getObjectTypeCode().equals(options.getFinObjTypeExpenditureexpCd()) || balance.getObjectTypeCode().equals(options.getFinObjTypeExpendNotExpCode()) || options.getFinancialObjectTypeTransferExpenseCd().equals(balance.getObjectTypeCode()) || options.getFinObjTypeExpNotExpendCode().equals(balance.getObjectTypeCode())) {
407                    processCashEncumbrance(balance);
408                }
409            }
410        }
411    
412        /**
413         * Updates the current sufficient fund balance record with a cash actual balance
414         * 
415         * @param sfrbAccount the account of the current sufficient funds balance record
416         * @param balance the cash encumbrance balance to update the sufficient funds balance with
417         */
418        protected void processCashActual(Account sfrbAccount, Balance balance) {
419            if (balance.getObjectCode().equals(sfrbAccount.getChartOfAccounts().getFinancialCashObjectCode())) {
420                currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().add(balance.getAccountLineAnnualBalanceAmount()));
421                currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().add(balance.getBeginningBalanceLineAmount()));
422            }
423            if (balance.getObjectCode().equals(sfrbAccount.getChartOfAccounts().getFinAccountsPayableObjectCode())) {
424                currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().subtract(balance.getAccountLineAnnualBalanceAmount()));
425                currentSfbl.setCurrentBudgetBalanceAmount(currentSfbl.getCurrentBudgetBalanceAmount().subtract(balance.getBeginningBalanceLineAmount()));
426            }
427        }
428    
429        /**
430         * Updates the current sufficient funds balance with a cash encumbrance balance
431         * 
432         * @param balance the cash encumbrance balance to update the sufficient funds balance with
433         */
434        protected void processCashEncumbrance(Balance balance) {
435            currentSfbl.setAccountEncumbranceAmount(currentSfbl.getAccountEncumbranceAmount().add(balance.getAccountLineAnnualBalanceAmount()));
436            currentSfbl.setAccountEncumbranceAmount(currentSfbl.getAccountEncumbranceAmount().add(balance.getBeginningBalanceLineAmount()));
437        }
438    
439        /**
440         * Adds an error message to this instance's List of error messages
441         * @param errorMessage the error message to keep
442         */
443        protected void addTransactionError(String errorMessage) {
444            transactionErrors.add(new Message(errorMessage, Message.TYPE_WARNING));
445        }
446    
447        public void setDateTimeService(DateTimeService dateTimeService) {
448            this.dateTimeService = dateTimeService;
449        }
450    
451        public void setKualiConfigurationService(KualiConfigurationService kualiConfigurationService) {
452            this.kualiConfigurationService = kualiConfigurationService;
453        }
454    
455        public void setBalanceDao(BalanceDao balanceDao) {
456            this.balanceDao = balanceDao;
457        }
458    
459        public void setSufficientFundBalancesDao(SufficientFundBalancesDao sufficientFundBalancesDao) {
460            this.sufficientFundBalancesDao = sufficientFundBalancesDao;
461        }
462    
463        public void setOptionsDao(OptionsDao optionsDao) {
464            this.optionsDao = optionsDao;
465        }
466    
467        public void setReportWriterService(ReportWriterService sfrs) {
468            reportWriterService = sfrs;
469        }
470    
471        public void setAccountService(AccountService accountService) {
472            this.accountService = accountService;
473        }
474    
475        public void setSufficientFundsService(SufficientFundsService sfs) {
476            sufficientFundsService = sfs;
477        }
478        
479        public void setBusinessObjectService(BusinessObjectService bos) {
480            boService = bos;
481        }
482        
483        public void setSufficientFundRebuildDao(SufficientFundRebuildDao sufficientFundRebuildDao) {
484            this.sufficientFundRebuildDao = sufficientFundRebuildDao;
485        }
486    }