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.apache.commons.lang.StringUtils;
025    import org.kuali.kfs.coa.businessobject.Account;
026    import org.kuali.kfs.gl.Constant;
027    import org.kuali.kfs.gl.OJBUtility;
028    import org.kuali.kfs.gl.batch.service.BalanceCalculator;
029    import org.kuali.kfs.gl.businessobject.Balance;
030    import org.kuali.kfs.gl.businessobject.CashBalance;
031    import org.kuali.kfs.gl.businessobject.inquiry.CashBalanceInquirableImpl;
032    import org.kuali.kfs.gl.service.BalanceService;
033    import org.kuali.kfs.sys.KFSConstants;
034    import org.kuali.kfs.sys.KFSPropertyConstants;
035    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
036    import org.kuali.kfs.sys.businessobject.UniversityDate;
037    import org.kuali.kfs.sys.context.SpringContext;
038    import org.kuali.kfs.sys.service.UniversityDateService;
039    import org.kuali.rice.kns.bo.BusinessObject;
040    import org.kuali.rice.kns.lookup.HtmlData;
041    import org.kuali.rice.kns.util.KualiDecimal;
042    import org.kuali.rice.kns.util.ObjectUtils;
043    import org.kuali.rice.kns.web.ui.Field;
044    import org.kuali.rice.kns.web.ui.Row;
045    
046    /**
047     * An extension of KualiLookupableImpl to support cash lookups
048     */
049    public class CashBalanceLookupableHelperServiceImpl extends AbstractGeneralLedgerLookupableHelperServiceImpl {
050        private BalanceCalculator postBalance;
051        private BalanceService balanceService;
052    
053        /**
054         * Returns the URL for inquiries on fields returned in the lookup
055         * @param bo the business object the field to inquiry on is in
056         * @param propertyName the name of the property that an inquiry url is being asked of
057         * @return the String of the url
058         * @see org.kuali.rice.kns.lookup.Lookupable#getInquiryUrl(org.kuali.rice.kns.bo.BusinessObject, java.lang.String)
059         */
060        @Override
061        public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
062            return (new CashBalanceInquirableImpl()).getInquiryUrl(bo, propertyName);
063        }
064    
065        /**
066         * Generates a list of results for this inquiry
067         * @param fieldValues the field values that the user entered for this inquiry
068         * @return a List of results
069         * @see org.kuali.rice.kns.lookup.Lookupable#getSearchResults(java.util.Map)
070         */
071        @Override
072        public List getSearchResults(Map fieldValues) {
073            setBackLocation((String) fieldValues.get(KFSConstants.BACK_LOCATION));
074            setDocFormKey((String) fieldValues.get(KFSConstants.DOC_FORM_KEY));
075    
076            // get the pending entry option. This method must be prior to the get search results
077            String pendingEntryOption = getSelectedPendingEntryOption(fieldValues);
078    
079            // get the consolidation option
080            boolean isConsolidated = isConsolidationSelected(fieldValues);
081    
082            // get the search result collection
083            Iterator cashBalanceIterator = balanceService.findCashBalance(fieldValues, isConsolidated);
084            Collection searchResultsCollection = this.buildCashBalanceCollection(cashBalanceIterator, isConsolidated);
085    
086            // update search results according to the selected pending entry option
087            updateByPendingLedgerEntry(searchResultsCollection, fieldValues, pendingEntryOption, isConsolidated, false);
088    
089            // get the actual size of all qualified search results
090            Integer recordCount = balanceService.getCashBalanceRecordCount(fieldValues, isConsolidated);
091            Long actualSize = OJBUtility.getResultActualSize(searchResultsCollection, recordCount, fieldValues, new Balance());
092    
093            return this.buildSearchResultList(searchResultsCollection, actualSize);
094        }
095    
096        /**
097         * This method builds the cash balance collection based on the input iterator
098         * 
099         * @param iterator the iterator of search results of avaiable cash balance
100         * @return the cash balance collection
101         */
102        private Collection buildCashBalanceCollection(Iterator iterator, boolean isConsolidated) {
103            Collection balanceCollection = new ArrayList();
104    
105            while (iterator.hasNext()) {
106                Object cashBalance = iterator.next();
107    
108                if (cashBalance.getClass().isArray()) {
109                    int i = 0;
110                    Object[] array = (Object[]) cashBalance;
111                    Balance balance = new CashBalance();
112    
113                    balance.setUniversityFiscalYear(new Integer(array[i++].toString()));
114                    balance.setChartOfAccountsCode(array[i++].toString());
115                    balance.setAccountNumber(array[i++].toString());
116    
117                    String subAccountNumber = isConsolidated ? Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER : array[i++].toString();
118                    balance.setSubAccountNumber(subAccountNumber);
119    
120                    balance.setBalanceTypeCode(array[i++].toString());
121                    balance.setObjectCode(array[i++].toString());
122    
123                    String subObjectCode = isConsolidated ? Constant.CONSOLIDATED_SUB_OBJECT_CODE : array[i++].toString();
124                    balance.setSubObjectCode(subObjectCode);
125    
126                    String objectTypeCode = isConsolidated ? Constant.CONSOLIDATED_OBJECT_TYPE_CODE : array[i++].toString();
127                    balance.setObjectTypeCode(objectTypeCode);
128    
129                    KualiDecimal annualAmount = new KualiDecimal(array[i++].toString());
130                    balance.setAccountLineAnnualBalanceAmount(annualAmount);
131    
132                    KualiDecimal beginningAmount = new KualiDecimal(array[i++].toString());
133                    balance.setBeginningBalanceLineAmount(beginningAmount);
134    
135                    KualiDecimal CGBeginningAmount = new KualiDecimal(array[i].toString());
136                    balance.setContractsGrantsBeginningBalanceAmount(CGBeginningAmount);
137    
138                    KualiDecimal totalAvailableAmount = this.getTotalAvailableCashAmount(balance);
139                    balance.getDummyBusinessObject().setGenericAmount(totalAvailableAmount);
140    
141                    balanceCollection.add(balance);
142                }
143            }
144            return balanceCollection;
145        }
146    
147        /**
148         * Allows an updating of pending entry records before they are applied to the inquiry results
149         * 
150         * @param entryCollection a collection of balance entries
151         * @param fieldValues the map containing the search fields and values
152         * @param isApproved flag whether the approved entries or all entries will be processed
153         * @param isConsolidated flag whether the results are consolidated or not
154         * @param isCostShareExcluded flag whether the user selects to see the results with cost share subaccount
155         * @see org.kuali.module.gl.web.lookupable.AbstractGLLookupableImpl#updateEntryCollection(java.util.Collection, java.util.Map,
156         *      boolean, boolean, boolean)
157         */
158        @Override
159        protected void updateEntryCollection(Collection entryCollection, Map fieldValues, boolean isApproved, boolean isConsolidated, boolean isCostShareInclusive) {
160    
161            // convert the field names of balance object into corresponding ones of pending entry object
162            Map pendingEntryFieldValues = BusinessObjectFieldConverter.convertToTransactionFieldValues(fieldValues);
163    
164            UniversityDate today = SpringContext.getBean(UniversityDateService.class).getCurrentUniversityDate();
165            String currentFiscalPeriodCode = today.getUniversityFiscalAccountingPeriod();
166            Integer currentFiscalYear = today.getUniversityFiscalYear();
167    
168            // use the pending entry to update the input entry collection
169            Iterator pendingEntryIterator = getGeneralLedgerPendingEntryService().findPendingLedgerEntriesForCashBalance(pendingEntryFieldValues, isApproved);
170            while (pendingEntryIterator.hasNext()) {
171                GeneralLedgerPendingEntry pendingEntry = (GeneralLedgerPendingEntry) pendingEntryIterator.next();
172    
173                // Fix the fiscal period/year if they are null
174                // Don't want to use the GLPE service.fillInFiscalPeriodYear. It totally kills performance.
175                // generalLedgerPendingEntryService.fillInFiscalPeriodYear(pendingEntry);
176    
177                if (pendingEntry.getUniversityFiscalYear() == null) {
178                    pendingEntry.setUniversityFiscalYear(currentFiscalYear);
179                }
180    
181                if (pendingEntry.getUniversityFiscalPeriodCode() == null) {
182                    pendingEntry.setUniversityFiscalPeriodCode(currentFiscalPeriodCode);
183                }
184    
185                // if consolidated, change the following fields into the default values for consolidation
186                if (isConsolidated) {
187                    pendingEntry.setSubAccountNumber(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER);
188                    pendingEntry.setFinancialSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
189                    pendingEntry.setFinancialObjectTypeCode(Constant.CONSOLIDATED_OBJECT_TYPE_CODE);
190                }
191                Balance balance = postBalance.findBalance(entryCollection, pendingEntry);
192                postBalance.updateBalance(pendingEntry, balance);
193    
194                KualiDecimal totalAvailableAmount = this.getTotalAvailableCashAmount(balance);
195                balance.getDummyBusinessObject().setGenericAmount(totalAvailableAmount);
196            }
197        }
198    
199        // calculate the total available cash amont of the given balance record
200        private KualiDecimal getTotalAvailableCashAmount(Balance balance) {
201            KualiDecimal annualAmount = balance.getAccountLineAnnualBalanceAmount();
202            KualiDecimal beginningAmount = balance.getBeginningBalanceLineAmount();
203            KualiDecimal CGBeginningAmount = balance.getContractsGrantsBeginningBalanceAmount();
204    
205            KualiDecimal totalAvailableAmount = annualAmount.add(beginningAmount);
206            totalAvailableAmount = totalAvailableAmount.add(CGBeginningAmount);
207    
208            return totalAvailableAmount;
209        }
210    
211        /**
212         * Sets the postBalance attribute value.
213         * 
214         * @param postBalance The postBalance to set.
215         */
216        public void setPostBalance(BalanceCalculator postBalance) {
217            this.postBalance = postBalance;
218        }
219    
220        /**
221         * Sets the balanceService attribute value.
222         * 
223         * @param balanceService The balanceService to set.
224         */
225        public void setBalanceService(BalanceService balanceService) {
226            this.balanceService = balanceService;
227        }
228    
229        @Override
230        public List<Row> getRows() {
231            // TODO Auto-generated method stub
232            List<Row> rows = super.getRows();
233            
234            //look for field and replace BO class
235            for (Iterator iter = rows.iterator(); iter.hasNext();) {
236                Row row = (Row) iter.next();                
237                for (Iterator iterator = row.getFields().iterator(); iterator.hasNext();) {
238                        Field field = (Field) iterator.next();
239                        
240                        if(ObjectUtils.isNotNull(field) && StringUtils.equalsIgnoreCase(field.getPropertyName(), KFSPropertyConstants.ACCOUNT_NUMBER)){                        
241                            field.setQuickFinderClassNameImpl(Account.class.getName());
242                        }
243                }
244            }
245            
246            return rows;
247        }
248    
249    }