View Javadoc
1   /*
2    * Copyright 2006 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.service.impl;
17  
18  import java.util.ArrayList;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.collections.IteratorUtils;
24  import org.kuali.ole.coa.service.ObjectTypeService;
25  import org.kuali.ole.gl.GeneralLedgerConstants;
26  import org.kuali.ole.gl.OJBUtility;
27  import org.kuali.ole.gl.businessobject.AccountBalance;
28  import org.kuali.ole.gl.dataaccess.AccountBalanceDao;
29  import org.kuali.ole.gl.service.AccountBalanceService;
30  import org.kuali.ole.sys.OLEKeyConstants;
31  import org.kuali.ole.sys.businessobject.SystemOptions;
32  import org.kuali.ole.sys.businessobject.UniversityDate;
33  import org.kuali.ole.sys.context.SpringContext;
34  import org.kuali.ole.sys.service.OptionsService;
35  import org.kuali.ole.sys.service.UniversityDateService;
36  import org.kuali.rice.core.api.config.property.ConfigurationService;
37  import org.kuali.rice.krad.service.BusinessObjectService;
38  import org.springframework.transaction.annotation.Transactional;
39  
40  /**
41   * The basic implementation of the AccountBalanceService interface
42   */
43  @Transactional
44  public class AccountBalanceServiceImpl implements AccountBalanceService {
45      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccountBalanceServiceImpl.class);
46  
47      AccountBalanceDao accountBalanceDao;
48      ConfigurationService kualiConfigurationService;
49      protected UniversityDateService universityDateService;
50      protected OptionsService optionsService;
51  
52      /**
53       * Defers to the DAO to find the consolidated account balances, based on the keys given in the Map parameter
54       * 
55       * @param fieldValues the input fields and values
56       * @return the summary records of account balance entries
57       * @see org.kuali.ole.gl.service.AccountBalanceService#findConsolidatedAvailableAccountBalance(java.util.Map)
58       */
59      public Iterator findConsolidatedAvailableAccountBalance(Map fieldValues) {
60          LOG.debug("findConsolidatedAvailableAccountBalance() started");
61  
62          return accountBalanceDao.findConsolidatedAvailableAccountBalance(fieldValues);
63      }
64  
65      /**
66       * Given the map of parameters, constructs a query to find all qualifying account balance records
67       * 
68       * @param fieldValues the input fields and values
69       * @param isConsolidated determine whether the search results are consolidated
70       * @return a collection of account balance entries
71       * @see org.kuali.ole.gl.service.AccountBalanceService#findAvailableAccountBalance(java.util.Map)
72       */
73      public Iterator findAvailableAccountBalance(Map fieldValues) {
74          LOG.debug("findAvailableAccountBalance() started");
75  
76          return accountBalanceDao.findAvailableAccountBalance(fieldValues);
77      }
78  
79      /**
80       * This finds account balances grouped by consolidation
81       * 
82       * @param universityFiscalYear the fiscal year account to find account balances for
83       * @param chartOfAccountsCode the chart of accounts code to find account balances for
84       * @param accountNumber the account number to find account balances for
85       * @param subAccountNumber the sub account number to find account balances for
86       * @param isCostShareExcluded should account balances found have cost share information excluded?
87       * @param isConsolidated should account balances found be consolidated?
88       * @param pendingEntryCode should pending entries be included in the query?
89       * @return a List of qualifying account balance records
90       * @see org.kuali.ole.gl.service.AccountBalanceService#findAccountBalanceByConsolidation(java.util.Map, boolean, boolean)
91       */
92      public List findAccountBalanceByConsolidation(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String subAccountNumber, boolean isCostShareExcluded, boolean isConsolidated, int pendingEntryCode) {
93          LOG.debug("findAccountBalanceByConsolidation() started");
94  
95          ObjectTypeService objectTypeService = (ObjectTypeService) SpringContext.getBean(ObjectTypeService.class);
96  
97          String[] incomeObjectTypes = objectTypeService.getBasicIncomeObjectTypes(universityFiscalYear).toArray(new String[0]);
98          String[] incomeTransferObjectTypes = { objectTypeService.getIncomeTransferObjectType(universityFiscalYear) };
99          String[] expenseObjectTypes = objectTypeService.getBasicExpenseObjectTypes(universityFiscalYear).toArray(new String[0]);
100         String[] expenseTransferObjectTypes = { objectTypeService.getExpenseTransferObjectType(universityFiscalYear) };
101 
102         // Consolidate all object types into one array (yes I could have used lists, but it was just as many lines of code than
103         // this)
104         String[] allObjectTypes = new String[incomeObjectTypes.length + incomeTransferObjectTypes.length + expenseObjectTypes.length + expenseTransferObjectTypes.length];
105         int count = 0;
106         for (int i = 0; i < incomeObjectTypes.length; i++) {
107             allObjectTypes[count++] = incomeObjectTypes[i];
108         }
109         for (int i = 0; i < incomeTransferObjectTypes.length; i++) {
110             allObjectTypes[count++] = incomeTransferObjectTypes[i];
111         }
112         for (int i = 0; i < expenseObjectTypes.length; i++) {
113             allObjectTypes[count++] = expenseObjectTypes[i];
114         }
115         for (int i = 0; i < expenseTransferObjectTypes.length; i++) {
116             allObjectTypes[count++] = expenseTransferObjectTypes[i];
117         }
118 
119         // Put the total lines at the beginning of the list
120         List results = new ArrayList();
121         AccountBalance income = new AccountBalance(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME));
122         AccountBalance incomeTransfers = new AccountBalance(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME_FROM_TRANSFERS));
123         AccountBalance incomeTotal = new AccountBalance(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME_TOTAL));
124         AccountBalance expense = new AccountBalance(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE));
125         AccountBalance expenseTransfers = new AccountBalance(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE_FROM_TRANSFERS));
126         AccountBalance expenseTotal = new AccountBalance(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE_TOTAL));
127         AccountBalance total = new AccountBalance(kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.TOTAL));
128 
129         results.add(income);
130         results.add(incomeTransfers);
131         results.add(incomeTotal);
132         results.add(expense);
133         results.add(expenseTransfers);
134         results.add(expenseTotal);
135         results.add(total);
136 
137         // If you want a sub account, you can't do consolidated
138         if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
139             subAccountNumber = subAccountNumber.toUpperCase();
140             isConsolidated = false;
141         }
142 
143         SystemOptions options = optionsService.getOptions(universityFiscalYear);
144         UniversityDate today = universityDateService.getCurrentUniversityDate();
145         // Get the data
146         List balances = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(allObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode, options, today);
147 
148         // Convert it to Account Balances
149         for (Iterator iter = balances.iterator(); iter.hasNext();) {
150             Map bal = (Map) iter.next();
151             AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
152 
153             if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
154                 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
155                     results.add(bbc);
156                 }
157             }
158             else {
159                 results.add(bbc);
160             }
161         }
162 
163         // Calculate totals
164 
165         // Get balances for these parameters, then based on the object type code, put balances into the correct summary line
166         List data = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(incomeObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode, options, today);
167         for (Iterator iter = data.iterator(); iter.hasNext();) {
168             Map bal = (Map) iter.next();
169             AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
170             if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
171                 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
172                     income.add(bbc);
173                     incomeTotal.add(bbc);
174                 }
175             }
176             else {
177                 String transferExpenseCode = bbc.getFinancialObject().getFinancialObjectLevel().getFinancialConsolidationObject().getFinConsolidationObjectCode();
178                 if (transferExpenseCode.equals(GeneralLedgerConstants.INCOME_OR_EXPENSE_TRANSFER_CONSOLIDATION_CODE)) {
179                     incomeTransfers.add(bbc);
180                     incomeTotal.add(bbc);
181                 }
182                 else {
183                     income.add(bbc);
184                     incomeTotal.add(bbc);
185                 }
186             }
187         }
188 
189         data = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(incomeTransferObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode, options, today);
190         for (Iterator iter = data.iterator(); iter.hasNext();) {
191             Map bal = (Map) iter.next();
192             AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
193             if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
194                 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
195                     incomeTransfers.add(bbc);
196                     incomeTotal.add(bbc);
197                 }
198             }
199             else {
200                 incomeTransfers.add(bbc);
201                 incomeTotal.add(bbc);
202             }
203         }
204 
205         data = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(expenseObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode, options, today);
206         for (Iterator iter = data.iterator(); iter.hasNext();) {
207             Map bal = (Map) iter.next();
208             AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
209             if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
210                 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
211                     expense.add(bbc);
212                     expenseTotal.add(bbc);
213                 }
214             }
215             else {
216                 String transferExpenseCode = bbc.getFinancialObject().getFinancialObjectLevel().getFinancialConsolidationObject().getFinConsolidationObjectCode();
217                 if (transferExpenseCode.equals(GeneralLedgerConstants.INCOME_OR_EXPENSE_TRANSFER_CONSOLIDATION_CODE)) {
218                     expenseTransfers.add(bbc);
219                     expenseTotal.add(bbc);
220                 }
221                 else {
222                     expense.add(bbc);
223                     expenseTotal.add(bbc);
224                 }
225             }
226         }
227 
228         data = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(expenseTransferObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode, options, today);
229         for (Iterator iter = data.iterator(); iter.hasNext();) {
230             Map bal = (Map) iter.next();
231             AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
232             if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
233                 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
234                     expenseTransfers.add(bbc);
235                     expenseTotal.add(bbc);
236                 }
237             }
238             else {
239                 expenseTransfers.add(bbc);
240                 expenseTotal.add(bbc);
241             }
242         }
243 
244         // Add up variances
245         income.getDummyBusinessObject().setGenericAmount(income.getAccountLineActualsBalanceAmount().add(income.getAccountLineEncumbranceBalanceAmount()).subtract(income.getCurrentBudgetLineBalanceAmount()));
246         incomeTransfers.getDummyBusinessObject().setGenericAmount(incomeTransfers.getAccountLineActualsBalanceAmount().add(incomeTransfers.getAccountLineEncumbranceBalanceAmount()).subtract(incomeTransfers.getCurrentBudgetLineBalanceAmount()));
247         incomeTotal.getDummyBusinessObject().setGenericAmount(income.getDummyBusinessObject().getGenericAmount().add(incomeTransfers.getDummyBusinessObject().getGenericAmount()));
248 
249         expense.getDummyBusinessObject().setGenericAmount(expense.getCurrentBudgetLineBalanceAmount().subtract(expense.getAccountLineActualsBalanceAmount()).subtract(expense.getAccountLineEncumbranceBalanceAmount()));
250         expenseTransfers.getDummyBusinessObject().setGenericAmount(expenseTransfers.getCurrentBudgetLineBalanceAmount().subtract(expenseTransfers.getAccountLineActualsBalanceAmount()).subtract(expenseTransfers.getAccountLineEncumbranceBalanceAmount()));
251         expenseTotal.getDummyBusinessObject().setGenericAmount(expense.getDummyBusinessObject().getGenericAmount().add(expenseTransfers.getDummyBusinessObject().getGenericAmount()));
252 
253         total.getDummyBusinessObject().setGenericAmount(incomeTotal.getDummyBusinessObject().getGenericAmount().add(expenseTotal.getDummyBusinessObject().getGenericAmount()));
254 
255         return results;
256     }
257 
258     /**
259      * Finds account balances grouped by object level
260      * 
261      * @param universityFiscalYear the fiscal year account to find account balances for
262      * @param chartOfAccountsCode the chart of accounts code to find account balances for
263      * @param accountNumber the account number to find account balances for
264      * @param subAccountNumber the sub account number to find account balances for
265      * @param financialConsolidationCode the consolidation code to find account balances for
266      * @param isCostShareExcluded should account balances found have cost share information excluded?
267      * @param isConsolidated should account balances found be consolidated?
268      * @param pendingEntryCode should pending entries be included in the query?
269      * @return a List of qualifying account balance records
270      * @see org.kuali.ole.gl.service.AccountBalanceService#findAccountBalanceByLevel(java.lang.Integer, java.lang.String,
271      *      java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int)
272      */
273     public List findAccountBalanceByLevel(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String subAccountNumber, String financialConsolidationObjectCode, boolean isCostShareExcluded, boolean isConsolidated, int pendingEntryCode) {
274         LOG.debug("findAccountBalanceByLevel() started");
275 
276         List results = new ArrayList();
277 
278         // If you want a sub account, you can't do consolidated
279         if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
280             subAccountNumber = subAccountNumber.toUpperCase();
281             isConsolidated = false;
282         }
283 
284         // Get the data
285         UniversityDate today = universityDateService.getCurrentUniversityDate();
286         SystemOptions options = optionsService.getOptions(universityFiscalYear);
287         List balances = accountBalanceDao.findAccountBalanceByLevel(universityFiscalYear, chartOfAccountsCode, accountNumber, financialConsolidationObjectCode, isCostShareExcluded, isConsolidated, pendingEntryCode, today, options);
288 
289         // Convert it to Account Balances
290         for (Iterator iter = balances.iterator(); iter.hasNext();) {
291             Map bal = (Map) iter.next();
292             bal.put(GeneralLedgerConstants.ColumnNames.CONSOLIDATION_OBJECT_CODE, financialConsolidationObjectCode);
293             AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_LEVEL, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
294             if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
295                 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
296                     results.add(bbc);
297                 }
298             }
299             else {
300                 results.add(bbc);
301             }
302         }
303 
304         return results;
305     }
306 
307     /**
308      * Finds account balances that match the qualifying parameters, grouped by object code
309      * 
310      * @param universityFiscalYear the fiscal year account to find account balances for
311      * @param chartOfAccountsCode the chart of accounts code to find account balances for
312      * @param accountNumber the account number to find account balances for
313      * @param subAccountNumber the sub account number to find account balances for
314      * @param financialObjectLevelCode the financial object level code to find account balances for
315      * @param financialReportingSortCode the reporting sort code to sort account balances by
316      * @param isCostShareExcluded should account balances found have cost share information excluded?
317      * @param isConsolidated should account balances found be consolidated?
318      * @param pendingEntryCode should pending entries be included in the query?
319      * @return a List of qualifying account balance records
320      * @see org.kuali.ole.gl.service.AccountBalanceService#findAccountBalanceByObject(java.lang.Integer, java.lang.String,
321      *      java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int)
322      */
323     public List findAccountBalanceByObject(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String subAccountNumber, String financialObjectLevelCode, String financialReportingSortCode, boolean isCostShareExcluded, boolean isConsolidated, int pendingEntryCode) {
324         LOG.debug("findAccountBalanceByObject() started");
325 
326         List results = new ArrayList();
327 
328         // If you want a sub account, you can't do consolidated
329         if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
330             subAccountNumber = subAccountNumber.toUpperCase();
331             isConsolidated = false;
332         }
333 
334         // Get the data
335         UniversityDate today = universityDateService.getCurrentUniversityDate();
336         SystemOptions options = optionsService.getOptions(universityFiscalYear);
337         List balances = accountBalanceDao.findAccountBalanceByObject(universityFiscalYear, chartOfAccountsCode, accountNumber, financialObjectLevelCode, financialReportingSortCode, isCostShareExcluded, isConsolidated, pendingEntryCode, today, options);
338 
339         // Convert it to Account Balances
340         for (Iterator iter = balances.iterator(); iter.hasNext();) {
341             Map bal = (Map) iter.next();
342             bal.put(GeneralLedgerConstants.ColumnNames.OBJECT_LEVEL_CODE, financialObjectLevelCode);
343             AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_OBJECT, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
344             if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
345                 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
346                     results.add(bbc);
347                 }
348             }
349             else {
350                 results.add(bbc);
351             }
352         }
353 
354         return results;
355     }
356 
357     /**
358      * Defers to the DAO to save the account balance.
359      * 
360      * @param ab account balance record to save
361      * @see org.kuali.ole.gl.service.AccountBalanceService#save(org.kuali.ole.gl.businessobject.AccountBalance)
362      */
363     public void save(AccountBalance ab) {
364         SpringContext.getBean(BusinessObjectService.class).save(ab);
365     }
366 
367     /**
368      * Purge an entire fiscal year for a single chart.
369      * 
370      * @param chartOfAccountsCode the chart of accounts of account balances to purge
371      * @param year the fiscal year of account balances to purge
372      */
373     public void purgeYearByChart(String chartOfAccountsCode, int year) {
374         LOG.debug("purgeYearByChart() started");
375 
376         accountBalanceDao.purgeYearByChart(chartOfAccountsCode, year);
377     }
378 
379     /**
380      * This method gets the number of the available account balances according to input fields and values
381      * 
382      * @param fieldValues the input fields and values
383      * @param isConsolidated determine whether the search results are consolidated
384      * @return the number of the available account balances
385      * @see org.kuali.ole.gl.service.AccountBalanceService#getAvailableAccountBalanceCount(java.util.Map, boolean)
386      */
387     public Integer getAvailableAccountBalanceCount(Map fieldValues, boolean isConsolidated) {
388         Integer recordCount = null;
389         if (!isConsolidated) {
390             recordCount = OJBUtility.getResultSizeFromMap(fieldValues, new AccountBalance()).intValue();
391         }
392         else {
393             Iterator recordCountIterator = accountBalanceDao.findConsolidatedAvailableAccountBalance(fieldValues);
394             // TODO: WL: why build a list and waste time/memory when we can just iterate through the iterator and do a count?
395             List recordCountList = IteratorUtils.toList(recordCountIterator);
396             recordCount = recordCountList.size();
397         }
398         return recordCount;
399     }
400 
401     /**
402      * @param kcs
403      */
404     public void setConfigurationService(ConfigurationService kcs) {
405         kualiConfigurationService = kcs;
406     }
407 
408     /**
409      * @param accountBalanceDao
410      */
411     public void setAccountBalanceDao(AccountBalanceDao accountBalanceDao) {
412         this.accountBalanceDao = accountBalanceDao;
413     }
414 
415     /**
416      * @param universityDateService
417      */
418     public void setUniversityDateService(UniversityDateService universityDateService) {
419         this.universityDateService = universityDateService;
420     }
421 
422     /**
423      * Sets the optionsService.
424      * 
425      * @param optionsService
426      */
427     public void setOptionsService(OptionsService optionsService) {
428         this.optionsService = optionsService;
429     }
430 }