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.dataaccess.impl; 017 018 import java.util.ArrayList; 019 import java.util.Arrays; 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 import java.util.TreeMap; 026 027 import org.apache.commons.lang.StringUtils; 028 import org.apache.ojb.broker.query.Criteria; 029 import org.apache.ojb.broker.query.Query; 030 import org.apache.ojb.broker.query.QueryByCriteria; 031 import org.apache.ojb.broker.query.QueryFactory; 032 import org.apache.ojb.broker.query.ReportQueryByCriteria; 033 import org.kuali.kfs.coa.businessobject.Account; 034 import org.kuali.kfs.coa.businessobject.OrganizationReversion; 035 import org.kuali.kfs.coa.service.BalanceTypeService; 036 import org.kuali.kfs.coa.service.ObjectTypeService; 037 import org.kuali.kfs.coa.service.SubFundGroupService; 038 import org.kuali.kfs.gl.GeneralLedgerConstants; 039 import org.kuali.kfs.gl.OJBUtility; 040 import org.kuali.kfs.gl.batch.BalanceForwardStep; 041 import org.kuali.kfs.gl.batch.service.FilteringBalanceIterator; 042 import org.kuali.kfs.gl.businessobject.Balance; 043 import org.kuali.kfs.gl.businessobject.CashBalance; 044 import org.kuali.kfs.gl.businessobject.SufficientFundBalances; 045 import org.kuali.kfs.gl.businessobject.Transaction; 046 import org.kuali.kfs.gl.dataaccess.BalanceDao; 047 import org.kuali.kfs.gl.dataaccess.LedgerBalanceBalancingDao; 048 import org.kuali.kfs.sys.KFSConstants; 049 import org.kuali.kfs.sys.KFSPropertyConstants; 050 import org.kuali.kfs.sys.businessobject.SystemOptions; 051 import org.kuali.kfs.sys.context.SpringContext; 052 import org.kuali.kfs.sys.service.OptionsService; 053 import org.kuali.rice.kns.dao.impl.PlatformAwareDaoBaseOjb; 054 import org.kuali.rice.kns.service.ParameterEvaluator; 055 import org.kuali.rice.kns.service.ParameterService; 056 import org.kuali.rice.kns.util.KualiDecimal; 057 058 /** 059 * An OJB implementation of BalanceDao 060 */ 061 public class BalanceDaoOjb extends PlatformAwareDaoBaseOjb implements BalanceDao, LedgerBalanceBalancingDao { 062 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BalanceDaoOjb.class); 063 private ParameterService parameterService; 064 private OptionsService optionsService; 065 private BalanceTypeService balanceTypService; 066 067 /** 068 * Does a ReportQuery to summarize GL balance data 069 * 070 * @param universityFiscalYear the fiscal year of balances to search for 071 * @param balanceTypeCodes a list of balance type codes of balances to search for 072 * @return iterator of reported on java.lang.Object arrays with the report data 073 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#getGlSummary(int, java.util.List) 074 */ 075 public Iterator<Object[]> getGlSummary(int universityFiscalYear, List<String> balanceTypeCodes) { 076 LOG.debug("getGlSummary() started"); 077 078 Criteria c = new Criteria(); 079 c.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear); 080 c.addIn(KFSPropertyConstants.BALANCE_TYPE_CODE, balanceTypeCodes); 081 082 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)" }; 083 084 String[] groupby = new String[] { "account.subFundGroup.fundGroupCode" }; 085 086 ReportQueryByCriteria query = new ReportQueryByCriteria(Balance.class, c); 087 088 query.setAttributes(attributes); 089 query.addGroupBy(groupby); 090 query.addOrderByAscending("account.subFundGroup.fundGroupCode"); 091 092 return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 093 } 094 095 /** 096 * Queries the database for all the balances for a given fiscal year 097 * 098 * @param year the university fiscal year of balances to return 099 * @return an iterator over all balances for a given fiscal year 100 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#findBalancesForFiscalYear(java.lang.Integer) 101 */ 102 public Iterator<Balance> findBalancesForFiscalYear(Integer year) { 103 LOG.debug("findBalancesForFiscalYear() started"); 104 105 Criteria c = new Criteria(); 106 c.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, year); 107 108 QueryByCriteria query = QueryFactory.newQuery(Balance.class, c); 109 query.addOrderByAscending(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE); 110 query.addOrderByAscending(KFSPropertyConstants.ACCOUNT_NUMBER); 111 query.addOrderByAscending(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 112 query.addOrderByAscending(KFSPropertyConstants.OBJECT_CODE); 113 query.addOrderByAscending(KFSPropertyConstants.SUB_OBJECT_CODE); 114 query.addOrderByAscending(KFSPropertyConstants.BALANCE_TYPE_CODE); 115 query.addOrderByAscending(KFSPropertyConstants.OBJECT_TYPE_CODE); 116 117 return getPersistenceBrokerTemplate().getIteratorByQuery(query); 118 } 119 120 /** 121 * Saves a balance 122 * @param b a balance to save 123 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#save(org.kuali.kfs.gl.businessobject.Balance) 124 */ 125 public void save(Balance b) { 126 LOG.debug("save() started"); 127 128 getPersistenceBrokerTemplate().store(b); 129 } 130 131 /** 132 * Using values from the transaction as keys, lookup the balance the transaction would affect were it posted 133 * 134 * @t a transaction to look up the related balance for 135 * @return a Balance that the given transaction would affect 136 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#getBalanceByTransaction(org.kuali.kfs.gl.businessobject.Transaction) 137 */ 138 public Balance getBalanceByTransaction(Transaction t) { 139 LOG.debug("getBalanceByTransaction() started"); 140 141 Criteria crit = new Criteria(); 142 crit.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, t.getUniversityFiscalYear()); 143 crit.addEqualTo(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, t.getChartOfAccountsCode()); 144 crit.addEqualTo(KFSPropertyConstants.ACCOUNT_NUMBER, t.getAccountNumber()); 145 crit.addEqualTo(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, t.getSubAccountNumber()); 146 crit.addEqualTo(KFSPropertyConstants.OBJECT_CODE, t.getFinancialObjectCode()); 147 crit.addEqualTo(KFSPropertyConstants.SUB_OBJECT_CODE, t.getFinancialSubObjectCode()); 148 crit.addEqualTo(KFSPropertyConstants.BALANCE_TYPE_CODE, t.getFinancialBalanceTypeCode()); 149 crit.addEqualTo(KFSPropertyConstants.OBJECT_TYPE_CODE, t.getFinancialObjectTypeCode()); 150 151 QueryByCriteria qbc = QueryFactory.newQuery(Balance.class, crit); 152 return (Balance) getPersistenceBrokerTemplate().getObjectByQuery(qbc); 153 } 154 155 /** 156 * This method adds to the given criteria if the given collection is non-empty. It uses an EQUALS if there is exactly one 157 * element in the collection; otherwise, its uses an IN 158 * 159 * @param criteria - the criteria that might have a criterion appended 160 * @param name - name of the attribute 161 * @param collection - the collection to inspect 162 */ 163 protected void criteriaBuilder(Criteria criteria, String name, Collection collection) { 164 criteriaBuilderHelper(criteria, name, collection, false); 165 } 166 167 /** 168 * Similar to criteriaBuilder, this adds a negative criterion (NOT EQUALS, NOT IN) 169 * 170 * @param criteria - the criteria that might have a criterion appended 171 * @param name - name of the attribute 172 * @param collection - the collection to inspect 173 */ 174 protected void negatedCriteriaBuilder(Criteria criteria, String name, Collection collection) { 175 criteriaBuilderHelper(criteria, name, collection, true); 176 } 177 178 179 /** 180 * This method provides the implementation for the conveniences methods criteriaBuilder & negatedCriteriaBuilder 181 * 182 * @param criteria - the criteria that might have a criterion appended 183 * @param name - name of the attribute 184 * @param collection - the collection to inspect 185 * @param negate - the criterion will be negated (NOT EQUALS, NOT IN) when this is true 186 */ 187 protected void criteriaBuilderHelper(Criteria criteria, String name, Collection collection, boolean negate) { 188 if (collection != null) { 189 int size = collection.size(); 190 if (size == 1) { 191 if (negate) { 192 criteria.addNotEqualTo(name, collection.iterator().next()); 193 } 194 else { 195 criteria.addEqualTo(name, collection.iterator().next()); 196 } 197 } 198 if (size > 1) { 199 if (negate) { 200 criteria.addNotIn(name, collection); 201 } 202 else { 203 criteria.addIn(name, collection); 204 205 } 206 } 207 } 208 209 } 210 211 /** 212 * Build a query based on all the parameters, and return an Iterator of all Balances from the database that qualify 213 * 214 * @param account the account of balances to find 215 * @param fiscalYear the fiscal year of balances to find 216 * @param includedObjectCodes a Collection of object codes found balances should have one of 217 * @param excludedObjectCodes a Collection of object codes found balances should not have one of 218 * @param objectTypeCodes a Collection of object type codes found balances should have one of 219 * @param balanceTypeCodes a Collection of balance type codes found balances should have one of 220 * @return an Iterator of Balances 221 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#findBalances(org.kuali.kfs.coa.businessobject.Account, java.lang.Integer, java.util.Collection, java.util.Collection, java.util.Collection, java.util.Collection) 222 */ 223 public Iterator<Balance> findBalances(Account account, Integer fiscalYear, Collection includedObjectCodes, Collection excludedObjectCodes, Collection objectTypeCodes, Collection balanceTypeCodes) { 224 LOG.debug("findBalances() started"); 225 226 Criteria criteria = new Criteria(); 227 228 criteria.addEqualTo(KFSPropertyConstants.ACCOUNT_NUMBER, account.getAccountNumber()); 229 criteria.addEqualTo(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, account.getChartOfAccountsCode()); 230 231 criteria.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, fiscalYear); 232 233 criteriaBuilder(criteria, GeneralLedgerConstants.ColumnNames.OBJECT_TYPE_CODE, objectTypeCodes); 234 criteriaBuilder(criteria, GeneralLedgerConstants.ColumnNames.BALANCE_TYPE_CODE, balanceTypeCodes); 235 criteriaBuilder(criteria, GeneralLedgerConstants.ColumnNames.OBJECT_CODE, includedObjectCodes); 236 negatedCriteriaBuilder(criteria, GeneralLedgerConstants.ColumnNames.OBJECT_CODE, excludedObjectCodes); 237 238 ReportQueryByCriteria query = new ReportQueryByCriteria(Balance.class, criteria); 239 240 // returns an iterator of all matching balances 241 Iterator balances = getPersistenceBrokerTemplate().getIteratorByQuery(query); 242 return balances; 243 } 244 245 /** 246 * Using the given fieldValues as keys, return all cash balance records 247 * 248 * @param fieldValues the input fields and values 249 * @param isConsolidated consolidation option is applied or not 250 * @return the records of cash balance entries 251 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#findCashBalance(java.util.Map, boolean) 252 */ 253 public Iterator<Balance> findCashBalance(Map fieldValues, boolean isConsolidated) { 254 LOG.debug("findCashBalance() started"); 255 256 Query query = this.getCashBalanceQuery(fieldValues, isConsolidated); 257 OJBUtility.limitResultSize(query); 258 return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 259 } 260 261 /** 262 * Get the number of detailed cash balance records that would be returned, were we to do a query based on the given fieldValues 263 * 264 * @param fieldValues the input fields and values 265 * @param isConsolidated consolidation option is applied or not 266 * @return the size collection of cash balance entry groups 267 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#getCashBalanceRecordCount(java.util.Map, boolean) 268 */ 269 public Integer getDetailedCashBalanceRecordCount(Map fieldValues) { 270 LOG.debug("getDetailedCashBalanceRecordCount() started"); 271 272 Query query = this.getCashBalanceQuery(fieldValues, false); 273 return getPersistenceBrokerTemplate().getCount(query); 274 } 275 276 /** 277 * Given a map of keys, return all of the report data about qualifying cash balances 278 * 279 * @param fieldValues the input fields and values 280 * @return the size collection of cash balance entry groups 281 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#getCashBalanceRecordSize(java.util.Map, boolean) 282 */ 283 public Iterator getConsolidatedCashBalanceRecordCount(Map fieldValues) { 284 LOG.debug("getCashBalanceRecordCount() started"); 285 286 ReportQueryByCriteria query = this.getCashBalanceCountQuery(fieldValues); 287 return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 288 } 289 290 /** 291 * Given a map of values, build a query out of those and find all the balances that qualify 292 * 293 * @param fieldValues a Map of fieldValues to use as keys in the query 294 * @param isConsolidated should the results be consolidated? 295 * @return an Iterator of Balances 296 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#findBalance(java.util.Map, boolean) 297 */ 298 public Iterator<Balance> findBalance(Map fieldValues, boolean isConsolidated) { 299 LOG.debug("findBalance() started"); 300 301 Query query = this.getBalanceQuery(fieldValues, isConsolidated); 302 OJBUtility.limitResultSize(query); 303 304 if (isConsolidated) { 305 return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 306 } 307 return getPersistenceBrokerTemplate().getIteratorByQuery(query); 308 } 309 310 /** 311 * Given a Map of keys to use as a query, if we performed that query as a consolidated query... 312 * how many records would we get back? 313 * 314 * @param fieldValues a Map of values to use as keys to build the query 315 * @return an Iterator of counts... 316 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#getConsolidatedBalanceRecordCount(java.util.Map) 317 */ 318 public Iterator getConsolidatedBalanceRecordCount(Map fieldValues) { 319 LOG.debug("getBalanceRecordCount() started"); 320 321 ReportQueryByCriteria query = this.getBalanceCountQuery(fieldValues); 322 return getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 323 } 324 325 /** 326 * Builds a query for cash balances, based on the given field values 327 * 328 * @param fieldValues a map of keys to use when building the query 329 * @return an OJB ReportQuery to use as the query 330 */ 331 protected ReportQueryByCriteria getCashBalanceCountQuery(Map fieldValues) { 332 Criteria criteria = buildCriteriaFromMap(fieldValues, new CashBalance()); 333 criteria.addEqualTo(KFSPropertyConstants.BALANCE_TYPE_CODE, KFSConstants.BALANCE_TYPE_ACTUAL); 334 criteria.addEqualToField("chart.financialCashObjectCode", KFSPropertyConstants.OBJECT_CODE); 335 336 ReportQueryByCriteria query = QueryFactory.newReportQuery(CashBalance.class, criteria); 337 338 List groupByList = buildGroupByList(); 339 groupByList.remove(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 340 groupByList.remove(KFSPropertyConstants.SUB_OBJECT_CODE); 341 groupByList.remove(KFSPropertyConstants.OBJECT_TYPE_CODE); 342 343 // add the group criteria into the selection statement 344 String[] groupBy = (String[]) groupByList.toArray(new String[groupByList.size()]); 345 query.addGroupBy(groupBy); 346 347 // set the selection attributes 348 query.setAttributes(new String[] { "count(*)" }); 349 350 return query; 351 } 352 353 /** 354 * build the query for cash balance search 355 * 356 * @param fieldValues Map of keys to use for the query 357 * @param isConsolidated should the results be consolidated? 358 * @return the OJB query to perform 359 */ 360 protected Query getCashBalanceQuery(Map fieldValues, boolean isConsolidated) { 361 Criteria criteria = buildCriteriaFromMap(fieldValues, new CashBalance()); 362 criteria.addEqualTo(KFSPropertyConstants.BALANCE_TYPE_CODE, KFSConstants.BALANCE_TYPE_ACTUAL); 363 criteria.addEqualToField("chart.financialCashObjectCode", KFSPropertyConstants.OBJECT_CODE); 364 365 ReportQueryByCriteria query = QueryFactory.newReportQuery(CashBalance.class, criteria); 366 List attributeList = buildAttributeList(false); 367 List groupByList = buildGroupByList(); 368 369 // if consolidated, then ignore the following fields 370 if (isConsolidated) { 371 attributeList.remove(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 372 groupByList.remove(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 373 attributeList.remove(KFSPropertyConstants.SUB_OBJECT_CODE); 374 groupByList.remove(KFSPropertyConstants.SUB_OBJECT_CODE); 375 attributeList.remove(KFSPropertyConstants.OBJECT_TYPE_CODE); 376 groupByList.remove(KFSPropertyConstants.OBJECT_TYPE_CODE); 377 } 378 379 // add the group criteria into the selection statement 380 String[] groupBy = (String[]) groupByList.toArray(new String[groupByList.size()]); 381 query.addGroupBy(groupBy); 382 383 // set the selection attributes 384 String[] attributes = (String[]) attributeList.toArray(new String[attributeList.size()]); 385 query.setAttributes(attributes); 386 387 return query; 388 } 389 390 /** 391 * build the query for balance search 392 * 393 * @param fieldValues Map of keys to use for the query 394 * @param isConsolidated should the results be consolidated? 395 * @return an OJB query to perform 396 */ 397 protected Query getBalanceQuery(Map fieldValues, boolean isConsolidated) { 398 LOG.debug("getBalanceQuery(Map, boolean) started"); 399 400 Criteria criteria = buildCriteriaFromMap(fieldValues, new Balance()); 401 ReportQueryByCriteria query = QueryFactory.newReportQuery(Balance.class, criteria); 402 403 // if consolidated, then ignore subaccount number and balance type code 404 if (isConsolidated) { 405 List attributeList = buildAttributeList(true); 406 List groupByList = buildGroupByList(); 407 408 // ignore subaccount number, sub object code and object type code 409 attributeList.remove(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 410 groupByList.remove(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 411 attributeList.remove(KFSPropertyConstants.SUB_OBJECT_CODE); 412 groupByList.remove(KFSPropertyConstants.SUB_OBJECT_CODE); 413 attributeList.remove(KFSPropertyConstants.OBJECT_TYPE_CODE); 414 groupByList.remove(KFSPropertyConstants.OBJECT_TYPE_CODE); 415 416 // set the selection attributes 417 String[] attributes = (String[]) attributeList.toArray(new String[attributeList.size()]); 418 query.setAttributes(attributes); 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 } 424 425 return query; 426 } 427 428 /** 429 * build the query for balance search 430 * 431 * @param fieldValues Map of keys to use for the query 432 * @return an OJB ReportQuery to perform 433 */ 434 protected ReportQueryByCriteria getBalanceCountQuery(Map fieldValues) { 435 Criteria criteria = buildCriteriaFromMap(fieldValues, new Balance()); 436 ReportQueryByCriteria query = QueryFactory.newReportQuery(Balance.class, criteria); 437 438 // set the selection attributes 439 query.setAttributes(new String[] { "count(*)" }); 440 441 List groupByList = buildGroupByList(); 442 groupByList.remove(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 443 groupByList.remove(KFSPropertyConstants.SUB_OBJECT_CODE); 444 groupByList.remove(KFSPropertyConstants.OBJECT_TYPE_CODE); 445 446 // add the group criteria into the selection statement 447 String[] groupBy = (String[]) groupByList.toArray(new String[groupByList.size()]); 448 query.addGroupBy(groupBy); 449 return query; 450 } 451 452 /** 453 * This method builds the query criteria based on the input field map 454 * 455 * @param fieldValues Map of keys to use for the query 456 * @param balance this really usen't used in the method 457 * @return a query criteria 458 */ 459 protected Criteria buildCriteriaFromMap(Map fieldValues, Balance balance) { 460 Map localFieldValues = new HashMap(); 461 localFieldValues.putAll(fieldValues); 462 463 Criteria criteria = new Criteria(); 464 465 // handle encumbrance balance type 466 String propertyName = KFSPropertyConstants.BALANCE_TYPE_CODE; 467 if (localFieldValues.containsKey(propertyName)) { 468 String propertyValue = (String) localFieldValues.get(propertyName); 469 if (KFSConstants.AGGREGATE_ENCUMBRANCE_BALANCE_TYPE_CODE.equals(propertyValue)) { 470 localFieldValues.remove(KFSPropertyConstants.BALANCE_TYPE_CODE); 471 472 // the year should be part of the results for both the cash balance and regular balance lookupables 473 String universityFiscalYearStr = (String) localFieldValues.get(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR); 474 Integer universityFiscalYear = new Integer(universityFiscalYearStr); 475 476 criteria.addIn(KFSPropertyConstants.BALANCE_TYPE_CODE, balanceTypService.getEncumbranceBalanceTypes(universityFiscalYear)); 477 } 478 } 479 480 criteria.addAndCriteria(OJBUtility.buildCriteriaFromMap(localFieldValues, balance)); 481 return criteria; 482 } 483 484 /** 485 * This method builds the atrribute list used by balance searching 486 * 487 * @param isExtended should we add the attributes to sum each of the monthly totals? 488 * @return List an attribute list 489 */ 490 protected List<String> buildAttributeList(boolean isExtended) { 491 List attributeList = this.buildGroupByList(); 492 493 attributeList.add("sum(accountLineAnnualBalanceAmount)"); 494 attributeList.add("sum(beginningBalanceLineAmount)"); 495 attributeList.add("sum(contractsGrantsBeginningBalanceAmount)"); 496 497 // add the entended elements into the list 498 if (isExtended) { 499 attributeList.add("sum(month1Amount)"); 500 attributeList.add("sum(month2Amount)"); 501 attributeList.add("sum(month3Amount)"); 502 attributeList.add("sum(month4Amount)"); 503 attributeList.add("sum(month5Amount)"); 504 attributeList.add("sum(month6Amount)"); 505 attributeList.add("sum(month7Amount)"); 506 attributeList.add("sum(month8Amount)"); 507 attributeList.add("sum(month9Amount)"); 508 attributeList.add("sum(month10Amount)"); 509 attributeList.add("sum(month11Amount)"); 510 attributeList.add("sum(month12Amount)"); 511 attributeList.add("sum(month13Amount)"); 512 } 513 return attributeList; 514 } 515 516 /** 517 * This method builds group by attribute list used by balance searching 518 * 519 * @return List an group by attribute list 520 */ 521 protected List<String> buildGroupByList() { 522 List attributeList = new ArrayList(); 523 524 attributeList.add(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR); 525 attributeList.add(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE); 526 attributeList.add(KFSPropertyConstants.ACCOUNT_NUMBER); 527 attributeList.add(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 528 attributeList.add(KFSPropertyConstants.BALANCE_TYPE_CODE); 529 attributeList.add(KFSPropertyConstants.OBJECT_CODE); 530 attributeList.add(KFSPropertyConstants.SUB_OBJECT_CODE); 531 attributeList.add(KFSPropertyConstants.OBJECT_TYPE_CODE); 532 533 return attributeList; 534 } 535 536 /** 537 * Whoa! This method is seemingly not called in the code base right now, and you know what? You shouldn't call it 538 * First of all, we're not even sending in all the primary keys for Balance, and second of all, we're 539 * returning a SufficientFundsBalance, which we cast to a Balance, which is *always* going to throw a 540 * ClassCastException. Don't call this method. Just...just step away. 541 * 542 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#getBalanceByPrimaryId(java.lang.Integer, java.lang.String, java.lang.String) 543 */ 544 public Balance getBalanceByPrimaryId(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber) { 545 // TODO just kill this 546 LOG.debug("getBalanceByPrimaryId() started"); 547 548 Criteria crit = new Criteria(); 549 crit.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear); 550 crit.addEqualTo(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode); 551 crit.addEqualTo(KFSPropertyConstants.ACCOUNT_NUMBER, accountNumber); 552 553 QueryByCriteria qbc = QueryFactory.newQuery(SufficientFundBalances.class, crit); 554 return (Balance) getPersistenceBrokerTemplate().getObjectByQuery(qbc); 555 } 556 557 558 /** 559 * Since SubAccountNumber, SubObjectCode, and ObjectType are all part of the primary key of Balance, you're guaranteed to get one of those 560 * records when you call this method. Let's hope the right one. 561 * 562 * @param universityFiscalYear the fiscal year of the CB balance to return 563 * @param chartOfAccountsCode the chart of the accounts code of the CB balanes to return 564 * @param accountNumber the account number of the CB balance to return 565 * @param objectCode the object code of the CB balance to return 566 * @return the CB Balance record 567 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#getCurrentBudgetForObjectCode(java.lang.Integer, java.lang.String, java.lang.String, 568 * java.lang.String) 569 */ 570 public Balance getCurrentBudgetForObjectCode(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String objectCode) { 571 LOG.debug("getCurrentBudgetForObjectCode() started"); 572 573 Criteria crit = new Criteria(); 574 crit.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear); 575 crit.addEqualTo(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode); 576 crit.addEqualTo(KFSPropertyConstants.ACCOUNT_NUMBER, accountNumber); 577 crit.addEqualTo(KFSPropertyConstants.OBJECT_CODE, objectCode); 578 crit.addEqualTo(KFSPropertyConstants.BALANCE_TYPE_CODE, KFSConstants.BALANCE_TYPE_CURRENT_BUDGET); 579 580 QueryByCriteria qbc = QueryFactory.newQuery(Balance.class, crit); 581 return (Balance) getPersistenceBrokerTemplate().getObjectByQuery(qbc); 582 } 583 584 /** 585 * Find all matching account balances. 586 * 587 * @param universityFiscalYear the university fiscal year of balances to return 588 * @param chartOfAccountsCode the chart of accounts code of balances to return 589 * @param accountNumber the account number of balances to return 590 * @return balances sorted by object code 591 */ 592 public Iterator<Balance> findAccountBalances(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber) { 593 LOG.debug("findAccountBalances() started"); 594 return this.findAccountBalances(universityFiscalYear, chartOfAccountsCode, accountNumber, KFSConstants.SF_TYPE_OBJECT); 595 } 596 597 /** 598 * Find all matching account balances. The Sufficient funds code is used to determine the sort of the results. 599 * 600 * @param universityFiscalYear the university fiscal year of balances to return 601 * @param chartOfAccountsCode the chart of accounts code of balances to return 602 * @param accountNumber the account number of balances to return 603 * @param sfCode the sufficient funds code, used to sort on 604 * @return an Iterator of balances 605 */ 606 public Iterator<Balance> findAccountBalances(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String sfCode) { 607 LOG.debug("findAccountBalances() started"); 608 609 Criteria crit = new Criteria(); 610 crit.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear); 611 crit.addEqualTo(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode); 612 crit.addEqualTo(KFSPropertyConstants.ACCOUNT_NUMBER, accountNumber); 613 614 QueryByCriteria qbc = QueryFactory.newQuery(Balance.class, crit); 615 if (KFSConstants.SF_TYPE_OBJECT.equals(sfCode)) { 616 qbc.addOrderByAscending(KFSPropertyConstants.OBJECT_CODE); 617 } 618 else if (KFSConstants.SF_TYPE_LEVEL.equals(sfCode)) { 619 qbc.addOrderByAscending(GeneralLedgerConstants.BalanceInquiryDrillDowns.OBJECT_LEVEL_CODE); 620 } 621 else if (KFSConstants.SF_TYPE_CONSOLIDATION.equals(sfCode)) { 622 qbc.addOrderByAscending(GeneralLedgerConstants.BalanceInquiryDrillDowns.CONSOLIDATION_OBJECT_CODE); 623 } 624 return getPersistenceBrokerTemplate().getIteratorByQuery(qbc); 625 } 626 627 /** 628 * Purge the sufficient funds balance table by year/chart 629 * 630 * @param chart the chart of balances to purge 631 * @param year the university fiscal year of balances to purge 632 */ 633 public void purgeYearByChart(String chartOfAccountsCode, int year) { 634 LOG.debug("purgeYearByChart() started"); 635 636 Criteria criteria = new Criteria(); 637 criteria.addEqualTo(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode); 638 criteria.addLessThan(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, new Integer(year)); 639 640 getPersistenceBrokerTemplate().deleteByQuery(new QueryByCriteria(Balance.class, criteria)); 641 642 // This is required because if any deleted account balances are in the cache, deleteByQuery doesn't 643 // remove them from the cache so a future select will retrieve these deleted account balances from 644 // the cache and return them. Clearing the cache forces OJB to go to the database again. 645 getPersistenceBrokerTemplate().clearCache(); 646 } 647 648 /** 649 * Returns the count of balances for a given fiscal year; this method is used for year end job reporting 650 * @param year the university fiscal year to count balances for 651 * @return an int with the count of balances for that fiscal year 652 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#countBalancesForFiscalYear(java.lang.Integer) 653 */ 654 public int countBalancesForFiscalYear(Integer year) { 655 LOG.debug("countBalancesForFiscalYear() started"); 656 657 Criteria c = new Criteria(); 658 c.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, year); 659 QueryByCriteria query = QueryFactory.newQuery(Balance.class, c); 660 661 return getPersistenceBrokerTemplate().getCount(query); 662 } 663 664 /** 665 * Finds all of the balances for the fiscal year that should be processed by nominal activity closing 666 * 667 * @param year the university fiscal year of balances to find 668 * @return an Iterator of Balances to process 669 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#findNominalActivityBalancesForFiscalYear(java.lang.Integer) 670 */ 671 public Iterator<Balance> findNominalActivityBalancesForFiscalYear(Integer year) { 672 LOG.debug("findNominalActivityBalancesForFiscalYear() started"); 673 674 SystemOptions currentYearOptions = optionsService.getCurrentYearOptions(); 675 676 // generate List of nominal activity object type codes 677 ObjectTypeService objectTypeService = SpringContext.getBean(ObjectTypeService.class); 678 679 Criteria c = new Criteria(); 680 c.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, year); 681 c.addEqualTo(KFSPropertyConstants.BALANCE_TYPE_CODE, currentYearOptions.getActualFinancialBalanceTypeCd()); 682 c.addIn(KFSPropertyConstants.OBJECT_TYPE_CODE, objectTypeService.getNominalActivityClosingAllowedObjectTypes(year)); 683 c.addNotEqualTo("accountLineAnnualBalanceAmount", KualiDecimal.ZERO); 684 685 QueryByCriteria query = QueryFactory.newQuery(Balance.class, c); 686 query.addOrderByAscending(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE); 687 query.addOrderByAscending(KFSPropertyConstants.ACCOUNT_NUMBER); 688 query.addOrderByAscending(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 689 query.addOrderByAscending(KFSPropertyConstants.OBJECT_CODE); 690 query.addOrderByAscending(KFSPropertyConstants.SUB_OBJECT_CODE); 691 query.addOrderByAscending(KFSPropertyConstants.BALANCE_TYPE_CODE); 692 query.addOrderByAscending(KFSPropertyConstants.OBJECT_TYPE_CODE); 693 694 return getPersistenceBrokerTemplate().getIteratorByQuery(query); 695 } 696 697 /** 698 * Returns all of the balances that should be procesed by the BalanceForward year end job under the general rule 699 * 700 * @param the university fiscal year to find balances for 701 * @return an Iterator of Balances to process 702 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#findCumulativeBalancesToForwardForFiscalYear(java.lang.Integer) 703 */ 704 public Iterator<Balance> findGeneralBalancesToForwardForFiscalYear(Integer year) { 705 ObjectTypeService objectTypeService = SpringContext.getBean(ObjectTypeService.class); 706 707 String[] generalBalanceForwardBalanceTypesArray = parameterService.getParameterValues(BalanceForwardStep.class, GeneralLedgerConstants.BalanceForwardRule.BALANCE_TYPES_TO_ROLL_FORWARD_FOR_BALANCE_SHEET).toArray(new String[] {}); 708 List<String> generalBalanceForwardBalanceTypes = new ArrayList<String>(); 709 for (String bt : generalBalanceForwardBalanceTypesArray) { 710 generalBalanceForwardBalanceTypes.add(bt); 711 } 712 713 Criteria c = new Criteria(); 714 c.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, year); 715 c.addIn(KFSPropertyConstants.BALANCE_TYPE_CODE, generalBalanceForwardBalanceTypes); 716 c.addIn(KFSPropertyConstants.OBJECT_TYPE_CODE, objectTypeService.getGeneralForwardBalanceObjectTypes(year)); 717 718 QueryByCriteria query = QueryFactory.newQuery(Balance.class, c); 719 query.addOrderByAscending(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE); 720 query.addOrderByAscending(KFSPropertyConstants.ACCOUNT_NUMBER); 721 query.addOrderByAscending(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 722 query.addOrderByAscending(KFSPropertyConstants.OBJECT_CODE); 723 query.addOrderByAscending(KFSPropertyConstants.SUB_OBJECT_CODE); 724 query.addOrderByAscending(KFSPropertyConstants.BALANCE_TYPE_CODE); 725 query.addOrderByAscending(KFSPropertyConstants.OBJECT_TYPE_CODE); 726 727 Iterator<Balance> balances = getPersistenceBrokerTemplate().getIteratorByQuery(query); 728 729 Map<String, FilteringBalanceIterator> balanceIterators = SpringContext.getBeansOfType(FilteringBalanceIterator.class); 730 FilteringBalanceIterator filteredBalances = balanceIterators.get("glBalanceTotalNotZeroIterator"); 731 filteredBalances.setBalancesSource(balances); 732 733 return filteredBalances; 734 } 735 736 /** 737 * Returns all of the balances that should be procesed by the BalanceForward year end job under the active rule 738 * 739 * @param the university fiscal year to find balances for 740 * @return an Iterator of Balances to process 741 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#findGeneralBalancesToForwardForFiscalYear(java.lang.Integer) 742 */ 743 public Iterator<Balance> findCumulativeBalancesToForwardForFiscalYear(Integer year) { 744 ObjectTypeService objectTypeService = SpringContext.getBean(ObjectTypeService.class); 745 SubFundGroupService subFundGroupService = SpringContext.getBean(SubFundGroupService.class); 746 747 final String[] subFundGroupsForCumulativeBalanceForwardingArray = parameterService.getParameterValues(BalanceForwardStep.class, GeneralLedgerConstants.BalanceForwardRule.SUB_FUND_GROUPS_FOR_INCEPTION_TO_DATE_REPORTING).toArray(new String[] {}); 748 List<String> subFundGroupsForCumulativeBalanceForwarding = new ArrayList<String>(); 749 for (String subFundGroup : subFundGroupsForCumulativeBalanceForwardingArray) { 750 subFundGroupsForCumulativeBalanceForwarding.add(subFundGroup); 751 } 752 753 String[] cumulativeBalanceForwardBalanceTypesArray = parameterService.getParameterValues(BalanceForwardStep.class, GeneralLedgerConstants.BalanceForwardRule.BALANCE_TYPES_TO_ROLL_FORWARD_FOR_INCOME_EXPENSE).toArray(new String[] {}); 754 List<String> cumulativeBalanceForwardBalanceTypes = new ArrayList<String>(); 755 for (String bt : cumulativeBalanceForwardBalanceTypesArray) { 756 cumulativeBalanceForwardBalanceTypes.add(bt); 757 } 758 759 Criteria c = new Criteria(); 760 c.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, year); 761 c.addIn(KFSPropertyConstants.BALANCE_TYPE_CODE, cumulativeBalanceForwardBalanceTypes); 762 c.addIn(KFSPropertyConstants.OBJECT_TYPE_CODE, objectTypeService.getCumulativeForwardBalanceObjectTypes(year)); 763 764 Criteria forCGCrit = new Criteria(); 765 if (parameterService.getIndicatorParameter(Account.class, KFSConstants.ChartApcParms.ACCOUNT_FUND_GROUP_DENOTES_CG)) { 766 for (String value : subFundGroupService.getContractsAndGrantsDenotingValues()) { 767 forCGCrit.addEqualTo("priorYearAccount.subFundGroup.fundGroupCode", value); 768 } 769 } else { 770 for (String value : subFundGroupService.getContractsAndGrantsDenotingValues()) { 771 forCGCrit.addEqualTo("priorYearAccount.subFundGroupCode", value); 772 } 773 } 774 775 Criteria subFundGroupCrit = new Criteria(); 776 subFundGroupCrit.addIn("priorYearAccount.subFundGroupCode", subFundGroupsForCumulativeBalanceForwarding); 777 forCGCrit.addOrCriteria(subFundGroupCrit); 778 c.addAndCriteria(forCGCrit); 779 780 QueryByCriteria query = QueryFactory.newQuery(Balance.class, c); 781 query.addOrderByAscending(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE); 782 query.addOrderByAscending(KFSPropertyConstants.ACCOUNT_NUMBER); 783 query.addOrderByAscending(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 784 query.addOrderByAscending(KFSPropertyConstants.OBJECT_CODE); 785 query.addOrderByAscending(KFSPropertyConstants.SUB_OBJECT_CODE); 786 query.addOrderByAscending(KFSPropertyConstants.BALANCE_TYPE_CODE); 787 query.addOrderByAscending(KFSPropertyConstants.OBJECT_TYPE_CODE); 788 789 Iterator<Balance> balances = getPersistenceBrokerTemplate().getIteratorByQuery(query); 790 791 FilteringBalanceIterator filteredBalances = SpringContext.getBean(FilteringBalanceIterator.class,"glBalanceAnnualAndCGTotalNotZeroIterator"); 792 filteredBalances.setBalancesSource(balances); 793 794 return filteredBalances; 795 } 796 797 protected static final String PARAMETER_PREFIX = "SELECTION_"; 798 799 /** 800 * Returns a list of balances to return for the Organization Reversion year end job to process 801 * 802 * @param the university fiscal year to find balances for 803 * @param endOfYear if true, use currrent year accounts, otherwise use prior year accounts 804 * @return an Iterator of Balances to process 805 * @see org.kuali.kfs.gl.dataaccess.BalanceDao#findOrganizationReversionBalancesForFiscalYear(java.lang.Integer, boolean) 806 */ 807 public Iterator<Balance> findOrganizationReversionBalancesForFiscalYear(Integer year, boolean endOfYear) { 808 LOG.debug("findOrganizationReversionBalancesForFiscalYear() started"); 809 Criteria c = new Criteria(); 810 c.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, year); 811 ParameterService parameterService = SpringContext.getBean(ParameterService.class); 812 Map<Integer, String> parsedRules = new TreeMap<Integer, String>(); 813 int i = 1; 814 boolean moreParams = true; 815 while (moreParams) { 816 if (parameterService.parameterExists(OrganizationReversion.class, PARAMETER_PREFIX + i)) { 817 ParameterEvaluator parameterEvaluator = parameterService.getParameterEvaluator(OrganizationReversion.class, PARAMETER_PREFIX + i); 818 String currentRule = parameterEvaluator.getValue(); 819 if (endOfYear) { 820 currentRule = currentRule.replaceAll("account\\.", "priorYearAccount."); 821 } 822 if (StringUtils.isNotBlank(currentRule)) { 823 String propertyName = StringUtils.substringBefore(currentRule, "="); 824 List<String> ruleValues = Arrays.asList(StringUtils.substringAfter(currentRule, "=").split(";")); 825 if (propertyName != null && propertyName.length() > 0 && ruleValues.size() > 0 && !StringUtils.isBlank(ruleValues.get(0))) { 826 if (parameterEvaluator.constraintIsAllow()) { 827 c.addIn(propertyName, ruleValues); 828 } 829 else { 830 c.addNotIn(propertyName, ruleValues); 831 } 832 } 833 } 834 } 835 else { 836 moreParams = false; 837 } 838 i++; 839 } 840 // we only ever calculate on CB, AC, and encumbrance types, so let's only select those 841 SystemOptions options = SpringContext.getBean(OptionsService.class).getOptions(year); 842 List organizationReversionBalancesToSelect = new ArrayList(); 843 organizationReversionBalancesToSelect.add(options.getActualFinancialBalanceTypeCd()); 844 organizationReversionBalancesToSelect.add(options.getFinObjTypeExpenditureexpCd()); 845 organizationReversionBalancesToSelect.add(options.getCostShareEncumbranceBalanceTypeCd()); 846 organizationReversionBalancesToSelect.add(options.getIntrnlEncumFinBalanceTypCd()); 847 organizationReversionBalancesToSelect.add(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET); 848 c.addIn(KFSPropertyConstants.BALANCE_TYPE_CODE, organizationReversionBalancesToSelect); 849 QueryByCriteria query = QueryFactory.newQuery(Balance.class, c); 850 query.addOrderByAscending(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE); 851 query.addOrderByAscending(KFSPropertyConstants.ACCOUNT_NUMBER); 852 query.addOrderByAscending(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); 853 query.addOrderByAscending(KFSPropertyConstants.OBJECT_CODE); 854 query.addOrderByAscending(KFSPropertyConstants.SUB_OBJECT_CODE); 855 query.addOrderByAscending(KFSPropertyConstants.BALANCE_TYPE_CODE); 856 query.addOrderByAscending(KFSPropertyConstants.OBJECT_TYPE_CODE); 857 858 return getPersistenceBrokerTemplate().getIteratorByQuery(query); 859 } 860 861 /** 862 * @see org.kuali.kfs.gl.dataaccess.BalancingDao#findCountGreaterOrEqualThan(java.lang.Integer) 863 */ 864 public Integer findCountGreaterOrEqualThan(Integer year) { 865 Criteria criteria = new Criteria(); 866 criteria.addGreaterOrEqualThan(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, year); 867 868 ReportQueryByCriteria query = QueryFactory.newReportQuery(Balance.class, criteria); 869 870 return getPersistenceBrokerTemplate().getCount(query); 871 } 872 873 public void setOptionsService(OptionsService optionsService) { 874 this.optionsService = optionsService; 875 } 876 877 public void setParameterService(ParameterService parameterService) { 878 this.parameterService = parameterService; 879 } 880 881 public void setBalanceTypService(BalanceTypeService balanceTypService) { 882 this.balanceTypService = balanceTypService; 883 } 884 }