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 }