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.module.ld.businessobject.lookup;
017    
018    import static org.kuali.kfs.module.ld.LaborConstants.BalanceInquiries.EMPLOYEE_FUNDING_EXPENSE_OBJECT_TYPE_CODE;
019    import static org.kuali.kfs.module.ld.LaborConstants.BalanceInquiries.EMPLOYEE_FUNDING_NORMAL_OP_EXPENSE_OBJECT_TYPE_CODE;
020    
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.Collections;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    
029    import org.apache.commons.lang.ArrayUtils;
030    import org.apache.commons.lang.StringUtils;
031    import org.kuali.kfs.gl.Constant;
032    import org.kuali.kfs.module.ld.businessobject.EmployeeFunding;
033    import org.kuali.kfs.module.ld.businessobject.LaborLedgerPendingEntry;
034    import org.kuali.kfs.module.ld.businessobject.inquiry.AbstractLaborInquirableImpl;
035    import org.kuali.kfs.module.ld.businessobject.inquiry.EmployeeFundingInquirableImpl;
036    import org.kuali.kfs.module.ld.businessobject.inquiry.PositionDataDetailsInquirableImpl;
037    import org.kuali.kfs.module.ld.service.LaborInquiryOptionsService;
038    import org.kuali.kfs.module.ld.service.LaborLedgerBalanceService;
039    import org.kuali.kfs.module.ld.service.LaborLedgerPendingEntryService;
040    import org.kuali.kfs.module.ld.util.DebitCreditUtil;
041    import org.kuali.kfs.sys.KFSConstants;
042    import org.kuali.kfs.sys.KFSPropertyConstants;
043    import org.kuali.kfs.sys.ObjectUtil;
044    import org.kuali.rice.kns.bo.BusinessObject;
045    import org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl;
046    import org.kuali.rice.kns.lookup.CollectionIncomplete;
047    import org.kuali.rice.kns.lookup.HtmlData;
048    import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
049    import org.kuali.rice.kns.util.BeanPropertyComparator;
050    import org.kuali.rice.kns.util.KualiDecimal;
051    
052    /**
053     * The EmployeeFundingLookupableHelperServiceImpl class is the front-end for all Employee Funding balance inquiry processing.
054     */
055    public class EmployeeFundingLookupableHelperServiceImpl extends AbstractLookupableHelperServiceImpl {
056        private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory.getLog(EmployeeFundingLookupableHelperServiceImpl.class);
057    
058        private LaborLedgerBalanceService laborLedgerBalanceService;
059        private LaborInquiryOptionsService laborInquiryOptionsService;
060        private LaborLedgerPendingEntryService laborLedgerPendingEntryService;
061    
062        /**
063         * @see org.kuali.rice.kns.lookup.Lookupable#getInquiryUrl(org.kuali.rice.kns.bo.BusinessObject, java.lang.String)
064         */
065        @Override
066        public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
067            if (KFSPropertyConstants.POSITION_NUMBER.equals(propertyName)) {
068                EmployeeFunding employeeFunding = (EmployeeFunding) bo;
069                AbstractLaborInquirableImpl positionDataDetailsInquirable = new PositionDataDetailsInquirableImpl();
070    
071                Map<String, String> fieldValues = new HashMap<String, String>();
072                fieldValues.put(propertyName, employeeFunding.getPositionNumber());
073    
074                BusinessObject positionData = positionDataDetailsInquirable.getBusinessObject(fieldValues);
075    
076                return positionData == null ? new AnchorHtmlData(KFSConstants.EMPTY_STRING, KFSConstants.EMPTY_STRING) : positionDataDetailsInquirable.getInquiryUrl(positionData, propertyName);
077            }
078    
079            return (new EmployeeFundingInquirableImpl()).getInquiryUrl(bo, propertyName);
080        }
081    
082        /**
083         * @see org.kuali.rice.kns.lookup.Lookupable#gfetSearchResults(java.util.Map)
084         */
085        @Override
086        public List getSearchResults(Map fieldValues) {
087            setBackLocation((String) fieldValues.get(KFSConstants.BACK_LOCATION));
088            setDocFormKey((String) fieldValues.get(KFSConstants.DOC_FORM_KEY));
089    
090            boolean showBlankLine = this.showBlankLines(fieldValues);
091            fieldValues.remove(Constant.BLANK_LINE_OPTION);
092    
093            // get the pending entry option. This method must be prior to the get search results
094            String pendingEntryOption = laborInquiryOptionsService.getSelectedPendingEntryOption(fieldValues);
095    
096            // test if the consolidation option is selected or not
097            boolean isConsolidated = false;
098    
099            Collection<EmployeeFunding> searchResultsCollection = laborLedgerBalanceService.findEmployeeFundingWithCSFTracker(fieldValues, isConsolidated);
100    
101            if (!showBlankLine) {
102                Collection<EmployeeFunding> tempSearchResultsCollection = new ArrayList<EmployeeFunding>();
103                for (EmployeeFunding employeeFunding : searchResultsCollection) {
104                    if (employeeFunding.getCurrentAmount().isNonZero() || employeeFunding.getOutstandingEncumbrance().isNonZero()) {
105                        tempSearchResultsCollection.add(employeeFunding);
106                    }
107                }
108                searchResultsCollection = tempSearchResultsCollection;
109            }
110    
111            // update search results according to the selected pending entry option
112            updateByPendingLedgerEntry(searchResultsCollection, fieldValues, pendingEntryOption, isConsolidated);
113    
114            // get the actual size of all qualified search results
115            Long actualSize = new Long(searchResultsCollection.size());
116    
117            return this.buildSearchResultList(searchResultsCollection, actualSize);
118        }
119    
120        private boolean showBlankLines(Map fieldValues) {
121            String pendingEntryOption = (String) fieldValues.get(Constant.BLANK_LINE_OPTION);
122            return Constant.SHOW_BLANK_LINE.equals(pendingEntryOption) ? true : false;
123        }
124    
125        /**
126         * build the serach result list from the given collection and the number of all qualified search results
127         * 
128         * @param searchResultsCollection the given search results, which may be a subset of the qualified search results
129         * @param actualSize the number of all qualified search results
130         * @return the serach result list with the given results and actual size
131         */
132        protected List buildSearchResultList(Collection searchResultsCollection, Long actualSize) {
133            CollectionIncomplete results = new CollectionIncomplete(searchResultsCollection, actualSize);
134    
135            // sort list if default sort column given
136            List searchResults = (List) results;
137            List defaultSortColumns = getDefaultSortColumns();
138            if (defaultSortColumns.size() > 0) {
139                Collections.sort(results, new BeanPropertyComparator(defaultSortColumns, true));
140            }
141            return searchResults;
142        }
143    
144        /**
145         * @see org.kuali.kfs.module.ld.service.LaborInquiryOptionsService#updateByPendingLedgerEntry(java.util.Collection,
146         *      java.util.Map, java.lang.String, boolean)
147         */
148        public void updateByPendingLedgerEntry(Collection entryCollection, Map fieldValues, String pendingEntryOption, boolean isConsolidated) {
149    
150            // determine if search results need to be updated by pending ledger entries
151            if (Constant.ALL_PENDING_ENTRY.equals(pendingEntryOption)) {
152                updateEntryCollection(entryCollection, fieldValues, false, isConsolidated);
153            }
154            else if (Constant.APPROVED_PENDING_ENTRY.equals(pendingEntryOption)) {
155                updateEntryCollection(entryCollection, fieldValues, true, isConsolidated);
156            }
157        }
158    
159        /**
160         * @see org.kuali.kfs.module.ld.service.LaborInquiryOptionsService#updateEntryCollection(java.util.Collection, java.util.Map,
161         *      boolean, boolean)
162         */
163        public void updateEntryCollection(Collection entryCollection, Map fieldValues, boolean isApproved, boolean isConsolidated) {
164            // go through the pending entries to update the balance collection
165            Iterator<LaborLedgerPendingEntry> pendingEntryIterator = laborLedgerPendingEntryService.findPendingLedgerEntriesForLedgerBalance(fieldValues, isApproved);
166    
167            while (pendingEntryIterator.hasNext()) {
168                LaborLedgerPendingEntry pendingEntry = pendingEntryIterator.next();
169    
170                if (!isEmployeeFunding(pendingEntry)) {
171                    continue;
172                }
173    
174                // if consolidated, change the following fields into the default values for consolidation
175                if (isConsolidated) {
176                    pendingEntry.setSubAccountNumber(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER);
177                    pendingEntry.setFinancialSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
178                    pendingEntry.setFinancialObjectTypeCode(Constant.CONSOLIDATED_OBJECT_TYPE_CODE);
179                }
180    
181                EmployeeFunding ledgerBalance = (EmployeeFunding) laborLedgerBalanceService.findLedgerBalance(entryCollection, pendingEntry, getKeyList());
182                if (ledgerBalance == null) {
183                    ledgerBalance = new EmployeeFunding();
184                    ObjectUtil.buildObject(ledgerBalance, pendingEntry);
185                    entryCollection.add(ledgerBalance);
186                }
187                else {
188                    laborLedgerBalanceService.updateLedgerBalance(ledgerBalance, pendingEntry);
189                }
190                updateAmount(ledgerBalance, pendingEntry);
191            }
192        }
193    
194        /**
195         * update the amount of the given employee funding with the given pending entry
196         * 
197         * @param employeeFunding the given employee funding
198         * @param pendingEntry the given pending entry
199         */
200        private void updateAmount(EmployeeFunding employeeFunding, LaborLedgerPendingEntry pendingEntry) {
201            String balanceTypeCode = pendingEntry.getFinancialBalanceTypeCode();
202            String debitCreditCode = pendingEntry.getTransactionDebitCreditCode();
203            KualiDecimal amount = DebitCreditUtil.getNumericAmount(pendingEntry.getTransactionLedgerEntryAmount(), pendingEntry.getTransactionDebitCreditCode());
204    
205            if (StringUtils.equals(balanceTypeCode, KFSConstants.BALANCE_TYPE_ACTUAL)) {
206                employeeFunding.setCurrentAmount(amount.add(employeeFunding.getCurrentAmount()));
207            }
208            else if (StringUtils.equals(balanceTypeCode, KFSConstants.BALANCE_TYPE_INTERNAL_ENCUMBRANCE)) {
209                employeeFunding.setOutstandingEncumbrance(amount.add(employeeFunding.getOutstandingEncumbrance()));
210            }
211        }
212    
213        /**
214         * determine whether the given pending entry is qualified to be processed as an employee funding
215         * 
216         * @param pendingEntry the given pending entry
217         * @return true if the given pending entry is qualified to be processed as an employee funding; otherwise, false
218         */
219        private boolean isEmployeeFunding(LaborLedgerPendingEntry pendingEntry) {
220            String balanceTypeCode = pendingEntry.getFinancialBalanceTypeCode();
221    
222            if (StringUtils.equals(balanceTypeCode, KFSConstants.BALANCE_TYPE_ACTUAL)) {
223                String objectTypeCode = pendingEntry.getFinancialObjectTypeCode();
224                String[] objectTypeCodes = { EMPLOYEE_FUNDING_EXPENSE_OBJECT_TYPE_CODE, EMPLOYEE_FUNDING_NORMAL_OP_EXPENSE_OBJECT_TYPE_CODE };
225    
226                return ArrayUtils.contains(objectTypeCodes, objectTypeCode) ? true : false;
227            }
228    
229            if (StringUtils.equals(balanceTypeCode, KFSConstants.BALANCE_TYPE_INTERNAL_ENCUMBRANCE)) {
230                return true;
231            }
232    
233            return false;
234        }
235    
236        /**
237         * construct the primary key list of the business object
238         * 
239         * @return the primary key list of the business object
240         */
241        private List<String> getKeyList() {
242            List<String> keyList = new ArrayList<String>();
243            keyList.add(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR);
244            keyList.add(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE);
245            keyList.add(KFSPropertyConstants.ACCOUNT_NUMBER);
246            keyList.add(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
247            keyList.add(KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
248            keyList.add(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE);
249            keyList.add(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE);
250            keyList.add(KFSPropertyConstants.POSITION_NUMBER);
251            keyList.add(KFSPropertyConstants.EMPLID);
252            return keyList;
253        }
254    
255        /**
256         * Sets the laborLedgerBalanceService attribute value.
257         * 
258         * @param laborLedgerBalanceService The laborLedgerBalanceService to set.
259         */
260        public void setLaborLedgerBalanceService(LaborLedgerBalanceService laborLedgerBalanceService) {
261            this.laborLedgerBalanceService = laborLedgerBalanceService;
262        }
263    
264        /**
265         * Sets the laborInquiryOptionsService attribute value.
266         * 
267         * @param laborInquiryOptionsService The laborInquiryOptionsService to set.
268         */
269        public void setLaborInquiryOptionsService(LaborInquiryOptionsService laborInquiryOptionsService) {
270            this.laborInquiryOptionsService = laborInquiryOptionsService;
271        }
272    
273        /**
274         * Sets the laborLedgerPendingEntryService attribute value.
275         * 
276         * @param laborLedgerPendingEntryService The laborLedgerPendingEntryService to set.
277         */
278        public void setLaborLedgerPendingEntryService(LaborLedgerPendingEntryService laborLedgerPendingEntryService) {
279            this.laborLedgerPendingEntryService = laborLedgerPendingEntryService;
280        }
281    }