001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.module.gl.service.impl;
017:
018: import java.util.ArrayList;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Map;
022:
023: import org.apache.commons.collections.IteratorUtils;
024: import org.kuali.core.service.KualiConfigurationService;
025: import org.kuali.kfs.KFSKeyConstants;
026: import org.kuali.kfs.context.SpringContext;
027: import org.kuali.module.chart.service.ObjectTypeService;
028: import org.kuali.module.gl.GLConstants;
029: import org.kuali.module.gl.bo.AccountBalance;
030: import org.kuali.module.gl.dao.AccountBalanceDao;
031: import org.kuali.module.gl.service.AccountBalanceService;
032: import org.kuali.module.gl.util.OJBUtility;
033: import org.kuali.module.gl.web.Constant;
034: import org.springframework.transaction.annotation.Transactional;
035:
036: /**
037: * The basic implementation of the AccountBalanceService interface
038: */
039: @Transactional
040: public class AccountBalanceServiceImpl implements AccountBalanceService {
041: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
042: .getLogger(AccountBalanceServiceImpl.class);
043:
044: AccountBalanceDao accountBalanceDao;
045: KualiConfigurationService kualiConfigurationService;
046:
047: /**
048: * Defers to the DAO to find the consolidated account balances, based on the keys given in the Map parameter
049: *
050: * @param fieldValues the input fields and values
051: * @return the summary records of account balance entries
052: * @see org.kuali.module.gl.service.AccountBalanceService#findConsolidatedAvailableAccountBalance(java.util.Map)
053: */
054: public Iterator findConsolidatedAvailableAccountBalance(
055: Map fieldValues) {
056: LOG.debug("findConsolidatedAvailableAccountBalance() started");
057:
058: return accountBalanceDao
059: .findConsolidatedAvailableAccountBalance(fieldValues);
060: }
061:
062: /**
063: * Given the map of parameters, constructs a query to find all qualifying account balance records
064: *
065: * @param fieldValues the input fields and values
066: * @param isConsolidated determine whether the search results are consolidated
067: * @return a collection of account balance entries
068: * @see org.kuali.module.gl.service.AccountBalanceService#findAvailableAccountBalance(java.util.Map)
069: */
070: public Iterator findAvailableAccountBalance(Map fieldValues) {
071: LOG.debug("findAvailableAccountBalance() started");
072:
073: return accountBalanceDao
074: .findAvailableAccountBalance(fieldValues);
075: }
076:
077: /**
078: * This finds account balances grouped by consolidation
079: *
080: * @param universityFiscalYear the fiscal year account to find account balances for
081: * @param chartOfAccountsCode the chart of accounts code to find account balances for
082: * @param accountNumber the account number to find account balances for
083: * @param subAccountNumber the sub account number to find account balances for
084: * @param isCostShareExcluded should account balances found have cost share information excluded?
085: * @param isConsolidated should account balances found be consolidated?
086: * @param pendingEntryCode should pending entries be included in the query?
087: * @return a List of qualifying account balance records
088: * @see org.kuali.module.gl.service.AccountBalanceService#findAccountBalanceByConsolidation(java.util.Map, boolean, boolean)
089: */
090: public List findAccountBalanceByConsolidation(
091: Integer universityFiscalYear, String chartOfAccountsCode,
092: String accountNumber, String subAccountNumber,
093: boolean isCostShareExcluded, boolean isConsolidated,
094: int pendingEntryCode) {
095: LOG.debug("findAccountBalanceByConsolidation() started");
096:
097: ObjectTypeService objectTypeService = (ObjectTypeService) SpringContext
098: .getBean(ObjectTypeService.class);
099:
100: String[] incomeObjectTypes = objectTypeService
101: .getBasicIncomeObjectTypes(universityFiscalYear)
102: .toArray(new String[0]);
103: String[] incomeTransferObjectTypes = { objectTypeService
104: .getIncomeTransferObjectType(universityFiscalYear) };
105: String[] expenseObjectTypes = objectTypeService
106: .getBasicExpenseObjectTypes(universityFiscalYear)
107: .toArray(new String[0]);
108: String[] expenseTransferObjectTypes = { objectTypeService
109: .getExpenseTransferObjectType(universityFiscalYear) };
110:
111: // Consolidate all object types into one array (yes I could have used lists, but it was just as many lines of code than
112: // this)
113: String[] allObjectTypes = new String[incomeObjectTypes.length
114: + incomeTransferObjectTypes.length
115: + expenseObjectTypes.length
116: + expenseTransferObjectTypes.length];
117: int count = 0;
118: for (int i = 0; i < incomeObjectTypes.length; i++) {
119: allObjectTypes[count++] = incomeObjectTypes[i];
120: }
121: for (int i = 0; i < incomeTransferObjectTypes.length; i++) {
122: allObjectTypes[count++] = incomeTransferObjectTypes[i];
123: }
124: for (int i = 0; i < expenseObjectTypes.length; i++) {
125: allObjectTypes[count++] = expenseObjectTypes[i];
126: }
127: for (int i = 0; i < expenseTransferObjectTypes.length; i++) {
128: allObjectTypes[count++] = expenseTransferObjectTypes[i];
129: }
130:
131: // Put the total lines at the beginning of the list
132: List results = new ArrayList();
133: AccountBalance income = new AccountBalance(
134: kualiConfigurationService
135: .getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME));
136: AccountBalance incomeTransfers = new AccountBalance(
137: kualiConfigurationService
138: .getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME_FROM_TRANSFERS));
139: AccountBalance incomeTotal = new AccountBalance(
140: kualiConfigurationService
141: .getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME_TOTAL));
142: AccountBalance expense = new AccountBalance(
143: kualiConfigurationService
144: .getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE));
145: AccountBalance expenseTransfers = new AccountBalance(
146: kualiConfigurationService
147: .getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE_FROM_TRANSFERS));
148: AccountBalance expenseTotal = new AccountBalance(
149: kualiConfigurationService
150: .getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE_TOTAL));
151: AccountBalance total = new AccountBalance(
152: kualiConfigurationService
153: .getPropertyString(KFSKeyConstants.AccountBalanceService.TOTAL));
154:
155: results.add(income);
156: results.add(incomeTransfers);
157: results.add(incomeTotal);
158: results.add(expense);
159: results.add(expenseTransfers);
160: results.add(expenseTotal);
161: results.add(total);
162:
163: // If you want a sub account, you can't do consolidated
164: if ((subAccountNumber != null)
165: && (subAccountNumber.length() > 0)) {
166: subAccountNumber = subAccountNumber.toUpperCase();
167: isConsolidated = false;
168: }
169:
170: // Get the data
171: List balances = accountBalanceDao
172: .findAccountBalanceByConsolidationByObjectTypes(
173: allObjectTypes, universityFiscalYear,
174: chartOfAccountsCode, accountNumber,
175: isCostShareExcluded, isConsolidated,
176: pendingEntryCode);
177:
178: // Convert it to Account Balances
179: for (Iterator iter = balances.iterator(); iter.hasNext();) {
180: Map bal = (Map) iter.next();
181: AccountBalance bbc = new AccountBalance(
182: AccountBalance.TYPE_CONSOLIDATION, bal,
183: universityFiscalYear, chartOfAccountsCode,
184: accountNumber);
185:
186: if ((subAccountNumber != null)
187: && (subAccountNumber.length() > 0)) {
188: if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
189: addBalanceToTotals(bbc, incomeTotal, expenseTotal);
190: results.add(bbc);
191: }
192: } else {
193: addBalanceToTotals(bbc, incomeTotal, expenseTotal);
194: results.add(bbc);
195: }
196: }
197:
198: // Calculate totals
199:
200: // Get balances for these parameters, then based on the object type code, put balances into the correct summary line
201: List data = accountBalanceDao
202: .findAccountBalanceByConsolidationByObjectTypes(
203: incomeObjectTypes, universityFiscalYear,
204: chartOfAccountsCode, accountNumber,
205: isCostShareExcluded, isConsolidated,
206: pendingEntryCode);
207: for (Iterator iter = data.iterator(); iter.hasNext();) {
208: Map bal = (Map) iter.next();
209: AccountBalance bbc = new AccountBalance(
210: AccountBalance.TYPE_CONSOLIDATION, bal,
211: universityFiscalYear, chartOfAccountsCode,
212: accountNumber);
213: if ((subAccountNumber != null)
214: && (subAccountNumber.length() > 0)) {
215: if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
216: income.add(bbc);
217: }
218: } else {
219: income.add(bbc);
220: }
221: }
222:
223: data = accountBalanceDao
224: .findAccountBalanceByConsolidationByObjectTypes(
225: incomeTransferObjectTypes,
226: universityFiscalYear, chartOfAccountsCode,
227: accountNumber, isCostShareExcluded,
228: isConsolidated, pendingEntryCode);
229: for (Iterator iter = data.iterator(); iter.hasNext();) {
230: Map bal = (Map) iter.next();
231: AccountBalance bbc = new AccountBalance(
232: AccountBalance.TYPE_CONSOLIDATION, bal,
233: universityFiscalYear, chartOfAccountsCode,
234: accountNumber);
235: if ((subAccountNumber != null)
236: && (subAccountNumber.length() > 0)) {
237: if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
238: incomeTransfers.add(bbc);
239: }
240: } else {
241: incomeTransfers.add(bbc);
242: }
243: }
244:
245: data = accountBalanceDao
246: .findAccountBalanceByConsolidationByObjectTypes(
247: expenseObjectTypes, universityFiscalYear,
248: chartOfAccountsCode, accountNumber,
249: isCostShareExcluded, isConsolidated,
250: pendingEntryCode);
251: for (Iterator iter = data.iterator(); iter.hasNext();) {
252: Map bal = (Map) iter.next();
253: AccountBalance bbc = new AccountBalance(
254: AccountBalance.TYPE_CONSOLIDATION, bal,
255: universityFiscalYear, chartOfAccountsCode,
256: accountNumber);
257: if ((subAccountNumber != null)
258: && (subAccountNumber.length() > 0)) {
259: if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
260: expense.add(bbc);
261: }
262: } else {
263: expense.add(bbc);
264: }
265: }
266:
267: data = accountBalanceDao
268: .findAccountBalanceByConsolidationByObjectTypes(
269: expenseTransferObjectTypes,
270: universityFiscalYear, chartOfAccountsCode,
271: accountNumber, isCostShareExcluded,
272: isConsolidated, pendingEntryCode);
273: for (Iterator iter = data.iterator(); iter.hasNext();) {
274: Map bal = (Map) iter.next();
275: AccountBalance bbc = new AccountBalance(
276: AccountBalance.TYPE_CONSOLIDATION, bal,
277: universityFiscalYear, chartOfAccountsCode,
278: accountNumber);
279: if ((subAccountNumber != null)
280: && (subAccountNumber.length() > 0)) {
281: if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
282: expenseTransfers.add(bbc);
283: }
284: } else {
285: expenseTransfers.add(bbc);
286: }
287: }
288:
289: // Add up variances
290: income
291: .getDummyBusinessObject()
292: .setGenericAmount(
293: income
294: .getAccountLineActualsBalanceAmount()
295: .add(
296: income
297: .getAccountLineEncumbranceBalanceAmount())
298: .subtract(
299: income
300: .getCurrentBudgetLineBalanceAmount()));
301: incomeTransfers
302: .getDummyBusinessObject()
303: .setGenericAmount(
304: incomeTransfers
305: .getAccountLineActualsBalanceAmount()
306: .add(
307: incomeTransfers
308: .getAccountLineEncumbranceBalanceAmount())
309: .subtract(
310: incomeTransfers
311: .getCurrentBudgetLineBalanceAmount()));
312: incomeTotal.getDummyBusinessObject().setGenericAmount(
313: income.getDummyBusinessObject().getGenericAmount().add(
314: incomeTransfers.getDummyBusinessObject()
315: .getGenericAmount()));
316:
317: expense
318: .getDummyBusinessObject()
319: .setGenericAmount(
320: expense
321: .getCurrentBudgetLineBalanceAmount()
322: .subtract(
323: expense
324: .getAccountLineActualsBalanceAmount())
325: .subtract(
326: expense
327: .getAccountLineEncumbranceBalanceAmount()));
328: expenseTransfers
329: .getDummyBusinessObject()
330: .setGenericAmount(
331: expenseTransfers
332: .getCurrentBudgetLineBalanceAmount()
333: .subtract(
334: expenseTransfers
335: .getAccountLineActualsBalanceAmount())
336: .subtract(
337: expenseTransfers
338: .getAccountLineEncumbranceBalanceAmount()));
339: expenseTotal.getDummyBusinessObject().setGenericAmount(
340: expense.getDummyBusinessObject().getGenericAmount()
341: .add(
342: expenseTransfers
343: .getDummyBusinessObject()
344: .getGenericAmount()));
345:
346: total.getDummyBusinessObject().setGenericAmount(
347: incomeTotal.getDummyBusinessObject().getGenericAmount()
348: .add(
349: expenseTotal.getDummyBusinessObject()
350: .getGenericAmount()));
351:
352: return results;
353: }
354:
355: /**
356: * Takes an account balance and, depending on the objec type, adds it to the expense total or the income total account balance
357: *
358: * @param accountBalance the account balance to add to the totals
359: * @param incomeTotal the account balance holding totals for income
360: * @param expenseTotal the account balance holding totals for expense
361: */
362: private void addBalanceToTotals(AccountBalance accountBalance,
363: AccountBalance incomeTotal, AccountBalance expenseTotal) {
364: String reportingSortCode = accountBalance.getFinancialObject()
365: .getFinancialObjectType()
366: .getFinancialReportingSortCode();
367:
368: if (reportingSortCode
369: .startsWith(Constant.START_CHAR_OF_REPORTING_SORT_CODE_B)) {
370: expenseTotal.add(accountBalance);
371: } else {
372: incomeTotal.add(accountBalance);
373: }
374: }
375:
376: /**
377: * Finds account balances grouped by object level
378: *
379: * @param universityFiscalYear the fiscal year account to find account balances for
380: * @param chartOfAccountsCode the chart of accounts code to find account balances for
381: * @param accountNumber the account number to find account balances for
382: * @param subAccountNumber the sub account number to find account balances for
383: * @param financialConsolidationCode the consolidation code to find account balances for
384: * @param isCostShareExcluded should account balances found have cost share information excluded?
385: * @param isConsolidated should account balances found be consolidated?
386: * @param pendingEntryCode should pending entries be included in the query?
387: * @return a List of qualifying account balance records
388: * @see org.kuali.module.gl.service.AccountBalanceService#findAccountBalanceByLevel(java.lang.Integer, java.lang.String,
389: * java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int)
390: */
391: public List findAccountBalanceByLevel(Integer universityFiscalYear,
392: String chartOfAccountsCode, String accountNumber,
393: String subAccountNumber,
394: String financialConsolidationObjectCode,
395: boolean isCostShareExcluded, boolean isConsolidated,
396: int pendingEntryCode) {
397: LOG.debug("findAccountBalanceByLevel() started");
398:
399: List results = new ArrayList();
400:
401: // If you want a sub account, you can't do consolidated
402: if ((subAccountNumber != null)
403: && (subAccountNumber.length() > 0)) {
404: subAccountNumber = subAccountNumber.toUpperCase();
405: isConsolidated = false;
406: }
407:
408: // Get the data
409: List balances = accountBalanceDao.findAccountBalanceByLevel(
410: universityFiscalYear, chartOfAccountsCode,
411: accountNumber, financialConsolidationObjectCode,
412: isCostShareExcluded, isConsolidated, pendingEntryCode);
413:
414: // Convert it to Account Balances
415: for (Iterator iter = balances.iterator(); iter.hasNext();) {
416: Map bal = (Map) iter.next();
417: bal.put(GLConstants.ColumnNames.CONSOLIDATION_OBJECT_CODE,
418: financialConsolidationObjectCode);
419: AccountBalance bbc = new AccountBalance(
420: AccountBalance.TYPE_LEVEL, bal,
421: universityFiscalYear, chartOfAccountsCode,
422: accountNumber);
423: if ((subAccountNumber != null)
424: && (subAccountNumber.length() > 0)) {
425: if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
426: results.add(bbc);
427: }
428: } else {
429: results.add(bbc);
430: }
431: }
432:
433: return results;
434: }
435:
436: /**
437: * Finds account balances that match the qualifying parameters, grouped by object code
438: *
439: * @param universityFiscalYear the fiscal year account to find account balances for
440: * @param chartOfAccountsCode the chart of accounts code to find account balances for
441: * @param accountNumber the account number to find account balances for
442: * @param subAccountNumber the sub account number to find account balances for
443: * @param financialObjectLevelCode the financial object level code to find account balances for
444: * @param financialReportingSortCode the reporting sort code to sort account balances by
445: * @param isCostShareExcluded should account balances found have cost share information excluded?
446: * @param isConsolidated should account balances found be consolidated?
447: * @param pendingEntryCode should pending entries be included in the query?
448: * @return a List of qualifying account balance records
449: * @see org.kuali.module.gl.service.AccountBalanceService#findAccountBalanceByObject(java.lang.Integer, java.lang.String,
450: * java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int)
451: */
452: public List findAccountBalanceByObject(
453: Integer universityFiscalYear, String chartOfAccountsCode,
454: String accountNumber, String subAccountNumber,
455: String financialObjectLevelCode,
456: String financialReportingSortCode,
457: boolean isCostShareExcluded, boolean isConsolidated,
458: int pendingEntryCode) {
459: LOG.debug("findAccountBalanceByObject() started");
460:
461: List results = new ArrayList();
462:
463: // If you want a sub account, you can't do consolidated
464: if ((subAccountNumber != null)
465: && (subAccountNumber.length() > 0)) {
466: subAccountNumber = subAccountNumber.toUpperCase();
467: isConsolidated = false;
468: }
469:
470: // Get the data
471: List balances = accountBalanceDao.findAccountBalanceByObject(
472: universityFiscalYear, chartOfAccountsCode,
473: accountNumber, financialObjectLevelCode,
474: financialReportingSortCode, isCostShareExcluded,
475: isConsolidated, pendingEntryCode);
476:
477: // Convert it to Account Balances
478: for (Iterator iter = balances.iterator(); iter.hasNext();) {
479: Map bal = (Map) iter.next();
480: bal.put(GLConstants.ColumnNames.OBJECT_LEVEL_CODE,
481: financialObjectLevelCode);
482: AccountBalance bbc = new AccountBalance(
483: AccountBalance.TYPE_OBJECT, bal,
484: universityFiscalYear, chartOfAccountsCode,
485: accountNumber);
486: if ((subAccountNumber != null)
487: && (subAccountNumber.length() > 0)) {
488: if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
489: results.add(bbc);
490: }
491: } else {
492: results.add(bbc);
493: }
494: }
495:
496: return results;
497: }
498:
499: /**
500: * Defers to the DAO to save the account balance.
501: *
502: * @param ab account balance record to save
503: * @see org.kuali.module.gl.service.AccountBalanceService#save(org.kuali.module.gl.bo.AccountBalance)
504: */
505: public void save(AccountBalance ab) {
506: accountBalanceDao.save(ab);
507: }
508:
509: /**
510: * Purge an entire fiscal year for a single chart.
511: *
512: * @param chartOfAccountsCode the chart of accounts of account balances to purge
513: * @param year the fiscal year of account balances to purge
514: */
515: public void purgeYearByChart(String chartOfAccountsCode, int year) {
516: LOG.debug("purgeYearByChart() started");
517:
518: accountBalanceDao.purgeYearByChart(chartOfAccountsCode, year);
519: }
520:
521: /**
522: * This method gets the number of the available account balances according to input fields and values
523: *
524: * @param fieldValues the input fields and values
525: * @param isConsolidated determine whether the search results are consolidated
526: * @return the number of the available account balances
527: * @see org.kuali.module.gl.service.AccountBalanceService#getAvailableAccountBalanceCount(java.util.Map, boolean)
528: */
529: public Integer getAvailableAccountBalanceCount(Map fieldValues,
530: boolean isConsolidated) {
531: Integer recordCount = null;
532: if (!isConsolidated) {
533: recordCount = OJBUtility.getResultSizeFromMap(fieldValues,
534: new AccountBalance()).intValue();
535: } else {
536: Iterator recordCountIterator = accountBalanceDao
537: .findConsolidatedAvailableAccountBalance(fieldValues);
538: // TODO: WL: why build a list and waste time/memory when we can just iterate through the iterator and do a count?
539: List recordCountList = IteratorUtils
540: .toList(recordCountIterator);
541: recordCount = recordCountList.size();
542: }
543: return recordCount;
544: }
545:
546: public void setKualiConfigurationService(
547: KualiConfigurationService kcs) {
548: kualiConfigurationService = kcs;
549: }
550:
551: public void setAccountBalanceDao(AccountBalanceDao accountBalanceDao) {
552: this.accountBalanceDao = accountBalanceDao;
553: }
554: }
|