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