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.businessobject.lookup;
017    
018    import java.util.ArrayList;
019    import java.util.Collection;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.Map;
023    
024    import org.kuali.kfs.gl.Constant;
025    import org.kuali.kfs.gl.OJBUtility;
026    import org.kuali.kfs.gl.batch.service.BalanceCalculator;
027    import org.kuali.kfs.gl.businessobject.Balance;
028    import org.kuali.kfs.gl.businessobject.TransientBalanceInquiryAttributes;
029    import org.kuali.kfs.gl.businessobject.inquiry.BalanceInquirableImpl;
030    import org.kuali.kfs.gl.service.BalanceService;
031    import org.kuali.kfs.sys.KFSConstants;
032    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
033    import org.kuali.rice.kns.bo.BusinessObject;
034    import org.kuali.rice.kns.lookup.HtmlData;
035    import org.kuali.rice.kns.util.KualiDecimal;
036    
037    /**
038     * An extension of KualiLookupableImpl to support balance lookups
039     */
040    public class BalanceLookupableHelperServiceImpl extends AbstractGeneralLedgerLookupableHelperServiceImpl {
041        private BalanceCalculator postBalance;
042        private BalanceService balanceService;
043        private Map fieldValues;
044    
045        /**
046         * Returns the url for any drill down links within the lookup
047         * @param bo the business object with a property being drilled down on
048         * @param propertyName the name of the property being drilled down on
049         * @return a String with the URL of the property
050         * @see org.kuali.rice.kns.lookup.Lookupable#getInquiryUrl(org.kuali.rice.kns.bo.BusinessObject, java.lang.String)
051         */
052        @Override
053        public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
054            return (new BalanceInquirableImpl()).getInquiryUrl(bo, propertyName);
055        }
056    
057        /**
058         * Generates the list of search results for this inquiry
059         * @param fieldValues the field values of the query to carry out
060         * @return List the search results returned by the lookup
061         * @see org.kuali.rice.kns.lookup.Lookupable#getSearchResults(java.util.Map)
062         */
063        @Override
064        public List getSearchResults(Map fieldValues) {
065            setBackLocation((String) fieldValues.get(KFSConstants.BACK_LOCATION));
066            setDocFormKey((String) fieldValues.get(KFSConstants.DOC_FORM_KEY));
067    
068            // get the pending entry option. This method must be prior to the get search results
069            String pendingEntryOption = this.getSelectedPendingEntryOption(fieldValues);
070    
071            // test if the consolidation option is selected or not
072            boolean isConsolidated = isConsolidationSelected(fieldValues);
073    
074            // get Amount View Option and determine if the results has to be accumulated
075            String amountViewOption = getSelectedAmountViewOption(fieldValues);
076            boolean isAccumulated = amountViewOption.equals(Constant.ACCUMULATE);
077    
078            // get the search result collection
079            Iterator balanceIterator = balanceService.findBalance(fieldValues, isConsolidated);
080            Collection searchResultsCollection = this.buildBalanceCollection(balanceIterator, isConsolidated, pendingEntryOption);
081    
082            // update search results according to the selected pending entry option
083            updateByPendingLedgerEntry(searchResultsCollection, fieldValues, pendingEntryOption, isConsolidated, false);
084    
085            // perform the accumulation of the amounts
086            this.accumulate(searchResultsCollection, isAccumulated);
087    
088            // get the actual size of all qualified search results
089            Integer recordCount = balanceService.getBalanceRecordCount(fieldValues, isConsolidated);
090            Long actualSize = OJBUtility.getResultActualSize(searchResultsCollection, recordCount, fieldValues, new Balance());
091    
092            return this.buildSearchResultList(searchResultsCollection, actualSize);
093        }
094    
095        /**
096         * This method builds the balance collection based on the input iterator
097         * 
098         * @param iterator the iterator of search results of balance
099         * @param isConsolidated determine if the consolidated result is desired
100         * @param pendingEntryOption the given pending entry option that can be no, approved or all
101         * @return the balance collection
102         */
103        private Collection buildBalanceCollection(Iterator iterator, boolean isConsolidated, String pendingEntryOption) {
104            Collection balanceCollection = null;
105    
106            if (isConsolidated) {
107                balanceCollection = buildConsolidatedBalanceCollection(iterator, pendingEntryOption);
108            }
109            else {
110                balanceCollection = buildDetailedBalanceCollection(iterator, pendingEntryOption);
111            }
112            return balanceCollection;
113        }
114    
115        /**
116         * This method builds the balance collection with consolidation option from an iterator
117         * 
118         * @param iterator th iterator of balance results
119         * @param pendingEntryOption the selected pending entry option
120         * @return the consolidated balance collection
121         */
122        private Collection buildConsolidatedBalanceCollection(Iterator iterator, String pendingEntryOption) {
123            Collection balanceCollection = new ArrayList();
124    
125            while (iterator.hasNext()) {
126                Object collectionEntry = iterator.next();
127    
128                if (collectionEntry.getClass().isArray()) {
129                    int i = 0;
130                    Object[] array = (Object[]) collectionEntry;
131                    Balance balance = new Balance();
132    
133                    balance.setUniversityFiscalYear(new Integer(array[i++].toString()));
134                    balance.setChartOfAccountsCode(array[i++].toString());
135                    balance.setAccountNumber(array[i++].toString());
136    
137                    String subAccountNumber = Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER;
138                    balance.setSubAccountNumber(subAccountNumber);
139    
140                    balance.setBalanceTypeCode(array[i++].toString());
141                    balance.setObjectCode(array[i++].toString());
142    
143                    balance.setSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
144                    balance.setObjectTypeCode(Constant.CONSOLIDATED_OBJECT_TYPE_CODE);
145    
146                    balance.setAccountLineAnnualBalanceAmount(new KualiDecimal(array[i++].toString()));
147                    balance.setBeginningBalanceLineAmount(new KualiDecimal(array[i++].toString()));
148                    balance.setContractsGrantsBeginningBalanceAmount(new KualiDecimal(array[i++].toString()));
149    
150                    balance.setMonth1Amount(new KualiDecimal(array[i++].toString()));
151                    balance.setMonth2Amount(new KualiDecimal(array[i++].toString()));
152                    balance.setMonth3Amount(new KualiDecimal(array[i++].toString()));
153                    balance.setMonth4Amount(new KualiDecimal(array[i++].toString()));
154                    balance.setMonth5Amount(new KualiDecimal(array[i++].toString()));
155                    balance.setMonth6Amount(new KualiDecimal(array[i++].toString()));
156                    balance.setMonth7Amount(new KualiDecimal(array[i++].toString()));
157                    balance.setMonth8Amount(new KualiDecimal(array[i++].toString()));
158                    balance.setMonth9Amount(new KualiDecimal(array[i++].toString()));
159    
160                    balance.setMonth10Amount(new KualiDecimal(array[i++].toString()));
161                    balance.setMonth11Amount(new KualiDecimal(array[i++].toString()));
162                    balance.setMonth12Amount(new KualiDecimal(array[i++].toString()));
163                    balance.setMonth13Amount(new KualiDecimal(array[i].toString()));
164    
165                    balance.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
166                    balance.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
167    
168                    balanceCollection.add(balance);
169                }
170            }
171            return balanceCollection;
172        }
173    
174        /**
175         * This method builds the balance collection with detail option from an iterator
176         * 
177         * @param iterator the balance iterator
178         * @param pendingEntryOption the selected pending entry option
179         * @return the detailed balance collection
180         */
181        private Collection buildDetailedBalanceCollection(Iterator iterator, String pendingEntryOption) {
182            Collection balanceCollection = new ArrayList();
183    
184            while (iterator.hasNext()) {
185                Balance balance = (Balance) (iterator.next());
186    
187                balance.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
188                balance.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
189    
190                balanceCollection.add(balance);
191            }
192            return balanceCollection;
193        }
194    
195        /**
196         * This method updates the balance collection with accumulated amounts if required (isAccumulated is true)
197         * 
198         * @param balanceCollection the balance collection to be updated
199         * @param isAccumulated determine if the accumulated result is desired
200         */
201        private void accumulate(Collection balanceCollection, boolean isAccumulated) {
202    
203            if (isAccumulated) {
204                for (Iterator iterator = balanceCollection.iterator(); iterator.hasNext();) {
205                    Balance balance = (Balance) (iterator.next());
206                    accumulateByBalance(balance, isAccumulated);
207                }
208            }
209        }
210    
211        /**
212         * This method computes the accumulate amount of the given balance and updates its fields
213         * 
214         * @param balance the given balance object
215         * @param isAccumulated determine if the accumulated result is desired
216         */
217        private void accumulateByBalance(Balance balance, boolean isAccumulated) {
218    
219            KualiDecimal annualAmount = balance.getAccountLineAnnualBalanceAmount();
220            KualiDecimal beginningAmount = balance.getBeginningBalanceLineAmount();
221            KualiDecimal CGBeginningAmount = balance.getContractsGrantsBeginningBalanceAmount();
222    
223            KualiDecimal month0Amount = beginningAmount.add(CGBeginningAmount);
224            KualiDecimal month1Amount = balance.getMonth1Amount();
225            month1Amount = accumulateAmount(month1Amount, month0Amount, isAccumulated);
226            balance.setMonth1Amount(month1Amount);
227    
228            KualiDecimal month2Amount = balance.getMonth2Amount();
229            month2Amount = accumulateAmount(month2Amount, month1Amount, isAccumulated);
230            balance.setMonth2Amount(month2Amount);
231    
232            KualiDecimal month3Amount = balance.getMonth3Amount();
233            month3Amount = accumulateAmount(month3Amount, month2Amount, isAccumulated);
234            balance.setMonth3Amount(month3Amount);
235    
236            KualiDecimal month4Amount = balance.getMonth4Amount();
237            month4Amount = accumulateAmount(month4Amount, month3Amount, isAccumulated);
238            balance.setMonth4Amount(month4Amount);
239    
240            KualiDecimal month5Amount = balance.getMonth5Amount();
241            month5Amount = accumulateAmount(month5Amount, month4Amount, isAccumulated);
242            balance.setMonth5Amount(month5Amount);
243    
244            KualiDecimal month6Amount = balance.getMonth6Amount();
245            month6Amount = accumulateAmount(month6Amount, month5Amount, isAccumulated);
246            balance.setMonth6Amount(month6Amount);
247    
248            KualiDecimal month7Amount = balance.getMonth7Amount();
249            month7Amount = accumulateAmount(month7Amount, month6Amount, isAccumulated);
250            balance.setMonth7Amount(month7Amount);
251    
252            KualiDecimal month8Amount = balance.getMonth8Amount();
253            month8Amount = accumulateAmount(month8Amount, month7Amount, isAccumulated);
254            balance.setMonth8Amount(month8Amount);
255    
256            KualiDecimal month9Amount = balance.getMonth9Amount();
257            month9Amount = accumulateAmount(month9Amount, month8Amount, isAccumulated);
258            balance.setMonth9Amount(month9Amount);
259    
260            KualiDecimal month10Amount = balance.getMonth10Amount();
261            month10Amount = accumulateAmount(month10Amount, month9Amount, isAccumulated);
262            balance.setMonth10Amount(month10Amount);
263    
264            KualiDecimal month11Amount = balance.getMonth11Amount();
265            month11Amount = accumulateAmount(month11Amount, month10Amount, isAccumulated);
266            balance.setMonth11Amount(month11Amount);
267    
268            KualiDecimal month12Amount = balance.getMonth12Amount();
269            month12Amount = accumulateAmount(month12Amount, month11Amount, isAccumulated);
270            balance.setMonth12Amount(month12Amount);
271    
272            KualiDecimal month13Amount = balance.getMonth13Amount();
273            month13Amount = accumulateAmount(month13Amount, month12Amount, isAccumulated);
274            balance.setMonth13Amount(month13Amount);
275        }
276    
277        /**
278         * This method converts the amount from String and adds it with the input addend
279         * 
280         * @param stringAugend a String-type augend
281         * @param addend an addend
282         * @param isAccumulated determine if the accumulated result is desired
283         * @return the accumulated amount if accumulate option is selected; otherwise, the input amount itself
284         */
285        private KualiDecimal accumulateAmount(Object stringAugend, KualiDecimal addend, boolean isAccumulated) {
286    
287            KualiDecimal augend = new KualiDecimal(stringAugend.toString());
288            if (isAccumulated) {
289                augend = augend.add(addend);
290            }
291            return augend;
292        }
293    
294        /**
295         * Updates pending entries before their results are included in the lookup results
296         * 
297         * @param entryCollection a collection of balance entries
298         * @param fieldValues the map containing the search fields and values
299         * @param isApproved flag whether the approved entries or all entries will be processed
300         * @param isConsolidated flag whether the results are consolidated or not
301         * @param isCostShareExcluded flag whether the user selects to see the results with cost share subaccount
302         * @see org.kuali.module.gl.web.lookupable.AbstractGLLookupableImpl#updateEntryCollection(java.util.Collection, java.util.Map,
303         *      boolean, boolean, boolean)
304         */
305        public void updateEntryCollection(Collection entryCollection, Map fieldValues, boolean isApproved, boolean isConsolidated, boolean isCostShareInclusive) {
306    
307            // convert the field names of balance object into corresponding ones of pending entry object
308            Map pendingEntryFieldValues = BusinessObjectFieldConverter.convertToTransactionFieldValues(fieldValues);
309    
310            // go through the pending entries to update the balance collection
311            Iterator pendingEntryIterator = getGeneralLedgerPendingEntryService().findPendingLedgerEntriesForBalance(pendingEntryFieldValues, isApproved);
312            while (pendingEntryIterator.hasNext()) {
313                GeneralLedgerPendingEntry pendingEntry = (GeneralLedgerPendingEntry) pendingEntryIterator.next();
314    
315                // if consolidated, change the following fields into the default values for consolidation
316                if (isConsolidated) {
317                    pendingEntry.setSubAccountNumber(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER);
318                    pendingEntry.setFinancialSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
319                    pendingEntry.setFinancialObjectTypeCode(Constant.CONSOLIDATED_OBJECT_TYPE_CODE);
320                }
321    
322                Balance balance = postBalance.findBalance(entryCollection, pendingEntry);
323    
324                String pendingEntryOption = isApproved ? Constant.APPROVED_PENDING_ENTRY : Constant.ALL_PENDING_ENTRY;
325                balance.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
326                balance.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
327    
328                postBalance.updateBalance(pendingEntry, balance);
329            }
330        }
331    
332        /**
333         * Sets the postBalance attribute value.
334         * 
335         * @param postBalance The postBalance to set.
336         */
337        public void setPostBalance(BalanceCalculator postBalance) {
338            this.postBalance = postBalance;
339        }
340    
341        /**
342         * Sets the balanceService attribute value.
343         * 
344         * @param balanceService The balanceService to set.
345         */
346        public void setBalanceService(BalanceService balanceService) {
347            this.balanceService = balanceService;
348        }
349    
350    }