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.coa.dataaccess.impl; 017 018 import java.util.ArrayList; 019 import java.util.Collection; 020 import java.util.Iterator; 021 import java.util.List; 022 023 import org.apache.ojb.broker.query.Criteria; 024 import org.apache.ojb.broker.query.QueryFactory; 025 import org.apache.ojb.broker.query.ReportQueryByCriteria; 026 import org.kuali.kfs.coa.businessobject.Account; 027 import org.kuali.kfs.coa.businessobject.AccountDelegate; 028 import org.kuali.kfs.coa.dataaccess.AccountDao; 029 import org.kuali.kfs.sys.KFSConstants; 030 import org.kuali.kfs.sys.KFSPropertyConstants; 031 import org.kuali.kfs.sys.businessobject.AccountResponsibility; 032 import org.kuali.kfs.sys.context.SpringContext; 033 import org.kuali.rice.kim.bo.Person; 034 import org.kuali.rice.kns.dao.impl.PlatformAwareDaoBaseOjb; 035 import org.kuali.rice.kns.service.DateTimeService; 036 import org.kuali.rice.kns.util.KualiDecimal; 037 import org.kuali.rice.kns.util.ObjectUtils; 038 039 /** 040 * This class is the OJB implementation of the AccountDao interface. 041 */ 042 public class AccountDaoOjb extends PlatformAwareDaoBaseOjb implements AccountDao { 043 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccountDaoOjb.class); 044 045 private DateTimeService dateTimeService; 046 047 /** 048 * Retrieves account business object by primary key 049 * 050 * @param chartOfAccountsCode - the FIN_COA_CD of the Chart Code that is part of the composite key of Account 051 * @param accountNumber - the ACCOUNT_NBR part of the composite key of Accont 052 * @return Account 053 * @see AccountDao 054 */ 055 public Account getByPrimaryId(String chartOfAccountsCode, String accountNumber) { 056 LOG.debug("getByPrimaryId() started"); 057 058 Criteria criteria = new Criteria(); 059 criteria.addEqualTo("chartOfAccountsCode", chartOfAccountsCode); 060 criteria.addEqualTo("accountNumber", accountNumber); 061 062 return (Account) getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQuery(Account.class, criteria)); 063 } 064 065 /** 066 * fetch the accounts that the user is either the fiscal officer or a delegate of the fiscal officer 067 * 068 * @param kualiUser 069 * @return a list of Accounts that the user has responsibility for 070 */ 071 public List getAccountsThatUserIsResponsibleFor(Person person) { 072 LOG.debug("getAccountsThatUserIsResponsibleFor() started"); 073 074 List accountResponsibilities = new ArrayList(); 075 accountResponsibilities.addAll(getFiscalOfficerResponsibilities(person)); 076 accountResponsibilities.addAll(getDelegatedResponsibilities(person)); 077 return accountResponsibilities; 078 } 079 080 /** 081 * This method determines if the given user has any responsibilities on the given account 082 * 083 * @param person the user to check responsibilities for 084 * @param account the account to check responsibilities on 085 * @return true if user is somehow responsible for account, false if otherwise 086 */ 087 public boolean determineUserResponsibilityOnAccount(Person person, Account account) { 088 boolean result = hasFiscalOfficerResponsibility(person, account); 089 if (!result) { 090 result = hasDelegatedResponsibility(person, account); 091 } 092 return result; 093 } 094 095 /** 096 * Resolves the Primary Delegate for the given delegate example. If the primary delegate exists for a specific Document Type 097 * Code and for a Document Type Code of "KFS", the delegate for the specific document type code is returned; 098 * 099 * @see org.kuali.kfs.coa.dataaccess.AccountDao#getPrimaryDelegationByExample(org.kuali.kfs.coa.businessobject.AccountDelegate, 100 * java.lang.String) 101 */ 102 public List getPrimaryDelegationByExample(AccountDelegate delegateExample, String totalDollarAmount) { 103 return new ArrayList(getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(AccountDelegate.class, getDelegateByExampleCriteria(delegateExample, totalDollarAmount, "Y")))); 104 } 105 106 /** 107 * @see org.kuali.kfs.coa.dataaccess.AccountDao#getSecondaryDelegationsByExample(org.kuali.kfs.coa.businessobject.AccountDelegate, 108 * java.lang.String) 109 */ 110 public List getSecondaryDelegationsByExample(AccountDelegate delegateExample, String totalDollarAmount) { 111 return new ArrayList(getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(AccountDelegate.class, getDelegateByExampleCriteria(delegateExample, totalDollarAmount, "N")))); 112 } 113 114 /** 115 * This method creates a {@link Criteria} based on {@link Delegate}, dollar amount and whether or not it is the primary 116 * delegate 117 * 118 * @param delegateExample 119 * @param totalDollarAmount 120 * @param accountsDelegatePrmrtIndicator 121 * @return example {@link Delegate} {@link Criteria} 122 */ 123 protected Criteria getDelegateByExampleCriteria(AccountDelegate delegateExample, String totalDollarAmount, String accountsDelegatePrmrtIndicator) { 124 Criteria criteria = new Criteria(); 125 criteria.addEqualTo(KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME, delegateExample.getChartOfAccountsCode()); 126 criteria.addEqualTo(KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME, delegateExample.getAccountNumber()); 127 criteria.addEqualTo("active", "Y"); 128 criteria.addLessOrEqualThan("accountDelegateStartDate", SpringContext.getBean(DateTimeService.class).getCurrentSqlDate()); 129 criteria.addEqualTo("accountsDelegatePrmrtIndicator", accountsDelegatePrmrtIndicator); 130 if (totalDollarAmount != null) { 131 // (toAmt is nullish and (fromAmt is nullish or fromAmt <= total)) or (fromAmt is nullish and (toAmt is nullish or toAmt >= total)) or (fromAmt <= total and toAmount >= total) 132 133 /* to not active clause: (toAmt is nullish and (fromAmt is nullish or fromAmt <= total)) */ 134 Criteria toAmountIsNullish = new Criteria(); 135 toAmountIsNullish.addIsNull(KFSPropertyConstants.FIN_DOC_APPROVAL_TO_THIS_AMOUNT); 136 Criteria toAmountIsZero1 = new Criteria(); 137 toAmountIsZero1.addEqualTo(KFSPropertyConstants.FIN_DOC_APPROVAL_TO_THIS_AMOUNT, "0"); 138 toAmountIsNullish.addOrCriteria(toAmountIsZero1); 139 140 Criteria fromMatchesClause = new Criteria(); 141 fromMatchesClause.addIsNull(KFSPropertyConstants.FIN_DOC_APPROVAL_FROM_THIS_AMT); 142 Criteria fromAmountIsLessThanTotal = new Criteria(); 143 fromAmountIsLessThanTotal.addLessOrEqualThan(KFSPropertyConstants.FIN_DOC_APPROVAL_FROM_THIS_AMT, totalDollarAmount); 144 fromMatchesClause.addOrCriteria(fromAmountIsLessThanTotal); 145 146 Criteria toNotActiveClause = new Criteria(); 147 toNotActiveClause.addAndCriteria(toAmountIsNullish); 148 toNotActiveClause.addAndCriteria(fromMatchesClause); 149 150 /* from not active clause: (fromAmt is nullish and (toAmt is nullish or toAmt >= total)) */ 151 Criteria toMatchesClause = new Criteria(); 152 toMatchesClause.addIsNull(KFSPropertyConstants.FIN_DOC_APPROVAL_TO_THIS_AMOUNT); 153 Criteria toAmountIsZero2 = new Criteria(); 154 toAmountIsZero2.addEqualTo(KFSPropertyConstants.FIN_DOC_APPROVAL_TO_THIS_AMOUNT, "0"); 155 toMatchesClause.addOrCriteria(toAmountIsZero2); 156 Criteria toAmountIsGreaterThanTotal = new Criteria(); 157 toAmountIsGreaterThanTotal.addGreaterOrEqualThan(KFSPropertyConstants.FIN_DOC_APPROVAL_TO_THIS_AMOUNT, totalDollarAmount); 158 toMatchesClause.addOrCriteria(toAmountIsGreaterThanTotal); 159 160 Criteria fromIsNullClause = new Criteria(); 161 fromIsNullClause.addIsNull(KFSPropertyConstants.FIN_DOC_APPROVAL_FROM_THIS_AMT); 162 Criteria fromIsZeroClause = new Criteria(); 163 fromIsZeroClause.addEqualTo(KFSPropertyConstants.FIN_DOC_APPROVAL_FROM_THIS_AMT, "0"); 164 Criteria fromIsNullishClause = new Criteria(); 165 fromIsNullishClause.addOrCriteria(fromIsNullClause); 166 fromIsNullishClause.addOrCriteria(fromIsZeroClause); 167 Criteria fromNotActiveClause = new Criteria(); 168 fromNotActiveClause.addAndCriteria(fromIsNullishClause); 169 fromNotActiveClause.addAndCriteria(toMatchesClause); 170 171 Criteria bothActive = new Criteria(); 172 bothActive.addLessOrEqualThan(KFSPropertyConstants.FIN_DOC_APPROVAL_FROM_THIS_AMT, totalDollarAmount); 173 bothActive.addGreaterOrEqualThan(KFSPropertyConstants.FIN_DOC_APPROVAL_TO_THIS_AMOUNT, totalDollarAmount); 174 175 Criteria totalDollarAmountCriteria = new Criteria(); 176 totalDollarAmountCriteria.addOrCriteria(toNotActiveClause); 177 totalDollarAmountCriteria.addOrCriteria(fromNotActiveClause); 178 totalDollarAmountCriteria.addOrCriteria(bothActive); 179 180 criteria.addAndCriteria(totalDollarAmountCriteria); 181 } 182 return criteria; 183 } 184 185 /** 186 * method to get the fo responsibilities for the account 187 * 188 * @param person - fiscal officer to check for 189 * @return list of {@link AccountResponsibility} for this fiscal officer 190 */ 191 protected List getFiscalOfficerResponsibilities(Person person) { 192 List fiscalOfficerResponsibilities = new ArrayList(); 193 Criteria criteria = new Criteria(); 194 criteria.addEqualTo("accountFiscalOfficerSystemIdentifier", person.getPrincipalId()); 195 Collection accounts = getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(Account.class, criteria)); 196 for (Iterator iter = accounts.iterator(); iter.hasNext();) { 197 Account account = (Account) iter.next(); 198 AccountResponsibility accountResponsibility = new AccountResponsibility(AccountResponsibility.FISCAL_OFFICER_RESPONSIBILITY, KualiDecimal.ZERO, KualiDecimal.ZERO, "", account); 199 fiscalOfficerResponsibilities.add(accountResponsibility); 200 } 201 return fiscalOfficerResponsibilities; 202 } 203 204 /** 205 * This method determines if a given user has fiscal officer responsiblity on a given account. 206 * 207 * @param person the user to check responsibilities for 208 * @param account the account to check responsibilities on 209 * @return true if user does have fiscal officer responsibility on account, false if otherwise 210 */ 211 protected boolean hasFiscalOfficerResponsibility(Person person, Account account) { 212 boolean hasFiscalOfficerResponsibility = false; 213 Criteria criteria = new Criteria(); 214 criteria.addEqualTo("accountFiscalOfficerSystemIdentifier", person.getPrincipalId()); 215 criteria.addEqualTo("chartOfAccountsCode", account.getChartOfAccountsCode()); 216 criteria.addEqualTo("accountNumber", account.getAccountNumber()); 217 Collection accounts = getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(Account.class, criteria)); 218 if (accounts != null && accounts.size() > 0) { 219 Account retrievedAccount = (Account) accounts.iterator().next(); 220 if (ObjectUtils.isNotNull(retrievedAccount)) { 221 hasFiscalOfficerResponsibility = true; 222 } 223 } 224 return hasFiscalOfficerResponsibility; 225 } 226 227 /** 228 * method to get the fo delegated responsibilities for the account 229 * 230 * @param person - user to check against 231 * @return a list of {@link AccountResponsibility} objects for a delegate 232 */ 233 protected List getDelegatedResponsibilities(Person person) { 234 List delegatedResponsibilities = new ArrayList(); 235 Criteria criteria = new Criteria(); 236 criteria.addEqualTo("accountDelegateSystemId", person.getPrincipalId()); 237 Collection accountDelegates = getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(AccountDelegate.class, criteria)); 238 for (Iterator iter = accountDelegates.iterator(); iter.hasNext();) { 239 AccountDelegate accountDelegate = (AccountDelegate) iter.next(); 240 if (accountDelegate.isActive()) { 241 // the start_date should never be null in the real world, but 242 // there is some test data that 243 // contains null startDates, therefore this check. 244 if (ObjectUtils.isNotNull(accountDelegate.getAccountDelegateStartDate())) { 245 if (!accountDelegate.getAccountDelegateStartDate().after(dateTimeService.getCurrentDate())) { 246 Account account = getByPrimaryId(accountDelegate.getChartOfAccountsCode(), accountDelegate.getAccount().getAccountNumber()); 247 AccountResponsibility accountResponsibility = new AccountResponsibility(AccountResponsibility.DELEGATED_RESPONSIBILITY, accountDelegate.getFinDocApprovalFromThisAmt(), accountDelegate.getFinDocApprovalToThisAmount(), accountDelegate.getFinancialDocumentTypeCode(), account); 248 delegatedResponsibilities.add(accountResponsibility); 249 } 250 } 251 } 252 } 253 return delegatedResponsibilities; 254 } 255 256 /** 257 * This method determines if a user has delegated responsibilities on a given account. 258 * 259 * @param person the user to check responsibilities for 260 * @param account the account to check responsibilities on 261 * @return true if user has delegated responsibilities 262 */ 263 protected boolean hasDelegatedResponsibility(Person person, Account account) { 264 boolean hasResponsibility = false; 265 Criteria criteria = new Criteria(); 266 criteria.addEqualTo("accountDelegateSystemId", person.getPrincipalId()); 267 criteria.addEqualTo("chartOfAccountsCode", account.getChartOfAccountsCode()); 268 criteria.addEqualTo("accountNumber", account.getAccountNumber()); 269 Collection accountDelegates = getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(AccountDelegate.class, criteria)); 270 for (Iterator iter = accountDelegates.iterator(); iter.hasNext() && !hasResponsibility;) { 271 AccountDelegate accountDelegate = (AccountDelegate) iter.next(); 272 if (accountDelegate.isActive()) { 273 // the start_date should never be null in the real world, but 274 // there is some test data that 275 // contains null startDates, therefore this check. 276 if (ObjectUtils.isNotNull(accountDelegate.getAccountDelegateStartDate())) { 277 if (!accountDelegate.getAccountDelegateStartDate().after(dateTimeService.getCurrentDate())) { 278 hasResponsibility = true; 279 } 280 } 281 } 282 } 283 return hasResponsibility; 284 } 285 286 /** 287 * @see org.kuali.kfs.coa.dataaccess.AccountDao#getAllAccounts() 288 * @return an iterator for all accounts 289 */ 290 public Iterator getAllAccounts() { 291 LOG.debug("getAllAccounts() started"); 292 293 Criteria criteria = new Criteria(); 294 return getPersistenceBrokerTemplate().getIteratorByQuery(QueryFactory.newQuery(Account.class, criteria)); 295 } 296 297 /** 298 * @see org.kuali.kfs.coa.dataaccess.AccountDao#getActiveAccountsForAccountSupervisor(java.lang.String) 299 */ 300 public Iterator<Account> getActiveAccountsForAccountSupervisor(String principalId) { 301 Criteria criteria = new Criteria(); 302 criteria.addEqualTo("accountsSupervisorySystemsIdentifier", principalId); 303 criteria.addEqualTo("active", true); 304 criteria.addAndCriteria(getAccountNotExpiredCriteria()); 305 return (Iterator<Account>)getPersistenceBrokerTemplate().getIteratorByQuery(QueryFactory.newQuery(Account.class, criteria)); 306 } 307 308 /** 309 * @see org.kuali.kfs.coa.dataaccess.AccountDao#getActiveAccountsForFiscalOfficer(java.lang.String) 310 */ 311 public Iterator<Account> getActiveAccountsForFiscalOfficer(String principalId) { 312 Criteria criteria = new Criteria(); 313 criteria.addEqualTo("accountFiscalOfficerSystemIdentifier", principalId); 314 criteria.addEqualTo("active", true); 315 criteria.addAndCriteria(getAccountNotExpiredCriteria()); 316 return (Iterator<Account>)getPersistenceBrokerTemplate().getIteratorByQuery(QueryFactory.newQuery(Account.class, criteria)); 317 } 318 319 /** 320 * @see org.kuali.kfs.coa.dataaccess.AccountDao#getExpiredAccountsForAccountSupervisor(java.lang.String) 321 */ 322 public Iterator<Account> getExpiredAccountsForAccountSupervisor(String principalId) { 323 Criteria criteria = new Criteria(); 324 criteria.addEqualTo("accountsSupervisorySystemsIdentifier", principalId); 325 criteria.addEqualTo("active", true); 326 criteria.addAndCriteria(getAccountExpiredCriteria()); 327 return (Iterator<Account>)getPersistenceBrokerTemplate().getIteratorByQuery(QueryFactory.newQuery(Account.class, criteria)); 328 } 329 330 /** 331 * @see org.kuali.kfs.coa.dataaccess.AccountDao#getExpiredAccountsForFiscalOfficer(java.lang.String) 332 */ 333 public Iterator<Account> getExpiredAccountsForFiscalOfficer(String principalId) { 334 Criteria criteria = new Criteria(); 335 criteria.addEqualTo("accountFiscalOfficerSystemIdentifier", principalId); 336 criteria.addEqualTo("active", true); 337 criteria.addAndCriteria(getAccountExpiredCriteria()); 338 return (Iterator<Account>)getPersistenceBrokerTemplate().getIteratorByQuery(QueryFactory.newQuery(Account.class, criteria)); 339 } 340 341 /** 342 * Builds a criteria to find expired accounts 343 * @return a Criteria for expired accounts 344 */ 345 protected Criteria getAccountExpiredCriteria() { 346 Criteria criteria = new Criteria(); 347 criteria.addNotNull("accountExpirationDate"); 348 criteria.addLessOrEqualThan("accountExpirationDate", dateTimeService.getCurrentSqlDate()); 349 return criteria; 350 } 351 352 /** 353 * Builds a criteria to find non-expired accounts 354 * @return a Criteria for non-expired accounts 355 */ 356 protected Criteria getAccountNotExpiredCriteria() { 357 Criteria criteria = new Criteria(); 358 criteria.addIsNull("accountExpirationDate"); 359 360 Criteria notYetExpiredCriteria = new Criteria(); 361 notYetExpiredCriteria.addGreaterThan("accountExpirationDate", dateTimeService.getCurrentSqlDate()); 362 363 criteria.addOrCriteria(notYetExpiredCriteria); 364 return criteria; 365 } 366 367 /** 368 * @see org.kuali.kfs.coa.dataaccess.AccountDao#isPrincipalInAnyWayShapeOrFormAccountManager(java.lang.String) 369 */ 370 public boolean isPrincipalInAnyWayShapeOrFormAccountManager(String principalId) { 371 return queryPrincipalHasAccountRole(principalId, "accountManagerSystemIdentifier"); 372 } 373 374 /** 375 * Determines if any non-closed accounts exist where the principal id is in the role of the role name 376 * @param principalId the principal id to check 377 * @param principalRoleName the name of the field on account to check for the principal id in 378 * @return true if the principal has that account role, false otherwise 379 */ 380 protected boolean queryPrincipalHasAccountRole(String principalId, String principalRoleName) { 381 Criteria criteria = new Criteria(); 382 criteria.addEqualTo(principalRoleName, principalId); 383 criteria.addEqualTo("active", "Y"); 384 385 ReportQueryByCriteria reportQuery = QueryFactory.newReportQuery(Account.class, criteria); 386 reportQuery.setAttributes(new String[] { "count(*)" }); 387 388 int resultCount = 0; 389 Iterator iter = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(reportQuery); 390 while (iter.hasNext()) { 391 final Object[] results = (Object[])iter.next(); 392 resultCount = (results[0] instanceof Number) ? ((Number)results[0]).intValue() : new Integer(results[0].toString()).intValue(); 393 } 394 return resultCount > 0; 395 } 396 397 398 /** 399 * @see org.kuali.kfs.coa.dataaccess.AccountDao#isPrincipalInAnyWayShapeOrFormAccountSupervisor(java.lang.String) 400 */ 401 public boolean isPrincipalInAnyWayShapeOrFormAccountSupervisor(String principalId) { 402 return queryPrincipalHasAccountRole(principalId, "accountsSupervisorySystemsIdentifier"); 403 } 404 405 /** 406 * @see org.kuali.kfs.coa.dataaccess.AccountDao#isPrincipalInAnyWayShapeOrFormFiscalOfficer(java.lang.String) 407 */ 408 public boolean isPrincipalInAnyWayShapeOrFormFiscalOfficer(String principalId) { 409 return queryPrincipalHasAccountRole(principalId, "accountFiscalOfficerSystemIdentifier"); 410 } 411 412 public void setDateTimeService(DateTimeService dateTimeService) { 413 this.dateTimeService = dateTimeService; 414 } 415 416 /** 417 * @see org.kuali.kfs.coa.dataaccess.AccountDao#getAccountsForAccountNumber(java.lang.String) 418 */ 419 public Collection<Account> getAccountsForAccountNumber(String accountNumber) { 420 Criteria criteria = new Criteria(); 421 criteria.addEqualTo(KFSPropertyConstants.ACCOUNT_NUMBER, accountNumber); 422 423 return getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(Account.class, criteria)); 424 } 425 } 426