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.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.kfs.coa.service.ObjectTypeService;
025 import org.kuali.kfs.gl.GeneralLedgerConstants;
026 import org.kuali.kfs.gl.OJBUtility;
027 import org.kuali.kfs.gl.businessobject.AccountBalance;
028 import org.kuali.kfs.gl.dataaccess.AccountBalanceDao;
029 import org.kuali.kfs.gl.service.AccountBalanceService;
030 import org.kuali.kfs.sys.KFSKeyConstants;
031 import org.kuali.kfs.sys.context.SpringContext;
032 import org.kuali.rice.kns.service.KualiConfigurationService;
033 import org.springframework.transaction.annotation.Transactional;
034
035 /**
036 * The basic implementation of the AccountBalanceService interface
037 */
038 @Transactional
039 public class AccountBalanceServiceImpl implements AccountBalanceService {
040 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccountBalanceServiceImpl.class);
041
042 AccountBalanceDao accountBalanceDao;
043 KualiConfigurationService kualiConfigurationService;
044
045 /**
046 * Defers to the DAO to find the consolidated account balances, based on the keys given in the Map parameter
047 *
048 * @param fieldValues the input fields and values
049 * @return the summary records of account balance entries
050 * @see org.kuali.kfs.gl.service.AccountBalanceService#findConsolidatedAvailableAccountBalance(java.util.Map)
051 */
052 public Iterator findConsolidatedAvailableAccountBalance(Map fieldValues) {
053 LOG.debug("findConsolidatedAvailableAccountBalance() started");
054
055 return accountBalanceDao.findConsolidatedAvailableAccountBalance(fieldValues);
056 }
057
058 /**
059 * Given the map of parameters, constructs a query to find all qualifying account balance records
060 *
061 * @param fieldValues the input fields and values
062 * @param isConsolidated determine whether the search results are consolidated
063 * @return a collection of account balance entries
064 * @see org.kuali.kfs.gl.service.AccountBalanceService#findAvailableAccountBalance(java.util.Map)
065 */
066 public Iterator findAvailableAccountBalance(Map fieldValues) {
067 LOG.debug("findAvailableAccountBalance() started");
068
069 return accountBalanceDao.findAvailableAccountBalance(fieldValues);
070 }
071
072 /**
073 * This finds account balances grouped by consolidation
074 *
075 * @param universityFiscalYear the fiscal year account to find account balances for
076 * @param chartOfAccountsCode the chart of accounts code to find account balances for
077 * @param accountNumber the account number to find account balances for
078 * @param subAccountNumber the sub account number to find account balances for
079 * @param isCostShareExcluded should account balances found have cost share information excluded?
080 * @param isConsolidated should account balances found be consolidated?
081 * @param pendingEntryCode should pending entries be included in the query?
082 * @return a List of qualifying account balance records
083 * @see org.kuali.kfs.gl.service.AccountBalanceService#findAccountBalanceByConsolidation(java.util.Map, boolean, boolean)
084 */
085 public List findAccountBalanceByConsolidation(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String subAccountNumber, boolean isCostShareExcluded, boolean isConsolidated, int pendingEntryCode) {
086 LOG.debug("findAccountBalanceByConsolidation() started");
087
088 ObjectTypeService objectTypeService = (ObjectTypeService) SpringContext.getBean(ObjectTypeService.class);
089
090 String[] incomeObjectTypes = objectTypeService.getBasicIncomeObjectTypes(universityFiscalYear).toArray(new String[0]);
091 String[] incomeTransferObjectTypes = { objectTypeService.getIncomeTransferObjectType(universityFiscalYear) };
092 String[] expenseObjectTypes = objectTypeService.getBasicExpenseObjectTypes(universityFiscalYear).toArray(new String[0]);
093 String[] expenseTransferObjectTypes = { objectTypeService.getExpenseTransferObjectType(universityFiscalYear) };
094
095 // Consolidate all object types into one array (yes I could have used lists, but it was just as many lines of code than
096 // this)
097 String[] allObjectTypes = new String[incomeObjectTypes.length + incomeTransferObjectTypes.length + expenseObjectTypes.length + expenseTransferObjectTypes.length];
098 int count = 0;
099 for (int i = 0; i < incomeObjectTypes.length; i++) {
100 allObjectTypes[count++] = incomeObjectTypes[i];
101 }
102 for (int i = 0; i < incomeTransferObjectTypes.length; i++) {
103 allObjectTypes[count++] = incomeTransferObjectTypes[i];
104 }
105 for (int i = 0; i < expenseObjectTypes.length; i++) {
106 allObjectTypes[count++] = expenseObjectTypes[i];
107 }
108 for (int i = 0; i < expenseTransferObjectTypes.length; i++) {
109 allObjectTypes[count++] = expenseTransferObjectTypes[i];
110 }
111
112 // Put the total lines at the beginning of the list
113 List results = new ArrayList();
114 AccountBalance income = new AccountBalance(kualiConfigurationService.getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME));
115 AccountBalance incomeTransfers = new AccountBalance(kualiConfigurationService.getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME_FROM_TRANSFERS));
116 AccountBalance incomeTotal = new AccountBalance(kualiConfigurationService.getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME_TOTAL));
117 AccountBalance expense = new AccountBalance(kualiConfigurationService.getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE));
118 AccountBalance expenseTransfers = new AccountBalance(kualiConfigurationService.getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE_FROM_TRANSFERS));
119 AccountBalance expenseTotal = new AccountBalance(kualiConfigurationService.getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE_TOTAL));
120 AccountBalance total = new AccountBalance(kualiConfigurationService.getPropertyString(KFSKeyConstants.AccountBalanceService.TOTAL));
121
122 results.add(income);
123 results.add(incomeTransfers);
124 results.add(incomeTotal);
125 results.add(expense);
126 results.add(expenseTransfers);
127 results.add(expenseTotal);
128 results.add(total);
129
130 // If you want a sub account, you can't do consolidated
131 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
132 subAccountNumber = subAccountNumber.toUpperCase();
133 isConsolidated = false;
134 }
135
136 // Get the data
137 List balances = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(allObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode);
138
139 // Convert it to Account Balances
140 for (Iterator iter = balances.iterator(); iter.hasNext();) {
141 Map bal = (Map) iter.next();
142 AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
143
144 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
145 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
146 results.add(bbc);
147 }
148 }
149 else {
150 results.add(bbc);
151 }
152 }
153
154 // Calculate totals
155
156 // Get balances for these parameters, then based on the object type code, put balances into the correct summary line
157 List data = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(incomeObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode);
158 for (Iterator iter = data.iterator(); iter.hasNext();) {
159 Map bal = (Map) iter.next();
160 AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
161 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
162 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
163 income.add(bbc);
164 incomeTotal.add(bbc);
165 }
166 }
167 else {
168 String transferExpenseCode = bbc.getFinancialObject().getFinancialObjectLevel().getFinancialConsolidationObject().getFinConsolidationObjectCode();
169 if (transferExpenseCode.equals(GeneralLedgerConstants.INCOME_OR_EXPENSE_TRANSFER_CONSOLIDATION_CODE)) {
170 incomeTransfers.add(bbc);
171 incomeTotal.add(bbc);
172 }
173 else {
174 income.add(bbc);
175 incomeTotal.add(bbc);
176 }
177 }
178 }
179
180 data = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(incomeTransferObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode);
181 for (Iterator iter = data.iterator(); iter.hasNext();) {
182 Map bal = (Map) iter.next();
183 AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
184 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
185 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
186 incomeTransfers.add(bbc);
187 incomeTotal.add(bbc);
188 }
189 }
190 else {
191 incomeTransfers.add(bbc);
192 incomeTotal.add(bbc);
193 }
194 }
195
196 data = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(expenseObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode);
197 for (Iterator iter = data.iterator(); iter.hasNext();) {
198 Map bal = (Map) iter.next();
199 AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
200 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
201 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
202 expense.add(bbc);
203 expenseTotal.add(bbc);
204 }
205 }
206 else {
207 String transferExpenseCode = bbc.getFinancialObject().getFinancialObjectLevel().getFinancialConsolidationObject().getFinConsolidationObjectCode();
208 if (transferExpenseCode.equals(GeneralLedgerConstants.INCOME_OR_EXPENSE_TRANSFER_CONSOLIDATION_CODE)) {
209 expenseTransfers.add(bbc);
210 expenseTotal.add(bbc);
211 }
212 else {
213 expense.add(bbc);
214 expenseTotal.add(bbc);
215 }
216 }
217 }
218
219 data = accountBalanceDao.findAccountBalanceByConsolidationByObjectTypes(expenseTransferObjectTypes, universityFiscalYear, chartOfAccountsCode, accountNumber, isCostShareExcluded, isConsolidated, pendingEntryCode);
220 for (Iterator iter = data.iterator(); iter.hasNext();) {
221 Map bal = (Map) iter.next();
222 AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_CONSOLIDATION, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
223 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
224 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
225 expenseTransfers.add(bbc);
226 expenseTotal.add(bbc);
227 }
228 }
229 else {
230 expenseTransfers.add(bbc);
231 expenseTotal.add(bbc);
232 }
233 }
234
235 // Add up variances
236 income.getDummyBusinessObject().setGenericAmount(income.getAccountLineActualsBalanceAmount().add(income.getAccountLineEncumbranceBalanceAmount()).subtract(income.getCurrentBudgetLineBalanceAmount()));
237 incomeTransfers.getDummyBusinessObject().setGenericAmount(incomeTransfers.getAccountLineActualsBalanceAmount().add(incomeTransfers.getAccountLineEncumbranceBalanceAmount()).subtract(incomeTransfers.getCurrentBudgetLineBalanceAmount()));
238 incomeTotal.getDummyBusinessObject().setGenericAmount(income.getDummyBusinessObject().getGenericAmount().add(incomeTransfers.getDummyBusinessObject().getGenericAmount()));
239
240 expense.getDummyBusinessObject().setGenericAmount(expense.getCurrentBudgetLineBalanceAmount().subtract(expense.getAccountLineActualsBalanceAmount()).subtract(expense.getAccountLineEncumbranceBalanceAmount()));
241 expenseTransfers.getDummyBusinessObject().setGenericAmount(expenseTransfers.getCurrentBudgetLineBalanceAmount().subtract(expenseTransfers.getAccountLineActualsBalanceAmount()).subtract(expenseTransfers.getAccountLineEncumbranceBalanceAmount()));
242 expenseTotal.getDummyBusinessObject().setGenericAmount(expense.getDummyBusinessObject().getGenericAmount().add(expenseTransfers.getDummyBusinessObject().getGenericAmount()));
243
244 total.getDummyBusinessObject().setGenericAmount(incomeTotal.getDummyBusinessObject().getGenericAmount().add(expenseTotal.getDummyBusinessObject().getGenericAmount()));
245
246 return results;
247 }
248
249 /**
250 * Finds account balances grouped by object level
251 *
252 * @param universityFiscalYear the fiscal year account to find account balances for
253 * @param chartOfAccountsCode the chart of accounts code to find account balances for
254 * @param accountNumber the account number to find account balances for
255 * @param subAccountNumber the sub account number to find account balances for
256 * @param financialConsolidationCode the consolidation code to find account balances for
257 * @param isCostShareExcluded should account balances found have cost share information excluded?
258 * @param isConsolidated should account balances found be consolidated?
259 * @param pendingEntryCode should pending entries be included in the query?
260 * @return a List of qualifying account balance records
261 * @see org.kuali.kfs.gl.service.AccountBalanceService#findAccountBalanceByLevel(java.lang.Integer, java.lang.String,
262 * java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int)
263 */
264 public List findAccountBalanceByLevel(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String subAccountNumber, String financialConsolidationObjectCode, boolean isCostShareExcluded, boolean isConsolidated, int pendingEntryCode) {
265 LOG.debug("findAccountBalanceByLevel() started");
266
267 List results = new ArrayList();
268
269 // If you want a sub account, you can't do consolidated
270 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
271 subAccountNumber = subAccountNumber.toUpperCase();
272 isConsolidated = false;
273 }
274
275 // Get the data
276 List balances = accountBalanceDao.findAccountBalanceByLevel(universityFiscalYear, chartOfAccountsCode, accountNumber, financialConsolidationObjectCode, isCostShareExcluded, isConsolidated, pendingEntryCode);
277
278 // Convert it to Account Balances
279 for (Iterator iter = balances.iterator(); iter.hasNext();) {
280 Map bal = (Map) iter.next();
281 bal.put(GeneralLedgerConstants.ColumnNames.CONSOLIDATION_OBJECT_CODE, financialConsolidationObjectCode);
282 AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_LEVEL, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
283 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
284 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
285 results.add(bbc);
286 }
287 }
288 else {
289 results.add(bbc);
290 }
291 }
292
293 return results;
294 }
295
296 /**
297 * Finds account balances that match the qualifying parameters, grouped by object code
298 *
299 * @param universityFiscalYear the fiscal year account to find account balances for
300 * @param chartOfAccountsCode the chart of accounts code to find account balances for
301 * @param accountNumber the account number to find account balances for
302 * @param subAccountNumber the sub account number to find account balances for
303 * @param financialObjectLevelCode the financial object level code to find account balances for
304 * @param financialReportingSortCode the reporting sort code to sort account balances by
305 * @param isCostShareExcluded should account balances found have cost share information excluded?
306 * @param isConsolidated should account balances found be consolidated?
307 * @param pendingEntryCode should pending entries be included in the query?
308 * @return a List of qualifying account balance records
309 * @see org.kuali.kfs.gl.service.AccountBalanceService#findAccountBalanceByObject(java.lang.Integer, java.lang.String,
310 * java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int)
311 */
312 public List findAccountBalanceByObject(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String subAccountNumber, String financialObjectLevelCode, String financialReportingSortCode, boolean isCostShareExcluded, boolean isConsolidated, int pendingEntryCode) {
313 LOG.debug("findAccountBalanceByObject() started");
314
315 List results = new ArrayList();
316
317 // If you want a sub account, you can't do consolidated
318 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
319 subAccountNumber = subAccountNumber.toUpperCase();
320 isConsolidated = false;
321 }
322
323 // Get the data
324 List balances = accountBalanceDao.findAccountBalanceByObject(universityFiscalYear, chartOfAccountsCode, accountNumber, financialObjectLevelCode, financialReportingSortCode, isCostShareExcluded, isConsolidated, pendingEntryCode);
325
326 // Convert it to Account Balances
327 for (Iterator iter = balances.iterator(); iter.hasNext();) {
328 Map bal = (Map) iter.next();
329 bal.put(GeneralLedgerConstants.ColumnNames.OBJECT_LEVEL_CODE, financialObjectLevelCode);
330 AccountBalance bbc = new AccountBalance(AccountBalance.TYPE_OBJECT, bal, universityFiscalYear, chartOfAccountsCode, accountNumber);
331 if ((subAccountNumber != null) && (subAccountNumber.length() > 0)) {
332 if (bbc.getSubAccountNumber().equals(subAccountNumber)) {
333 results.add(bbc);
334 }
335 }
336 else {
337 results.add(bbc);
338 }
339 }
340
341 return results;
342 }
343
344 /**
345 * Defers to the DAO to save the account balance.
346 *
347 * @param ab account balance record to save
348 * @see org.kuali.kfs.gl.service.AccountBalanceService#save(org.kuali.kfs.gl.businessobject.AccountBalance)
349 */
350 public void save(AccountBalance ab) {
351 accountBalanceDao.save(ab);
352 }
353
354 /**
355 * Purge an entire fiscal year for a single chart.
356 *
357 * @param chartOfAccountsCode the chart of accounts of account balances to purge
358 * @param year the fiscal year of account balances to purge
359 */
360 public void purgeYearByChart(String chartOfAccountsCode, int year) {
361 LOG.debug("purgeYearByChart() started");
362
363 accountBalanceDao.purgeYearByChart(chartOfAccountsCode, year);
364 }
365
366 /**
367 * This method gets the number of the available account balances according to input fields and values
368 *
369 * @param fieldValues the input fields and values
370 * @param isConsolidated determine whether the search results are consolidated
371 * @return the number of the available account balances
372 * @see org.kuali.kfs.gl.service.AccountBalanceService#getAvailableAccountBalanceCount(java.util.Map, boolean)
373 */
374 public Integer getAvailableAccountBalanceCount(Map fieldValues, boolean isConsolidated) {
375 Integer recordCount = null;
376 if (!isConsolidated) {
377 recordCount = OJBUtility.getResultSizeFromMap(fieldValues, new AccountBalance()).intValue();
378 }
379 else {
380 Iterator recordCountIterator = accountBalanceDao.findConsolidatedAvailableAccountBalance(fieldValues);
381 // TODO: WL: why build a list and waste time/memory when we can just iterate through the iterator and do a count?
382 List recordCountList = IteratorUtils.toList(recordCountIterator);
383 recordCount = recordCountList.size();
384 }
385 return recordCount;
386 }
387
388 public void setKualiConfigurationService(KualiConfigurationService kcs) {
389 kualiConfigurationService = kcs;
390 }
391
392 public void setAccountBalanceDao(AccountBalanceDao accountBalanceDao) {
393 this.accountBalanceDao = accountBalanceDao;
394 }
395 }