View Javadoc

1   /*
2    * Copyright 2005-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.coa.service.impl;
17  
18  import java.sql.Date;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.commons.collections.IteratorUtils;
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.log4j.Logger;
31  import org.kuali.ole.coa.businessobject.Account;
32  import org.kuali.ole.coa.businessobject.AccountDelegate;
33  import org.kuali.ole.coa.dataaccess.AccountDao;
34  import org.kuali.ole.coa.service.AccountService;
35  import org.kuali.ole.sys.OLEConstants;
36  import org.kuali.ole.sys.OLEConstants.SystemGroupParameterNames;
37  import org.kuali.ole.sys.OLEPropertyConstants;
38  import org.kuali.ole.sys.businessobject.AccountingLine;
39  import org.kuali.ole.sys.context.SpringContext;
40  import org.kuali.ole.sys.service.NonTransactional;
41  import org.kuali.ole.sys.service.impl.OleParameterConstants;
42  import org.kuali.rice.core.api.datetime.DateTimeService;
43  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
44  import org.kuali.rice.kew.api.doctype.DocumentTypeService;
45  import org.kuali.rice.kim.api.identity.Person;
46  import org.kuali.rice.kim.util.KimCommonUtils;
47  import org.kuali.rice.krad.service.BusinessObjectService;
48  import org.kuali.rice.krad.util.ObjectUtils;
49  import org.springframework.cache.annotation.Cacheable;
50  
51  /**
52   * This class is the service implementation for the Account structure. This is the default, Kuali provided implementation.
53   */
54  
55  @NonTransactional
56  public class AccountServiceImpl implements AccountService {
57      private static final Logger LOG = Logger.getLogger(AccountServiceImpl.class);
58  
59      protected ParameterService parameterService;
60      protected AccountDao accountDao;
61      protected DateTimeService dateTimeService;
62      protected DocumentTypeService documentTypeService;
63      protected BusinessObjectService businessObjectService;
64  
65      /**
66       * Retrieves an Account object based on primary key.
67       * 
68       * @param chartOfAccountsCode - Chart of Accounts Code
69       * @param accountNumber - Account Number
70       * @return Account
71       * @see AccountService
72       */
73      @Override
74      @Cacheable(value=Account.CACHE_NAME, key="#p0+'-'+#p1")
75      public Account getByPrimaryId(String chartOfAccountsCode, String accountNumber) {
76          if (LOG.isDebugEnabled()) {
77              LOG.debug("retrieving account by primaryId (" + chartOfAccountsCode + "," + accountNumber + ")");
78          }
79          Map<String, Object> keys = new HashMap<String, Object>(2);
80          keys.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode);
81          keys.put(OLEPropertyConstants.ACCOUNT_NUMBER, accountNumber);
82          Account account = businessObjectService.findByPrimaryKey(Account.class, keys);
83  
84          if (LOG.isDebugEnabled()) {
85              LOG.debug("retrieved account by primaryId (" + chartOfAccountsCode + "," + accountNumber + "): " + account );
86          }
87          return account;
88      }
89  
90      /**
91       * Method is used by KualiAccountAttribute to enable caching of accounts for routing.
92       * 
93       * @see org.kuali.ole.coa.service.impl.AccountServiceImpl#getByPrimaryId(java.lang.String, java.lang.String)
94       */
95      @Override
96      @Cacheable(value=Account.CACHE_NAME, key="#p0+'-'+#p1")
97      public Account getByPrimaryIdWithCaching(String chartOfAccountsCode, String accountNumber) {
98          Account account = getByPrimaryId(chartOfAccountsCode, accountNumber);
99          if ( account != null ) {
100             // force loading of chart reference object
101             account.getChartOfAccounts().getChartOfAccountsCode();
102         }
103         return account;
104     }
105 
106     /**
107      * @see org.kuali.ole.coa.service.AccountService#getAccountsThatUserIsResponsibleFor(org.kuali.bo.user.KualiUser)
108      */
109     @Override
110     @Cacheable(value=Account.CACHE_NAME, key="'ResponsibleForAccounts'+#p0.principalId")
111     public List getAccountsThatUserIsResponsibleFor(Person person) {
112         if (LOG.isDebugEnabled()) {
113             LOG.debug("retrieving accountsResponsible list for user " + person.getName());
114         }
115 
116         // gets the list of accounts that the user is the Fiscal Officer of
117         List accountList = accountDao.getAccountsThatUserIsResponsibleFor(person, dateTimeService.getCurrentDate());
118         if (LOG.isDebugEnabled()) {
119             LOG.debug("retrieved accountsResponsible list for user " + person.getName());
120         }
121         return accountList;
122     }
123 
124     /**
125      * @see org.kuali.ole.coa.service.AccountService#hasResponsibilityOnAccount(org.kuali.rice.kim.api.identity.Person,
126      *      org.kuali.ole.coa.businessobject.Account)
127      */
128     @Override
129     @Cacheable(value=Account.CACHE_NAME, key="'ResponsibilityOnAccount'+#p0.principalId+'-'+#p1.chartOfAccountsCode+'-'+#p1.accountNumber")
130     public boolean hasResponsibilityOnAccount(Person kualiUser, Account account) {
131         return accountDao.determineUserResponsibilityOnAccount(kualiUser, account, dateTimeService.getCurrentSqlDate());
132     }
133 
134     /**
135      * @see org.kuali.ole.coa.service.AccountService#getPrimaryDelegationByExample(org.kuali.ole.coa.businessobject.AccountDelegate,
136      *      java.lang.String)
137      */
138 
139     @Override
140     public AccountDelegate getPrimaryDelegationByExample(AccountDelegate delegateExample, String totalDollarAmount) {
141         String documentTypeName = delegateExample.getFinancialDocumentTypeCode();
142         Date currentSqlDate = dateTimeService.getCurrentSqlDate();
143         List<AccountDelegate> primaryDelegations = filterAccountDelegates(delegateExample, accountDao.getPrimaryDelegationByExample(delegateExample, currentSqlDate, totalDollarAmount));
144         if (primaryDelegations.isEmpty()) {
145             return null;
146         }
147         for (Iterator<AccountDelegate> iterator = primaryDelegations.iterator(); iterator.hasNext();) {
148             AccountDelegate delegate = iterator.next();
149             if (!OLEConstants.ROOT_DOCUMENT_TYPE.equals(delegate.getFinancialDocumentTypeCode())) {
150                 return delegate;
151             }
152         }
153         return primaryDelegations.iterator().next();
154     }
155 
156     /**
157      * @see org.kuali.ole.coa.service.AccountService#getSecondaryDelegationsByExample(org.kuali.ole.coa.businessobject.AccountDelegate,
158      *      java.lang.String)
159      */
160     @Override
161     public List getSecondaryDelegationsByExample(AccountDelegate delegateExample, String totalDollarAmount) {
162         Date currentSqlDate = dateTimeService.getCurrentSqlDate();
163         List secondaryDelegations = accountDao.getSecondaryDelegationsByExample(delegateExample, currentSqlDate, totalDollarAmount);
164         return filterAccountDelegates(delegateExample, secondaryDelegations);
165     }
166 
167     /**
168      * This method filters account delegates by 
169      * 1) performing an exact match on the document type name of delegateExample
170      * 2) if no match is found for 1), then by performing an exact match on 
171      * the closest parent document type name of delegateExample document type name.
172      * 
173      * @param delegateExample
174      * @param accountDelegatesToFilterFrom
175      * @return
176      */
177     protected List<AccountDelegate> filterAccountDelegates(AccountDelegate delegateExample, List<AccountDelegate> accountDelegatesToFilterFrom) {
178         String documentTypeName = delegateExample.getFinancialDocumentTypeCode();
179         List<AccountDelegate> filteredAccountDelegates = filterAccountDelegates(accountDelegatesToFilterFrom, documentTypeName);
180         if (filteredAccountDelegates.size() == 0) {
181             Set<String> potentialParentDocumentTypeNames = getPotentialParentDocumentTypeNames(accountDelegatesToFilterFrom);
182             String closestParentDocumentTypeName = KimCommonUtils.getClosestParentDocumentTypeName(documentTypeService.getDocumentTypeByName(documentTypeName), potentialParentDocumentTypeNames);
183             filteredAccountDelegates = filterAccountDelegates(accountDelegatesToFilterFrom, closestParentDocumentTypeName);
184         }
185         return filteredAccountDelegates;
186     }
187 
188     /**
189      * This method filters account delegates by performing an exact match on the document type name passed in.
190      * 
191      * @param delegations
192      * @param documentTypeNameToFilterOn
193      * @return
194      */
195     protected List<AccountDelegate> filterAccountDelegates(List<AccountDelegate> delegations, String documentTypeNameToFilterOn) {
196         List<AccountDelegate> filteredSecondaryDelegations = new ArrayList<AccountDelegate>();
197         for (Object delegateObject : delegations) {
198             AccountDelegate delegate = (AccountDelegate) delegateObject;
199             if (StringUtils.equals(delegate.getFinancialDocumentTypeCode(), documentTypeNameToFilterOn)) {
200                 filteredSecondaryDelegations.add(delegate);
201             }
202         }
203         return filteredSecondaryDelegations;
204     }
205 
206     /**
207      * This method gets a list of potential parent document type names by collecting the unique doc type names from the list of
208      * account delegations
209      * 
210      * @param delegations
211      * @return
212      */
213     protected Set<String> getPotentialParentDocumentTypeNames(List<AccountDelegate> delegations) {
214         AccountDelegate delegate;
215         Set<String> potentialParentDocumentTypeNames = new HashSet<String>();
216         for (Object delegateObject : delegations) {
217             delegate = (AccountDelegate) delegateObject;
218             if (!potentialParentDocumentTypeNames.contains(delegate.getFinancialDocumentTypeCode())) {
219                 potentialParentDocumentTypeNames.add(delegate.getFinancialDocumentTypeCode());
220         }
221         }
222         return potentialParentDocumentTypeNames;
223     }
224 
225     /**
226      * get all accounts in the system. This is needed by a sufficient funds rebuilder job
227      * 
228      * @return iterator of all accounts
229      */
230     @Override
231     public Iterator getAllAccounts() {
232         LOG.debug("getAllAccounts() started");
233 
234         Iterator accountIter = accountDao.getAllAccounts();
235         // FIXME: this loads all accounts into memory - could blow server
236         return IteratorUtils.toList(accountIter).iterator();
237     }
238 
239     /**
240      * @see org.kuali.ole.coa.service.AccountService#getActiveAccountsForAccountSupervisor(java.lang.String)
241      */
242     @Override
243     public Iterator<Account> getActiveAccountsForAccountSupervisor(String principalId) {
244         return accountDao.getActiveAccountsForAccountSupervisor(principalId, dateTimeService.getCurrentSqlDate());
245     }
246 
247     /**
248      * @see org.kuali.ole.coa.service.AccountService#getActiveAccountsForFiscalOfficer(java.lang.String)
249      */
250     @Override
251     public Iterator<Account> getActiveAccountsForFiscalOfficer(String principalId) {
252         return accountDao.getActiveAccountsForFiscalOfficer(principalId, dateTimeService.getCurrentSqlDate());
253     }
254 
255     /**
256      * @see org.kuali.ole.coa.service.AccountService#getExpiredAccountsForAccountSupervisor(java.lang.String)
257      */
258     @Override
259     public Iterator<Account> getExpiredAccountsForAccountSupervisor(String principalId) {
260         return accountDao.getExpiredAccountsForAccountSupervisor(principalId, dateTimeService.getCurrentSqlDate());
261     }
262 
263     /**
264      * @see org.kuali.ole.coa.service.AccountService#getExpiredAccountsForFiscalOfficer(java.lang.String)
265      */
266     @Override
267     public Iterator<Account> getExpiredAccountsForFiscalOfficer(String principalId) {
268         return accountDao.getExpiredAccountsForFiscalOfficer(principalId, dateTimeService.getCurrentSqlDate());
269     }
270 
271     /**
272      * @see org.kuali.ole.coa.service.AccountService#isPrincipalInAnyWayShapeOrFormAccountManager(java.lang.String)
273      */
274     @Override
275     public boolean isPrincipalInAnyWayShapeOrFormAccountManager(String principalId) {
276         return accountDao.isPrincipalInAnyWayShapeOrFormAccountManager(principalId);
277     }
278 
279     /**
280      * @see org.kuali.ole.coa.service.AccountService#isPrincipalInAnyWayShapeOrFormAccountSupervisor(java.lang.String)
281      */
282     @Override
283     public boolean isPrincipalInAnyWayShapeOrFormAccountSupervisor(String principalId) {
284         return accountDao.isPrincipalInAnyWayShapeOrFormAccountSupervisor(principalId);
285     }
286 
287     /**
288      * @see org.kuali.ole.coa.service.AccountService#isPrincipalInAnyWayShapeOrFormFiscalOfficer(java.lang.String)
289      */
290     @Override
291     public boolean isPrincipalInAnyWayShapeOrFormFiscalOfficer(String principalId) {
292         return accountDao.isPrincipalInAnyWayShapeOrFormFiscalOfficer(principalId);
293     }
294 
295     /**
296      * @see org.kuali.ole.coa.service.AccountService#getAccountsForAccountNumber(java.lang.String)
297      */
298     @Override
299     @Cacheable(value=Account.CACHE_NAME, key="'AccountsForAccountNumber'+#p0")
300     public Collection<Account> getAccountsForAccountNumber(String accountNumber) {
301         return accountDao.getAccountsForAccountNumber(accountNumber);
302     }
303 
304 
305     @Override
306     public String getDefaultLaborBenefitRateCategoryCodeForAccountType(String accountTypeCode) {
307         String benefitRateCategory = parameterService.getSubParameterValueAsString(Account.class, "DEFAULT_BENEFIT_RATE_CATEGORY_CODE_BY_ACCOUNT_TYPE", accountTypeCode);
308         if ( StringUtils.isBlank(benefitRateCategory) ) {
309             benefitRateCategory = parameterService.getParameterValueAsString(Account.class, "DEFAULT_BENEFIT_RATE_CATEGORY_CODE");
310         }
311         return StringUtils.trimToEmpty(benefitRateCategory);
312     }
313 
314     /**
315      * @see org.kuali.ole.coa.service.AccountService#isFridgeBenefitCalculationEnable()
316      */
317     @Override
318     public Boolean isFridgeBenefitCalculationEnable(){
319         Boolean isFringeBeneCalcEnable = null;
320 
321         //make sure the parameter exists
322         if(parameterService.parameterExists(OleParameterConstants.FINANCIAL_SYSTEM_ALL.class, "ENABLE_FRINGE_BENEFIT_CALC_BY_BENEFIT_RATE_CATEGORY_IND")){
323           //check the system param to see if the labor benefit rate category should be editable
324             isFringeBeneCalcEnable = SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(OleParameterConstants.FINANCIAL_SYSTEM_ALL.class, "ENABLE_FRINGE_BENEFIT_CALC_BY_BENEFIT_RATE_CATEGORY_IND");
325             LOG.debug("System Parameter retrieved: " + isFringeBeneCalcEnable);
326         }
327 
328         return (Boolean)org.apache.commons.lang.ObjectUtils.defaultIfNull(isFringeBeneCalcEnable, false);
329     }
330 
331 
332     /**
333      * @see org.kuali.ole.coa.service.AccountService#getUniqueAccountForAccountNumber(java.lang.String)
334      */
335     @Override
336     @Cacheable(value=Account.CACHE_NAME, key="'UniqueAccountForAccountNumber'+#p0")
337     public Account getUniqueAccountForAccountNumber(String accountNumber) {
338         Iterator<Account> accounts = accountDao.getAccountsForAccountNumber(accountNumber).iterator();
339         Account account = null;
340         // there should be only one account in the collection
341         if (accounts.hasNext()) {
342             account = accounts.next();
343         }
344         return account;
345     }
346 
347     /**
348      * @see org.kuali.ole.coa.service.AccountService#accountsCanCrossCharts()
349      */
350     @Override
351     public boolean accountsCanCrossCharts() {
352         return parameterService.getParameterValueAsBoolean(OleParameterConstants.FINANCIAL_SYSTEM_ALL.class, SystemGroupParameterNames.ACCOUNTS_CAN_CROSS_CHARTS_IND);
353     }
354 
355     /**
356      * @see org.kuali.ole.coa.service.AccountService#accountsCanCrossCharts()
357      */
358     @Override
359     public void populateAccountingLineChartIfNeeded(AccountingLine line) {
360         if (!accountsCanCrossCharts() /* && line.getChartOfAccountsCode() == null */) {
361             Account account = getUniqueAccountForAccountNumber(line.getAccountNumber());
362             if (ObjectUtils.isNotNull(account)) {
363                 line.setChartOfAccountsCode(account.getChartOfAccountsCode());
364             }
365         }
366     }
367 
368     public void setAccountDao(AccountDao accountDao) {
369         this.accountDao = accountDao;
370     }
371 
372     public void setDateTimeService(DateTimeService dateTimeService) {
373         this.dateTimeService = dateTimeService;
374     }
375 
376     public void setDocumentTypeService(DocumentTypeService documentTypeService) {
377         this.documentTypeService = documentTypeService;
378     }
379 
380     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
381         this.businessObjectService = businessObjectService;
382     }
383     
384     public void setParameterService(ParameterService parameterService) {
385         this.parameterService = parameterService;
386     }
387 }