View Javadoc

1   /*
2    * Copyright 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.gl.businessobject.lookup;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.apache.commons.lang.ArrayUtils;
25  import org.apache.commons.lang.StringUtils;
26  import org.kuali.ole.coa.businessobject.ObjectCode;
27  import org.kuali.ole.gl.Constant;
28  import org.kuali.ole.gl.GeneralLedgerConstants;
29  import org.kuali.ole.gl.OJBUtility;
30  import org.kuali.ole.gl.batch.service.AccountBalanceCalculator;
31  import org.kuali.ole.gl.businessobject.AccountBalance;
32  import org.kuali.ole.gl.businessobject.TransientBalanceInquiryAttributes;
33  import org.kuali.ole.gl.businessobject.inquiry.AccountBalanceInquirableImpl;
34  import org.kuali.ole.gl.service.AccountBalanceService;
35  import org.kuali.ole.sys.OLEConstants;
36  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry;
37  import org.kuali.ole.sys.businessobject.SystemOptions;
38  import org.kuali.ole.sys.service.OptionsService;
39  import org.kuali.rice.core.api.util.type.KualiDecimal;
40  import org.kuali.rice.kns.lookup.HtmlData;
41  import org.kuali.rice.krad.bo.BusinessObject;
42  import org.kuali.rice.krad.util.ObjectUtils;
43  
44  /**
45   * A class to support Account Balance lookups
46   */
47  public class AccountBalanceLookupableHelperServiceImpl extends AbstractGeneralLedgerLookupableHelperServiceImpl {
48  
49      private AccountBalanceCalculator postAccountBalance;
50      private AccountBalanceService accountBalanceService;
51      private OptionsService optionsService;
52  
53      /**
54       * Returns the url for the account balance inquiry
55       * @param bo the business object with a property that an inquiry drill down url is being asked for
56       * @param propertyName the property of that bo that the inquiry drill down url is being asked for
57       * @return the URL for the inquiry
58       * @see org.kuali.rice.kns.lookup.Lookupable#getInquiryUrl(org.kuali.rice.krad.bo.BusinessObject, java.lang.String)
59       */
60      @Override
61      public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
62          return (new AccountBalanceInquirableImpl()).getInquiryUrl(bo, propertyName);
63      }
64  
65      /**
66       * Given a map of fieldValues, actually searches for the appropriate account balance records to return
67       * @param fieldValues a map of keys for the search
68       * @return a List of AccountBalance records that match the search criteria
69       * @see org.kuali.rice.kns.lookup.Lookupable#getSearchResults(java.util.Map)
70       * 
71       * KRAD Conversion: Lookupable modifies the search results based on the fields consolidated.
72       * But all field definitions are in data dictionary.
73       */
74      public List getSearchResults(Map fieldValues) {
75          setBackLocation((String) fieldValues.get(OLEConstants.BACK_LOCATION));
76          setDocFormKey((String) fieldValues.get(OLEConstants.DOC_FORM_KEY));
77  
78          Collection searchResultsCollection = null;
79  
80          // get the pending entry option. This method must be prior to the get search results
81          String pendingEntryOption = this.getSelectedPendingEntryOption(fieldValues);
82  
83          // KFSMI-410: added one more node for consolidationOption
84          String consolidationOption = (String) fieldValues.get(GeneralLedgerConstants.DummyBusinessObject.CONSOLIDATION_OPTION);
85          // test if the consolidation option is selected or not
86          boolean isConsolidated = isConsolidationSelected(fieldValues); 
87          
88          // get the search result collection
89          // KFSMI-410: added one more node for consolidationOption
90          if (consolidationOption.equals(Constant.EXCLUDE_SUBACCOUNTS)){
91              fieldValues.put(Constant.SUB_ACCOUNT_OPTION, OLEConstants.getDashSubAccountNumber());
92              isConsolidated = false;
93          } 
94          
95          if (isConsolidated) {
96              Iterator availableBalanceIterator = accountBalanceService.findConsolidatedAvailableAccountBalance(fieldValues);
97              searchResultsCollection = buildConsolidedAvailableBalanceCollection(availableBalanceIterator);
98          }
99          else {
100             Iterator availableBalanceIterator = accountBalanceService.findAvailableAccountBalance(fieldValues);
101             searchResultsCollection = buildDetailedAvailableBalanceCollection(availableBalanceIterator);
102         }
103 
104         // update search results according to the selected pending entry option
105         updateByPendingLedgerEntry(searchResultsCollection, fieldValues, pendingEntryOption, isConsolidated, false);
106 
107         // Put the search related stuff in the objects
108         for (Iterator iter = searchResultsCollection.iterator(); iter.hasNext();) {
109             AccountBalance ab = (AccountBalance) iter.next();
110             TransientBalanceInquiryAttributes dbo = ab.getDummyBusinessObject();
111             dbo.setConsolidationOption(consolidationOption);
112             dbo.setPendingEntryOption(pendingEntryOption);
113         }
114 
115         // get the actual size of all qualified search results
116         Integer recordCount = accountBalanceService.getAvailableAccountBalanceCount(fieldValues, isConsolidated);
117         Long actualSize = OJBUtility.getResultActualSize(searchResultsCollection, recordCount, fieldValues, new AccountBalance());
118 
119         return this.buildSearchResultList(searchResultsCollection, actualSize);
120     }
121 
122     /**
123      * This method builds the available account balance collection based on the input iterator
124      * 
125      * @param iterator the iterator of search results of account balance
126      * @return the account balance collection
127      */
128     private Collection buildConsolidedAvailableBalanceCollection(Iterator iterator) {
129         Collection balanceCollection = new ArrayList();
130 
131         // build available balance collection throught analyzing the input iterator
132         while (iterator.hasNext()) {
133             Object avaiableAccountBalance = iterator.next();
134 
135             if (avaiableAccountBalance.getClass().isArray()) {
136                 int i = 0;
137                 Object[] array = (Object[]) avaiableAccountBalance;
138                 AccountBalance accountBalance = new AccountBalance();
139 
140                 accountBalance.setUniversityFiscalYear(new Integer(array[i++].toString()));
141                 accountBalance.setChartOfAccountsCode(array[i++].toString());
142 
143                 accountBalance.setAccountNumber(array[i++].toString());
144                 accountBalance.setSubAccountNumber(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER);
145 
146                 accountBalance.setObjectCode(array[i++].toString());
147                 accountBalance.setSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
148 
149                 String objectTypeCode = array[i++].toString();
150                 accountBalance.getFinancialObject().setFinancialObjectTypeCode(objectTypeCode);
151 
152                 KualiDecimal budgetAmount = new KualiDecimal(array[i++].toString());
153                 accountBalance.setCurrentBudgetLineBalanceAmount(budgetAmount);
154 
155                 KualiDecimal actualsAmount = new KualiDecimal(array[i++].toString());
156                 accountBalance.setAccountLineActualsBalanceAmount(actualsAmount);
157 
158                 KualiDecimal encumbranceAmount = new KualiDecimal(array[i].toString());
159                 accountBalance.setAccountLineEncumbranceBalanceAmount(encumbranceAmount);
160 
161                 KualiDecimal variance = calculateVariance(accountBalance);
162                 accountBalance.getDummyBusinessObject().setGenericAmount(variance);
163 
164                 balanceCollection.add(accountBalance);
165             }
166         }
167         return balanceCollection;
168     }
169 
170     /**
171      * This method builds the available account balance collection based on the input collection
172      * 
173      * @param collection a collection of account balance entries
174      * @return the account balance collection
175      */
176     private Collection buildDetailedAvailableBalanceCollection(Iterator iterator) {
177         Collection balanceCollection = new ArrayList();
178 
179         // build available balance collection throught analyzing the iterator above
180         while (iterator.hasNext()) {
181             AccountBalance accountBalance = (AccountBalance) iterator.next();
182 
183             if (accountBalance.getDummyBusinessObject() == null) {
184                 accountBalance.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
185             }
186 
187             KualiDecimal variance = calculateVariance(accountBalance);
188             accountBalance.getDummyBusinessObject().setGenericAmount(variance);
189 
190             balanceCollection.add(accountBalance);
191         }
192         return balanceCollection;
193     }
194 
195     /**
196      * This method calculates the variance of current budget balance, actuals balance and encumbrance balance
197      * 
198      * @param balance an account balance entry
199      */
200     private KualiDecimal calculateVariance(AccountBalance balance) {
201 
202         KualiDecimal variance = new KualiDecimal(0.0);
203         KualiDecimal budgetAmount = balance.getCurrentBudgetLineBalanceAmount();
204         KualiDecimal actualsAmount = balance.getAccountLineActualsBalanceAmount();
205         KualiDecimal encumbranceAmount = balance.getAccountLineEncumbranceBalanceAmount();
206 
207         // determine if the object type code is one of the given codes
208         if (ObjectUtils.isNull(balance.getFinancialObject()) || StringUtils.isBlank(balance.getFinancialObject().getFinancialObjectTypeCode())) {
209             balance.refreshReferenceObject("financialObject"); // refresh if we need to...
210         }
211         ObjectCode financialObject = balance.getFinancialObject();
212         String objectTypeCode = (financialObject == null) ? Constant.EMPTY_STRING : financialObject.getFinancialObjectTypeCode();
213 
214         SystemOptions options = getOptionsService().getOptions(balance.getUniversityFiscalYear());
215         if (ObjectUtils.isNull(options)) {
216             options = getOptionsService().getCurrentYearOptions();
217         }
218         String[] objectTypeCodeList = new String[3];
219         objectTypeCodeList[0] = options.getFinObjTypeExpendNotExpCode();
220         objectTypeCodeList[1] = options.getFinObjTypeExpNotExpendCode();
221         objectTypeCodeList[2] = options.getFinObjTypeExpenditureexpCd();
222 
223         boolean isObjectTypeCodeInList = ArrayUtils.contains(objectTypeCodeList, objectTypeCode);
224 
225         // calculate the variance based on the object type code of the balance
226         if (isObjectTypeCodeInList) {
227             variance = budgetAmount.subtract(actualsAmount);
228             variance = variance.subtract(encumbranceAmount);
229         }
230         else {
231             variance = actualsAmount.subtract(budgetAmount);
232         }
233         return variance;
234     }
235 
236     /**
237      * Updates the collection of entries that will be applied to the results of the inquiry
238      * 
239      * @param entryCollection a collection of balance entries
240      * @param fieldValues the map containing the search fields and values
241      * @param isApproved flag whether the approved entries or all entries will be processed
242      * @param isConsolidated flag whether the results are consolidated or not
243      * @param isCostShareExcluded flag whether the user selects to see the results with cost share subaccount
244      * @see org.kuali.module.gl.web.lookupable.AbstractGLLookupableImpl#updateEntryCollection(java.util.Collection, java.util.Map,
245      *      boolean, boolean, boolean)
246      */
247     @Override
248     protected void updateEntryCollection(Collection entryCollection, Map fieldValues, boolean isApproved, boolean isConsolidated, boolean isCostShareExcluded) {
249 
250         // convert the field names of balance object into corresponding ones of pending entry object
251         Map pendingEntryFieldValues = BusinessObjectFieldConverter.convertToTransactionFieldValues(fieldValues);
252 
253         // go through the pending entries to update the balance collection
254         Iterator pendingEntryIterator = getGeneralLedgerPendingEntryService().findPendingLedgerEntriesForAccountBalance(pendingEntryFieldValues, isApproved);
255         while (pendingEntryIterator.hasNext()) {
256             GeneralLedgerPendingEntry pendingEntry = (GeneralLedgerPendingEntry) pendingEntryIterator.next();
257 
258             if (isCostShareExcluded) {
259                 if (ObjectUtils.isNotNull(pendingEntry.getSubAccount()) && ObjectUtils.isNotNull(pendingEntry.getSubAccount().getA21SubAccount())) {
260                     if (OLEConstants.SubAccountType.COST_SHARE.equals(pendingEntry.getSubAccount().getA21SubAccount().getSubAccountTypeCode())) {
261                         // Don't process this one
262                         continue;
263                     }
264                 }
265             }
266 
267             // if consolidated, change the following fields into the default values for consolidation
268             if (isConsolidated) {
269                 pendingEntry.setSubAccountNumber(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER);
270                 pendingEntry.setFinancialSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
271                 pendingEntry.setFinancialObjectTypeCode(Constant.CONSOLIDATED_OBJECT_TYPE_CODE);
272             }
273 
274             AccountBalance accountBalance = postAccountBalance.findAccountBalance(entryCollection, pendingEntry);
275             postAccountBalance.updateAccountBalance(pendingEntry, accountBalance);
276 
277             // recalculate the variance after pending entries are combined into account balances
278             if (accountBalance.getDummyBusinessObject() == null) {
279                 accountBalance.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
280             }
281             KualiDecimal variance = calculateVariance(accountBalance);
282             accountBalance.getDummyBusinessObject().setGenericAmount(variance);
283         }
284     }
285 
286     /**
287      * Sets the postAccountBalance attribute value.
288      * 
289      * @param postAccountBalance The postAccountBalance to set.
290      */
291     public void setPostAccountBalance(AccountBalanceCalculator postAccountBalance) {
292         this.postAccountBalance = postAccountBalance;
293     }
294 
295     /**
296      * Sets the accountBalanceService attribute value.
297      * 
298      * @param accountBalanceService The accountBalanceService to set.
299      */
300     public void setAccountBalanceService(AccountBalanceService accountBalanceService) {
301         this.accountBalanceService = accountBalanceService;
302     }
303 
304     /**
305      * Sets the optionsService attribute value
306      * 
307      * @param optionsService The optionsService to set.
308      */
309     public void setOptionsService(OptionsService optionsService) {
310         this.optionsService = optionsService;
311     }
312 
313     /**
314      * Gets the optionsService attribute. 
315      * @return Returns the optionsService.
316      */
317     public OptionsService getOptionsService() {
318         return optionsService;
319     }
320 }