View Javadoc
1   /*
2    * Copyright 2005 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.dataaccess.impl;
17  
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.commons.lang.StringUtils;
27  import org.apache.ojb.broker.query.Criteria;
28  import org.apache.ojb.broker.query.Query;
29  import org.apache.ojb.broker.query.QueryByCriteria;
30  import org.apache.ojb.broker.query.QueryFactory;
31  import org.apache.ojb.broker.query.ReportQueryByCriteria;
32  import org.kuali.ole.coa.businessobject.Account;
33  import org.kuali.ole.gl.GeneralLedgerConstants;
34  import org.kuali.ole.gl.OJBUtility;
35  import org.kuali.ole.gl.businessobject.Balance;
36  import org.kuali.ole.gl.businessobject.CashBalance;
37  import org.kuali.ole.gl.businessobject.Transaction;
38  import org.kuali.ole.gl.dataaccess.BalanceDao;
39  import org.kuali.ole.gl.dataaccess.LedgerBalanceBalancingDao;
40  import org.kuali.ole.sys.OLEConstants;
41  import org.kuali.ole.sys.OLEPropertyConstants;
42  import org.kuali.ole.sys.businessobject.SystemOptions;
43  import org.kuali.rice.core.api.parameter.ParameterEvaluator;
44  import org.kuali.rice.core.api.util.type.KualiDecimal;
45  import org.kuali.rice.core.framework.persistence.ojb.dao.PlatformAwareDaoBaseOjb;
46  
47  /**
48   * An OJB implementation of BalanceDao
49   */
50  public class BalanceDaoOjb extends PlatformAwareDaoBaseOjb implements BalanceDao, LedgerBalanceBalancingDao {
51      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BalanceDaoOjb.class);
52  
53      /**
54       * Does a ReportQuery to summarize GL balance data
55       * 
56       * @param universityFiscalYear the fiscal year of balances to search for
57       * @param balanceTypeCodes a list of balance type codes of balances to search for
58       * @return iterator of reported on java.lang.Object arrays with the report data
59       * @see org.kuali.ole.gl.dataaccess.BalanceDao#getGlSummary(int, java.util.List)
60       */
61      public Iterator<Object[]> getGlSummary(int universityFiscalYear, Collection<String> balanceTypeCodes) {
62          LOG.debug("getGlSummary() started");
63  
64          Criteria c = new Criteria();
65          c.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear);
66          c.addIn(OLEPropertyConstants.BALANCE_TYPE_CODE, balanceTypeCodes);
67  
68          String[] attributes = new String[] { "account.subFundGroup.fundGroupCode", "sum(accountLineAnnualBalanceAmount)", "sum(beginningBalanceLineAmount)", "sum(contractsGrantsBeginningBalanceAmount)", "sum(month1Amount)", "sum(month2Amount)", "sum(month3Amount)", "sum(month4Amount)", "sum(month5Amount)", "sum(month6Amount)", "sum(month7Amount)", "sum(month8Amount)", "sum(month9Amount)", "sum(month10Amount)", "sum(month11Amount)", "sum(month12Amount)", "sum(month13Amount)" };
69  
70          String[] groupby = new String[] { "account.subFundGroup.fundGroupCode" };
71  
72          ReportQueryByCriteria query = new ReportQueryByCriteria(Balance.class, c);
73  
74          query.setAttributes(attributes);
75          query.addGroupBy(groupby);
76          query.addOrderByAscending("account.subFundGroup.fundGroupCode");
77  
78          return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query);
79      }
80  
81      /**
82       * Queries the database for all the balances for a given fiscal year
83       * 
84       * @param year the university fiscal year of balances to return
85       * @return an iterator over all balances for a given fiscal year
86       * @see org.kuali.ole.gl.dataaccess.BalanceDao#findBalancesForFiscalYear(java.lang.Integer)
87       */
88      public Iterator<Balance> findBalancesForFiscalYear(Integer year) {
89          LOG.debug("findBalancesForFiscalYear() started");
90  
91          Criteria c = new Criteria();
92          c.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
93  
94          QueryByCriteria query = QueryFactory.newQuery(Balance.class, c);
95          query.addOrderByAscending(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE);
96          query.addOrderByAscending(OLEPropertyConstants.ACCOUNT_NUMBER);
97          query.addOrderByAscending(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
98          query.addOrderByAscending(OLEPropertyConstants.OBJECT_CODE);
99          query.addOrderByAscending(OLEPropertyConstants.SUB_OBJECT_CODE);
100         query.addOrderByAscending(OLEPropertyConstants.BALANCE_TYPE_CODE);
101         query.addOrderByAscending(OLEPropertyConstants.OBJECT_TYPE_CODE);
102 
103         return getPersistenceBrokerTemplate().getIteratorByQuery(query);
104     }
105 
106     /**
107      * Using values from the transaction as keys, lookup the balance the transaction would affect were it posted
108      * 
109      * @t a transaction to look up the related balance for
110      * @return a Balance that the given transaction would affect
111      * @see org.kuali.ole.gl.dataaccess.BalanceDao#getBalanceByTransaction(org.kuali.ole.gl.businessobject.Transaction)
112      */
113     public Balance getBalanceByTransaction(Transaction t) {
114         LOG.debug("getBalanceByTransaction() started");
115 
116         Criteria crit = new Criteria();
117         crit.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, t.getUniversityFiscalYear());
118         crit.addEqualTo(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, t.getChartOfAccountsCode());
119         crit.addEqualTo(OLEPropertyConstants.ACCOUNT_NUMBER, t.getAccountNumber());
120         crit.addEqualTo(OLEPropertyConstants.SUB_ACCOUNT_NUMBER, t.getSubAccountNumber());
121         crit.addEqualTo(OLEPropertyConstants.OBJECT_CODE, t.getFinancialObjectCode());
122         crit.addEqualTo(OLEPropertyConstants.SUB_OBJECT_CODE, t.getFinancialSubObjectCode());
123         crit.addEqualTo(OLEPropertyConstants.BALANCE_TYPE_CODE, t.getFinancialBalanceTypeCode());
124         crit.addEqualTo(OLEPropertyConstants.OBJECT_TYPE_CODE, t.getFinancialObjectTypeCode());
125 
126         QueryByCriteria qbc = QueryFactory.newQuery(Balance.class, crit);
127         return (Balance) getPersistenceBrokerTemplate().getObjectByQuery(qbc);
128     }
129 
130     /**
131      * This method adds to the given criteria if the given collection is non-empty. It uses an EQUALS if there is exactly one
132      * element in the collection; otherwise, its uses an IN
133      * 
134      * @param criteria - the criteria that might have a criterion appended
135      * @param name - name of the attribute
136      * @param collection - the collection to inspect
137      */
138     protected void criteriaBuilder(Criteria criteria, String name, Collection collection) {
139         criteriaBuilderHelper(criteria, name, collection, false);
140     }
141 
142     /**
143      * Similar to criteriaBuilder, this adds a negative criterion (NOT EQUALS, NOT IN)
144      * 
145      * @param criteria - the criteria that might have a criterion appended
146      * @param name - name of the attribute
147      * @param collection - the collection to inspect
148      */
149     protected void negatedCriteriaBuilder(Criteria criteria, String name, Collection collection) {
150         criteriaBuilderHelper(criteria, name, collection, true);
151     }
152 
153 
154     /**
155      * This method provides the implementation for the conveniences methods criteriaBuilder & negatedCriteriaBuilder
156      * 
157      * @param criteria - the criteria that might have a criterion appended
158      * @param name - name of the attribute
159      * @param collection - the collection to inspect
160      * @param negate - the criterion will be negated (NOT EQUALS, NOT IN) when this is true
161      */
162     protected void criteriaBuilderHelper(Criteria criteria, String name, Collection collection, boolean negate) {
163         if (collection != null) {
164             int size = collection.size();
165             if (size == 1) {
166                 if (negate) {
167                     criteria.addNotEqualTo(name, collection.iterator().next());
168                 }
169                 else {
170                     criteria.addEqualTo(name, collection.iterator().next());
171                 }
172             }
173             if (size > 1) {
174                 if (negate) {
175                     criteria.addNotIn(name, collection);
176                 }
177                 else {
178                     criteria.addIn(name, collection);
179 
180                 }
181             }
182         }
183 
184     }
185 
186     /**
187      * Build a query based on all the parameters, and return an Iterator of all Balances from the database that qualify
188      * 
189      * @param account the account of balances to find
190      * @param fiscalYear the fiscal year of balances to find
191      * @param includedObjectCodes a Collection of object codes found balances should have one of
192      * @param excludedObjectCodes a Collection of object codes found balances should not have one of
193      * @param objectTypeCodes a Collection of object type codes found balances should have one of
194      * @param balanceTypeCodes a Collection of balance type codes found balances should have one of
195      * @return an Iterator of Balances
196      * @see org.kuali.ole.gl.dataaccess.BalanceDao#findBalances(org.kuali.ole.coa.businessobject.Account, java.lang.Integer,
197      *      java.util.Collection, java.util.Collection, java.util.Collection, java.util.Collection)
198      */
199     public Iterator<Balance> findBalances(Account account, Integer fiscalYear, Collection includedObjectCodes, Collection excludedObjectCodes, Collection objectTypeCodes, Collection balanceTypeCodes) {
200         LOG.debug("findBalances() started");
201 
202         Criteria criteria = new Criteria();
203 
204         criteria.addEqualTo(OLEPropertyConstants.ACCOUNT_NUMBER, account.getAccountNumber());
205         criteria.addEqualTo(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, account.getChartOfAccountsCode());
206 
207         criteria.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, fiscalYear);
208 
209         criteriaBuilder(criteria, GeneralLedgerConstants.ColumnNames.OBJECT_TYPE_CODE, objectTypeCodes);
210         criteriaBuilder(criteria, GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE, balanceTypeCodes);
211         criteriaBuilder(criteria, GeneralLedgerConstants.ColumnNames.OBJECT_CODE, includedObjectCodes);
212         negatedCriteriaBuilder(criteria, GeneralLedgerConstants.ColumnNames.OBJECT_CODE, excludedObjectCodes);
213 
214         ReportQueryByCriteria query = new ReportQueryByCriteria(Balance.class, criteria);
215 
216         // returns an iterator of all matching balances
217         Iterator balances = getPersistenceBrokerTemplate().getIteratorByQuery(query);
218         return balances;
219     }
220 
221     /**
222      * Using the given fieldValues as keys, return all cash balance records. The results will be limited to the system lookup
223      * results limit.
224      * 
225      * @param fieldValues the input fields and values
226      * @param isConsolidated consolidation option is applied or not
227      * @return the records of cash balance entries
228      * @see org.kuali.ole.gl.dataaccess.BalanceDao#lookupCashBalance(Map, boolean, List)
229      */
230     public Iterator<Balance> lookupCashBalance(Map fieldValues, boolean isConsolidated, Collection<String> encumbranceBalanceTypes) {
231         LOG.debug("findCashBalance() started");
232 
233         Query query = this.getCashBalanceQuery(fieldValues, isConsolidated, encumbranceBalanceTypes);
234         OJBUtility.limitResultSize(query);
235         return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query);
236     }
237 
238     /**
239      * Get the number of detailed cash balance records that would be returned, were we to do a query based on the given fieldValues
240      * 
241      * @param fieldValues the input fields and values
242      * @param isConsolidated consolidation option is applied or not
243      * @return the size collection of cash balance entry groups
244      * @see org.kuali.ole.gl.dataaccess.BalanceDao#getDetailedCashBalanceRecordCount(Map, List)
245      */
246     public Integer getDetailedCashBalanceRecordCount(Map fieldValues, Collection<String> encumbranceBalanceTypes) {
247         LOG.debug("getDetailedCashBalanceRecordCount() started");
248 
249         Query query = this.getCashBalanceQuery(fieldValues, false, encumbranceBalanceTypes);
250         return getPersistenceBrokerTemplate().getCount(query);
251     }
252 
253     /**
254      * Given a map of keys, return all of the report data about qualifying cash balances
255      * 
256      * @param fieldValues the input fields and values
257      * @return the size collection of cash balance entry groups
258      * @see org.kuali.ole.gl.dataaccess.BalanceDao#getConsolidatedCashBalanceRecordCount(Map, List)
259      */
260     public int getConsolidatedCashBalanceRecordCount(Map fieldValues, Collection<String> encumbranceBalanceTypes) {
261         LOG.debug("getCashBalanceRecordCount() started");
262 
263         ReportQueryByCriteria query = this.getCashBalanceCountQuery(fieldValues, encumbranceBalanceTypes);
264         return getPersistenceBrokerTemplate().getCount(query);
265     }
266 
267     /**
268      * Given a map of values, build a query out of those and find all the balances that qualify
269      * 
270      * @param fieldValues a Map of fieldValues to use as keys in the query
271      * @param isConsolidated should the results be consolidated?
272      * @return an Iterator of Balances
273      * @see org.kuali.ole.gl.dataaccess.BalanceDao#findBalance(java.util.Map, boolean)
274      */
275     public Iterator<Balance> findBalance(Map fieldValues, boolean isConsolidated, Collection<String> encumbranceBalanceTypes) {
276         LOG.debug("findBalance() started");
277 
278         Query query = this.getBalanceQuery(fieldValues, isConsolidated, encumbranceBalanceTypes);
279         OJBUtility.limitResultSize(query);
280 
281         if (isConsolidated) {
282             return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query);
283         }
284         return getPersistenceBrokerTemplate().getIteratorByQuery(query);
285     }
286 
287     /**
288      * Given a Map of keys to use as a query, if we performed that query as a consolidated query... how many records would we get
289      * back?
290      * 
291      * @param fieldValues a Map of values to use as keys to build the query
292      * @return an Iterator of counts...
293      * @see org.kuali.ole.gl.dataaccess.BalanceDao#getConsolidatedBalanceRecordCount(Map, List)
294      */
295     public Iterator getConsolidatedBalanceRecordCount(Map fieldValues, Collection<String> encumbranceBalanceTypes) {
296         LOG.debug("getBalanceRecordCount() started");
297 
298         ReportQueryByCriteria query = this.getBalanceCountQuery(fieldValues, encumbranceBalanceTypes);
299         return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query);
300     }
301 
302     /**
303      * Builds a query for cash balances, based on the given field values
304      * 
305      * @param fieldValues a map of keys to use when building the query
306      * @return an OJB ReportQuery to use as the query
307      */
308     protected ReportQueryByCriteria getCashBalanceCountQuery(Map fieldValues, Collection<String> encumbranceBalanceTypes) {
309         Criteria criteria = buildCriteriaFromMap(fieldValues, new CashBalance(), encumbranceBalanceTypes);
310         criteria.addEqualTo(OLEPropertyConstants.BALANCE_TYPE_CODE, OLEConstants.BALANCE_TYPE_ACTUAL);
311         criteria.addEqualToField("chart.financialCashObjectCode", OLEPropertyConstants.OBJECT_CODE);
312 
313         ReportQueryByCriteria query = QueryFactory.newReportQuery(CashBalance.class, criteria);
314 
315         List groupByList = buildGroupByList();
316         groupByList.remove(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
317         groupByList.remove(OLEPropertyConstants.SUB_OBJECT_CODE);
318         groupByList.remove(OLEPropertyConstants.OBJECT_TYPE_CODE);
319 
320         // add the group criteria into the selection statement
321         String[] groupBy = (String[]) groupByList.toArray(new String[groupByList.size()]);
322         query.addGroupBy(groupBy);
323 
324         return query;
325     }
326 
327     /**
328      * build the query for cash balance search
329      * 
330      * @param fieldValues Map of keys to use for the query
331      * @param isConsolidated should the results be consolidated?
332      * @return the OJB query to perform
333      */
334     protected Query getCashBalanceQuery(Map fieldValues, boolean isConsolidated, Collection<String> encumbranceBalanceTypes) {
335         Criteria criteria = buildCriteriaFromMap(fieldValues, new CashBalance(), encumbranceBalanceTypes);
336         criteria.addEqualTo(OLEPropertyConstants.BALANCE_TYPE_CODE, OLEConstants.BALANCE_TYPE_ACTUAL);
337         criteria.addEqualToField("chart.financialCashObjectCode", OLEPropertyConstants.OBJECT_CODE);
338 
339         ReportQueryByCriteria query = QueryFactory.newReportQuery(CashBalance.class, criteria);
340         List attributeList = buildAttributeList(false);
341         List groupByList = buildGroupByList();
342 
343         // if consolidated, then ignore the following fields
344         if (isConsolidated) {
345             attributeList.remove(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
346             groupByList.remove(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
347             attributeList.remove(OLEPropertyConstants.SUB_OBJECT_CODE);
348             groupByList.remove(OLEPropertyConstants.SUB_OBJECT_CODE);
349             attributeList.remove(OLEPropertyConstants.OBJECT_TYPE_CODE);
350             groupByList.remove(OLEPropertyConstants.OBJECT_TYPE_CODE);
351         }
352 
353         // add the group criteria into the selection statement
354         String[] groupBy = (String[]) groupByList.toArray(new String[groupByList.size()]);
355         query.addGroupBy(groupBy);
356 
357         // set the selection attributes
358         String[] attributes = (String[]) attributeList.toArray(new String[attributeList.size()]);
359         query.setAttributes(attributes);
360 
361         return query;
362     }
363 
364     /**
365      * build the query for balance search
366      * 
367      * @param fieldValues Map of keys to use for the query
368      * @param isConsolidated should the results be consolidated?
369      * @return an OJB query to perform
370      */
371     protected Query getBalanceQuery(Map fieldValues, boolean isConsolidated, Collection<String> encumbranceBalanceTypes) {
372         LOG.debug("getBalanceQuery(Map, boolean) started");
373 
374         Criteria criteria = buildCriteriaFromMap(fieldValues, new Balance(), encumbranceBalanceTypes);
375         ReportQueryByCriteria query = QueryFactory.newReportQuery(Balance.class, criteria);
376 
377         // if consolidated, then ignore subaccount number and balance type code
378         if (isConsolidated) {
379             List attributeList = buildAttributeList(true);
380             List groupByList = buildGroupByList();
381 
382             // ignore subaccount number, sub object code and object type code
383             attributeList.remove(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
384             groupByList.remove(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
385             attributeList.remove(OLEPropertyConstants.SUB_OBJECT_CODE);
386             groupByList.remove(OLEPropertyConstants.SUB_OBJECT_CODE);
387             attributeList.remove(OLEPropertyConstants.OBJECT_TYPE_CODE);
388             groupByList.remove(OLEPropertyConstants.OBJECT_TYPE_CODE);
389 
390             // set the selection attributes
391             String[] attributes = (String[]) attributeList.toArray(new String[attributeList.size()]);
392             query.setAttributes(attributes);
393 
394             // add the group criteria into the selection statement
395             String[] groupBy = (String[]) groupByList.toArray(new String[groupByList.size()]);
396             query.addGroupBy(groupBy);
397         }
398 
399         return query;
400     }
401 
402     /**
403      * build the query for balance search
404      * 
405      * @param fieldValues Map of keys to use for the query
406      * @return an OJB ReportQuery to perform
407      */
408     protected ReportQueryByCriteria getBalanceCountQuery(Map fieldValues, Collection<String> encumbranceBalanceTypes) {
409         Criteria criteria = buildCriteriaFromMap(fieldValues, new Balance(), encumbranceBalanceTypes);
410         ReportQueryByCriteria query = QueryFactory.newReportQuery(Balance.class, criteria);
411 
412         // set the selection attributes
413         query.setAttributes(new String[] { "count(*)" });
414 
415         List groupByList = buildGroupByList();
416         groupByList.remove(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
417         groupByList.remove(OLEPropertyConstants.SUB_OBJECT_CODE);
418         groupByList.remove(OLEPropertyConstants.OBJECT_TYPE_CODE);
419 
420         // add the group criteria into the selection statement
421         String[] groupBy = (String[]) groupByList.toArray(new String[groupByList.size()]);
422         query.addGroupBy(groupBy);
423         return query;
424     }
425 
426     /**
427      * This method builds the query criteria based on the input field map
428      * 
429      * @param fieldValues Map of keys to use for the query
430      * @param balance this really usen't used in the method
431      * @return a query criteria
432      */
433     protected Criteria buildCriteriaFromMap(Map fieldValues, Balance balance, Collection<String> encumbranceBalanceTypes) {
434         Map localFieldValues = new HashMap();
435         localFieldValues.putAll(fieldValues);
436 
437         Criteria criteria = new Criteria();
438 
439         // handle encumbrance balance type
440         String propertyName = OLEPropertyConstants.BALANCE_TYPE_CODE;
441         if (localFieldValues.containsKey(propertyName)) {
442             String propertyValue = (String) localFieldValues.get(propertyName);
443             if (OLEConstants.AGGREGATE_ENCUMBRANCE_BALANCE_TYPE_CODE.equals(propertyValue)) {
444                 localFieldValues.remove(OLEPropertyConstants.BALANCE_TYPE_CODE);
445 
446                 criteria.addIn(OLEPropertyConstants.BALANCE_TYPE_CODE, encumbranceBalanceTypes);
447             }
448         }
449 
450         criteria.addAndCriteria(OJBUtility.buildCriteriaFromMap(localFieldValues, balance));
451         return criteria;
452     }
453 
454     /**
455      * This method builds the atrribute list used by balance searching
456      * 
457      * @param isExtended should we add the attributes to sum each of the monthly totals?
458      * @return List an attribute list
459      */
460     protected List<String> buildAttributeList(boolean isExtended) {
461         List attributeList = this.buildGroupByList();
462 
463         attributeList.add("sum(accountLineAnnualBalanceAmount)");
464         attributeList.add("sum(beginningBalanceLineAmount)");
465         attributeList.add("sum(contractsGrantsBeginningBalanceAmount)");
466 
467         // add the entended elements into the list
468         if (isExtended) {
469             attributeList.add("sum(month1Amount)");
470             attributeList.add("sum(month2Amount)");
471             attributeList.add("sum(month3Amount)");
472             attributeList.add("sum(month4Amount)");
473             attributeList.add("sum(month5Amount)");
474             attributeList.add("sum(month6Amount)");
475             attributeList.add("sum(month7Amount)");
476             attributeList.add("sum(month8Amount)");
477             attributeList.add("sum(month9Amount)");
478             attributeList.add("sum(month10Amount)");
479             attributeList.add("sum(month11Amount)");
480             attributeList.add("sum(month12Amount)");
481             attributeList.add("sum(month13Amount)");
482         }
483         return attributeList;
484     }
485 
486     /**
487      * This method builds group by attribute list used by balance searching
488      * 
489      * @return List an group by attribute list
490      */
491     protected List<String> buildGroupByList() {
492         List attributeList = new ArrayList();
493 
494         attributeList.add(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR);
495         attributeList.add(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE);
496         attributeList.add(OLEPropertyConstants.ACCOUNT_NUMBER);
497         attributeList.add(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
498         attributeList.add(OLEPropertyConstants.BALANCE_TYPE_CODE);
499         attributeList.add(OLEPropertyConstants.OBJECT_CODE);
500         attributeList.add(OLEPropertyConstants.SUB_OBJECT_CODE);
501         attributeList.add(OLEPropertyConstants.OBJECT_TYPE_CODE);
502 
503         return attributeList;
504     }
505 
506     /**
507      * Since SubAccountNumber, SubObjectCode, and ObjectType are all part of the primary key of Balance, you're guaranteed to get
508      * one of those records when you call this method. Let's hope the right one.
509      * 
510      * @param universityFiscalYear the fiscal year of the CB balance to return
511      * @param chartOfAccountsCode the chart of the accounts code of the CB balanes to return
512      * @param accountNumber the account number of the CB balance to return
513      * @param objectCode the object code of the CB balance to return
514      * @return the CB Balance record
515      * @see org.kuali.ole.gl.dataaccess.BalanceDao#getCurrentBudgetForObjectCode(java.lang.Integer, java.lang.String,
516      *      java.lang.String, java.lang.String)
517      */
518     public Balance getCurrentBudgetForObjectCode(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String objectCode) {
519         LOG.debug("getCurrentBudgetForObjectCode() started");
520 
521         Criteria crit = new Criteria();
522         crit.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear);
523         crit.addEqualTo(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode);
524         crit.addEqualTo(OLEPropertyConstants.ACCOUNT_NUMBER, accountNumber);
525         crit.addEqualTo(OLEPropertyConstants.OBJECT_CODE, objectCode);
526         crit.addEqualTo(OLEPropertyConstants.BALANCE_TYPE_CODE, OLEConstants.BALANCE_TYPE_CURRENT_BUDGET);
527 
528         QueryByCriteria qbc = QueryFactory.newQuery(Balance.class, crit);
529         return (Balance) getPersistenceBrokerTemplate().getObjectByQuery(qbc);
530     }
531 
532     /**
533      * Find all matching account balances.
534      * 
535      * @param universityFiscalYear the university fiscal year of balances to return
536      * @param chartOfAccountsCode the chart of accounts code of balances to return
537      * @param accountNumber the account number of balances to return
538      * @return balances sorted by object code
539      */
540     public Iterator<Balance> findAccountBalances(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber) {
541         LOG.debug("findAccountBalances() started");
542         return this.findAccountBalances(universityFiscalYear, chartOfAccountsCode, accountNumber, OLEConstants.SF_TYPE_OBJECT);
543     }
544 
545     /**
546      * Find all matching account balances. The Sufficient funds code is used to determine the sort of the results.
547      * 
548      * @param universityFiscalYear the university fiscal year of balances to return
549      * @param chartOfAccountsCode the chart of accounts code of balances to return
550      * @param accountNumber the account number of balances to return
551      * @param sfCode the sufficient funds code, used to sort on
552      * @return an Iterator of balances
553      */
554     public Iterator<Balance> findAccountBalances(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String sfCode) {
555         LOG.debug("findAccountBalances() started");
556 
557         Criteria crit = new Criteria();
558         crit.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear);
559         crit.addEqualTo(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode);
560         crit.addEqualTo(OLEPropertyConstants.ACCOUNT_NUMBER, accountNumber);
561 
562         QueryByCriteria qbc = QueryFactory.newQuery(Balance.class, crit);
563         if (OLEConstants.SF_TYPE_OBJECT.equals(sfCode)) {
564             qbc.addOrderByAscending(OLEPropertyConstants.OBJECT_CODE);
565         }
566         else if (OLEConstants.SF_TYPE_LEVEL.equals(sfCode)) {
567             qbc.addOrderByAscending(GeneralLedgerConstants.BalanceInquiryDrillDowns.OBJECT_LEVEL_CODE);
568         }
569         else if (OLEConstants.SF_TYPE_CONSOLIDATION.equals(sfCode)) {
570             qbc.addOrderByAscending(GeneralLedgerConstants.BalanceInquiryDrillDowns.CONSOLIDATION_OBJECT_CODE);
571         }
572         return getPersistenceBrokerTemplate().getIteratorByQuery(qbc);
573     }
574 
575     /**
576      * Purge the sufficient funds balance table by year/chart
577      * 
578      * @param chart the chart of balances to purge
579      * @param year the university fiscal year of balances to purge
580      */
581     public void purgeYearByChart(String chartOfAccountsCode, int year) {
582         LOG.debug("purgeYearByChart() started");
583 
584         Criteria criteria = new Criteria();
585         criteria.addEqualTo(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode);
586         criteria.addLessThan(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, new Integer(year));
587 
588         getPersistenceBrokerTemplate().deleteByQuery(new QueryByCriteria(Balance.class, criteria));
589 
590         // This is required because if any deleted account balances are in the cache, deleteByQuery doesn't
591         // remove them from the cache so a future select will retrieve these deleted account balances from
592         // the cache and return them. Clearing the cache forces OJB to go to the database again.
593         getPersistenceBrokerTemplate().clearCache();
594     }
595 
596     /**
597      * Returns the count of balances for a given fiscal year; this method is used for year end job reporting
598      * 
599      * @param year the university fiscal year to count balances for
600      * @return an int with the count of balances for that fiscal year
601      * @see org.kuali.ole.gl.dataaccess.BalanceDao#countBalancesForFiscalYear(java.lang.Integer)
602      */
603     public int countBalancesForFiscalYear(Integer year) {
604         LOG.debug("countBalancesForFiscalYear() started");
605 
606         Criteria c = new Criteria();
607         c.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
608         QueryByCriteria query = QueryFactory.newQuery(Balance.class, c);
609 
610         return getPersistenceBrokerTemplate().getCount(query);
611     }
612 
613     /**
614      * Finds all of the balances for the fiscal year that should be processed by nominal activity closing
615      * 
616      * @param year the university fiscal year of balances to find
617      * @return an Iterator of Balances to process
618      * @see org.kuali.ole.gl.dataaccess.BalanceDao#findNominalActivityBalancesForFiscalYear(Integer, List, SystemOptions)
619      */
620     public Iterator<Balance> findNominalActivityBalancesForFiscalYear(Integer year, Collection<String> nominalActivityObjectTypeCodes, SystemOptions currentYearOptions) {
621         LOG.debug("findNominalActivityBalancesForFiscalYear() started");
622 
623         Criteria c = new Criteria();
624         c.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
625         c.addEqualTo(OLEPropertyConstants.BALANCE_TYPE_CODE, currentYearOptions.getActualFinancialBalanceTypeCd());
626         c.addIn(OLEPropertyConstants.OBJECT_TYPE_CODE, nominalActivityObjectTypeCodes);
627         c.addNotEqualTo("accountLineAnnualBalanceAmount", KualiDecimal.ZERO);
628 
629         QueryByCriteria query = QueryFactory.newQuery(Balance.class, c);
630         query.addOrderByAscending(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE);
631         query.addOrderByAscending(OLEPropertyConstants.ACCOUNT_NUMBER);
632         query.addOrderByAscending(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
633         query.addOrderByAscending(OLEPropertyConstants.OBJECT_CODE);
634         query.addOrderByAscending(OLEPropertyConstants.SUB_OBJECT_CODE);
635         query.addOrderByAscending(OLEPropertyConstants.BALANCE_TYPE_CODE);
636         query.addOrderByAscending(OLEPropertyConstants.OBJECT_TYPE_CODE);
637 
638         return getPersistenceBrokerTemplate().getIteratorByQuery(query);
639     }
640 
641     /**
642      * @see org.kuali.ole.gl.dataaccess.BalanceDao#findGeneralBalancesToForwardForFiscalYear(java.lang.Integer, java.util.List,
643      *      java.lang.String[])
644      */
645     public Iterator<Balance> findGeneralBalancesToForwardForFiscalYear(Integer year, Collection<String> generalForwardBalanceObjectTypes, Collection<String> generalBalanceForwardBalanceTypes) {
646 
647         Criteria c = new Criteria();
648         c.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
649         c.addIn(OLEPropertyConstants.BALANCE_TYPE_CODE, generalBalanceForwardBalanceTypes);
650         c.addIn(OLEPropertyConstants.OBJECT_TYPE_CODE, generalForwardBalanceObjectTypes);
651 
652         QueryByCriteria query = QueryFactory.newQuery(Balance.class, c);
653         query.addOrderByAscending(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE);
654         query.addOrderByAscending(OLEPropertyConstants.ACCOUNT_NUMBER);
655         query.addOrderByAscending(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
656         query.addOrderByAscending(OLEPropertyConstants.OBJECT_CODE);
657         query.addOrderByAscending(OLEPropertyConstants.SUB_OBJECT_CODE);
658         query.addOrderByAscending(OLEPropertyConstants.BALANCE_TYPE_CODE);
659         query.addOrderByAscending(OLEPropertyConstants.OBJECT_TYPE_CODE);
660 
661         Iterator<Balance> balances = getPersistenceBrokerTemplate().getIteratorByQuery(query);
662 
663         return balances;
664     }
665 
666     /**
667      * @see org.kuali.ole.gl.dataaccess.BalanceDao#findCumulativeBalancesToForwardForFiscalYear(java.lang.Integer, java.util.List,
668      *      java.util.List, java.lang.String[], java.lang.String[])
669      */
670     public Iterator<Balance> findCumulativeBalancesToForwardForFiscalYear(Integer year, Collection<String> cumulativeForwardBalanceObjectTypes, Collection<String> contractsAndGrantsDenotingValues, Collection<String> subFundGroupsForCumulativeBalanceForwarding, Collection<String> cumulativeBalanceForwardBalanceTypes, boolean fundGroupDenotesCGInd) {
671         Criteria c = new Criteria();
672         c.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
673         c.addIn(OLEPropertyConstants.BALANCE_TYPE_CODE, cumulativeBalanceForwardBalanceTypes);
674         c.addIn(OLEPropertyConstants.OBJECT_TYPE_CODE, cumulativeForwardBalanceObjectTypes);
675 
676         Criteria forCGCrit = new Criteria();
677         if (fundGroupDenotesCGInd) {
678             for (String value : contractsAndGrantsDenotingValues) {
679                 forCGCrit.addEqualTo("priorYearAccount.subFundGroup.fundGroupCode", value);
680             }
681         }
682         else {
683             for (String value : contractsAndGrantsDenotingValues) {
684                 forCGCrit.addEqualTo("priorYearAccount.subFundGroupCode", value);
685             }
686         }
687 
688         Criteria subFundGroupCrit = new Criteria();
689         subFundGroupCrit.addIn("priorYearAccount.subFundGroupCode", subFundGroupsForCumulativeBalanceForwarding);
690         forCGCrit.addOrCriteria(subFundGroupCrit);
691         c.addAndCriteria(forCGCrit);
692 
693         QueryByCriteria query = QueryFactory.newQuery(Balance.class, c);
694         query.addOrderByAscending(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE);
695         query.addOrderByAscending(OLEPropertyConstants.ACCOUNT_NUMBER);
696         query.addOrderByAscending(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
697         query.addOrderByAscending(OLEPropertyConstants.OBJECT_CODE);
698         query.addOrderByAscending(OLEPropertyConstants.SUB_OBJECT_CODE);
699         query.addOrderByAscending(OLEPropertyConstants.BALANCE_TYPE_CODE);
700         query.addOrderByAscending(OLEPropertyConstants.OBJECT_TYPE_CODE);
701 
702         Iterator<Balance> balances = getPersistenceBrokerTemplate().getIteratorByQuery(query);
703 
704         return balances;
705     }
706 
707     /**
708      * Returns a list of balances to return for the Organization Reversion year end job to process
709      * 
710      * @param the university fiscal year to find balances for
711      * @param endOfYear if true, use current year accounts, otherwise use prior year accounts
712      * @return an Iterator of Balances to process
713      * @see org.kuali.ole.gl.dataaccess.BalanceDao#findOrganizationReversionBalancesForFiscalYear(Integer, boolean, SystemOptions)
714      */
715     public Iterator<Balance> findOrganizationReversionBalancesForFiscalYear(Integer year, boolean endOfYear, SystemOptions options, List<ParameterEvaluator> parameterEvaluators) {
716         LOG.debug("findOrganizationReversionBalancesForFiscalYear() started");
717         Criteria c = new Criteria();
718         c.addEqualTo(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
719 
720         for (ParameterEvaluator parameterEvaluator : parameterEvaluators) {
721 
722             String currentRule = parameterEvaluator.getValue();
723             if (endOfYear) {
724                 currentRule = currentRule.replaceAll("account\\.", "priorYearAccount.");
725             }
726             if (StringUtils.isNotBlank(currentRule)) {
727                 String propertyName = StringUtils.substringBefore(currentRule, "=");
728                 List<String> ruleValues = Arrays.asList(StringUtils.substringAfter(currentRule, "=").split(";"));
729                 if (propertyName != null && propertyName.length() > 0 && ruleValues.size() > 0 && !StringUtils.isBlank(ruleValues.get(0))) {
730                     if (parameterEvaluator.constraintIsAllow()) {
731                         c.addIn(propertyName, ruleValues);
732                     }
733                     else {
734                         c.addNotIn(propertyName, ruleValues);
735                     }
736                 }
737             }
738         }
739         // we only ever calculate on CB, AC, and encumbrance types, so let's only select those
740         List organizationReversionBalancesToSelect = new ArrayList();
741         organizationReversionBalancesToSelect.add(options.getActualFinancialBalanceTypeCd());
742         organizationReversionBalancesToSelect.add(options.getFinObjTypeExpenditureexpCd());
743         organizationReversionBalancesToSelect.add(options.getCostShareEncumbranceBalanceTypeCd());
744         organizationReversionBalancesToSelect.add(options.getIntrnlEncumFinBalanceTypCd());
745         organizationReversionBalancesToSelect.add(OLEConstants.BALANCE_TYPE_CURRENT_BUDGET);
746         c.addIn(OLEPropertyConstants.BALANCE_TYPE_CODE, organizationReversionBalancesToSelect);
747         QueryByCriteria query = QueryFactory.newQuery(Balance.class, c);
748         query.addOrderByAscending(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE);
749         query.addOrderByAscending(OLEPropertyConstants.ACCOUNT_NUMBER);
750         query.addOrderByAscending(OLEPropertyConstants.SUB_ACCOUNT_NUMBER);
751         query.addOrderByAscending(OLEPropertyConstants.OBJECT_CODE);
752         query.addOrderByAscending(OLEPropertyConstants.SUB_OBJECT_CODE);
753         query.addOrderByAscending(OLEPropertyConstants.BALANCE_TYPE_CODE);
754         query.addOrderByAscending(OLEPropertyConstants.OBJECT_TYPE_CODE);
755 
756         return getPersistenceBrokerTemplate().getIteratorByQuery(query);
757     }
758 
759     /**
760      * @see org.kuali.ole.gl.dataaccess.BalancingDao#findCountGreaterOrEqualThan(java.lang.Integer)
761      */
762     public Integer findCountGreaterOrEqualThan(Integer year) {
763         Criteria criteria = new Criteria();
764         criteria.addGreaterOrEqualThan(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
765 
766         ReportQueryByCriteria query = QueryFactory.newReportQuery(Balance.class, criteria);
767 
768         return getPersistenceBrokerTemplate().getCount(query);
769     }
770 
771 }