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.Collection;
019    import java.util.Collections;
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.gl.Constant;
026    import org.kuali.kfs.sys.KFSPropertyConstants;
027    import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
028    import org.kuali.rice.kns.bo.BusinessObject;
029    import org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl;
030    import org.kuali.rice.kns.lookup.CollectionIncomplete;
031    import org.kuali.rice.kns.lookup.HtmlData;
032    import org.kuali.rice.kns.util.BeanPropertyComparator;
033    import org.kuali.rice.kns.web.ui.Field;
034    import org.kuali.rice.kns.web.ui.Row;
035    
036    /**
037     * The abstract parent class for GL Lookupables, providing base implementations of methods
038     * to make adding new lookupable reports easier
039     */
040    public abstract class AbstractGeneralLedgerLookupableHelperServiceImpl extends AbstractLookupableHelperServiceImpl {
041    
042        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AbstractGeneralLedgerLookupableHelperServiceImpl.class);
043    
044        private GeneralLedgerPendingEntryService generalLedgerPendingEntryService;
045    
046        protected GeneralLedgerPendingEntryService getGeneralLedgerPendingEntryService() {
047            return generalLedgerPendingEntryService;
048        }
049    
050        public void setGeneralLedgerPendingEntryService(GeneralLedgerPendingEntryService generalLedgerPendingEntryService) {
051            this.generalLedgerPendingEntryService = generalLedgerPendingEntryService;
052        }
053    
054        /**
055         * This method overides that in parent class so that the maintainance actions are surpressed
056         *
057         * @returns links to edit and copy maintenance action for the current maintenance record. For GL balance inquire, there are no
058         *          maintenance links.
059         */
060        @Override
061        public List<HtmlData> getCustomActionUrls(BusinessObject bo, List pkNames) {
062            return super.getEmptyActionUrls();
063        }
064    
065        /**
066         * This method tests if the user selects to see the general ledager pending entries
067         *
068         * @param fieldValues the map containing the search fields and values
069         * @return the value of pending entry option
070         */
071        protected String getSelectedPendingEntryOption(Map fieldValues) {
072            // truncate the non-property filed
073            String pendingEntryOption = (String) fieldValues.get(Constant.PENDING_ENTRY_OPTION);
074            fieldValues.remove(Constant.PENDING_ENTRY_OPTION);
075    
076            return pendingEntryOption;
077        }
078    
079        /**
080         * This method tests if the user selects to see the reports by monthly or accumulated
081         *
082         * @param fieldValues the map containing the search fields and values
083         * @return the value of amount view option
084         */
085        protected String getSelectedAmountViewOption(Map fieldValues) {
086    
087            String amountViewOption = Constant.EMPTY_STRING;
088            if (fieldValues.containsKey(Constant.AMOUNT_VIEW_OPTION)) {
089                amountViewOption = (String) fieldValues.get(Constant.AMOUNT_VIEW_OPTION);
090    
091                // truncate the non-property filed
092                fieldValues.remove(Constant.AMOUNT_VIEW_OPTION);
093            }
094            return amountViewOption;
095        }
096    
097        /**
098         * This method tests if the user selects to see the details or consolidated results
099         *
100         * @param fieldValues the map containing the search fields and values
101         * @return true if consolidation is selected and subaccount is not specified
102         */
103        protected boolean isConsolidationSelected(Map fieldValues) {
104            // truncate the non-property filed
105            String consolidationOption = (String) fieldValues.get(Constant.CONSOLIDATION_OPTION);
106            fieldValues.remove(Constant.CONSOLIDATION_OPTION);
107    
108            // detail option would be used
109            if (Constant.DETAIL.equals(consolidationOption)) {
110                return false;
111            }
112    
113            // if the subAccountNumber is specified, detail option could be used
114            String subAccountNumber = (String) fieldValues.get(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
115            if (!StringUtils.isBlank(subAccountNumber)) {
116                this.changeFieldValue(Constant.CONSOLIDATION_OPTION, Constant.DETAIL);
117                return false;
118            }
119    
120            // if the subObjectCode is specified, detail option could be used
121            String subObjectCode = (String) fieldValues.get(KFSPropertyConstants.SUB_OBJECT_CODE);
122            if (!StringUtils.isBlank(subObjectCode)) {
123                this.changeFieldValue(Constant.CONSOLIDATION_OPTION, Constant.DETAIL);
124                return false;
125            }
126    
127            // if the objectTypeCode is specified, detail option could be used
128            String objectTypeCode = (String) fieldValues.get(KFSPropertyConstants.OBJECT_TYPE_CODE);
129            if (!StringUtils.isBlank(objectTypeCode)) {
130                this.changeFieldValue(Constant.CONSOLIDATION_OPTION, Constant.DETAIL);
131                return false;
132            }
133            return true;
134        }
135    
136        /**
137         * This method tests if the user selects to see the results with cost share subaccount
138         *
139         * @param fieldValues the map containing the search fields and values
140         * @return true if inclusive option is selected
141         */
142        protected boolean isCostShareInclusive(Map fieldValues) {
143            // TODO: is this method being called?
144            // truncate the non-property filed
145            String costShareOption = (String) fieldValues.get(Constant.COST_SHARE_OPTION);
146            fieldValues.remove(Constant.COST_SHARE_OPTION);
147    
148            if (costShareOption.equals(Constant.COST_SHARE_INCLUDE)) {
149                return true;
150            }
151            return false;
152        }
153    
154    
155        /**
156         * build the serach result list from the given collection and the number of all qualified search results
157         *
158         * @param searchResultsCollection the given search results, which may be a subset of the qualified search results
159         * @param actualSize the number of all qualified search results
160         * @return the serach result list with the given results and actual size
161         */
162        protected List buildSearchResultList(Collection searchResultsCollection, Long actualSize) {
163            CollectionIncomplete results = new CollectionIncomplete(searchResultsCollection, actualSize);
164    
165            // sort list if default sort column given
166            List searchResults = (List) results;
167            List defaultSortColumns = getDefaultSortColumns();
168            if (defaultSortColumns.size() > 0) {
169                Collections.sort(results, new BeanPropertyComparator(defaultSortColumns, true));
170            }
171            return searchResults;
172        }
173    
174        /**
175         * This method is used to update amounts of the given entries with the corresponding pending amounts. It is a factory that
176         * executes the update methods of individual derived classes.
177         *
178         * @param entryCollection a collection of balance entries
179         * @param fieldValues the map containing the search fields and values
180         * @param pendingEntryOption flag whether the approved entries or all entries will be processed
181         * @param isCostShareInclusive flag whether the user selects to see the results with cost share subaccount
182         * @param isConsolidated flag whether the results are consolidated or not
183         */
184        protected void updateByPendingLedgerEntry(Collection entryCollection, Map fieldValues, String pendingEntryOption, boolean isConsolidated, boolean isCostShareInclusive) {
185    
186            // determine if search results need to be updated by pending ledger entries
187            if (Constant.ALL_PENDING_ENTRY.equals(pendingEntryOption)) {
188                updateEntryCollection(entryCollection, fieldValues, false, isConsolidated, isCostShareInclusive);
189            }
190            else if (Constant.APPROVED_PENDING_ENTRY.equals(pendingEntryOption)) {
191                updateEntryCollection(entryCollection, fieldValues, true, isConsolidated, isCostShareInclusive);
192            }
193        }
194    
195        /**
196         * This method is an abstract method and implemented to update the given entry collection by the children classes. It is called
197         * by updateByPendingLedgerEntry method.
198         *
199         * @param entryCollection a collection of balance entries
200         * @param fieldValues the map containing the search fields and values
201         * @param isApproved flag whether the approved entries or all entries will be processed
202         * @param isCostShareInclusive flag whether the user selects to see the results with cost share subaccount
203         * @param isConsolidated flag whether the results are consolidated or not
204         */
205        protected abstract void updateEntryCollection(Collection entryCollection, Map fieldValues, boolean isApproved, boolean isConsolidated, boolean isCostShareInclusive);
206    
207        // change the value of the field with the given field name into the given field value
208        private void changeFieldValue(String fieldName, String fieldValue) {
209            for (Iterator rowIterator = getRows().iterator(); rowIterator.hasNext();) {
210                Row row = (Row) rowIterator.next();
211    
212                for (Iterator fieldIterator = row.getFields().iterator(); fieldIterator.hasNext();) {
213                    Field field = (Field) fieldIterator.next();
214    
215                    if (field.getPropertyName().equals(fieldName)) {
216                        field.setPropertyValue(fieldValue);
217                    }
218                }
219            }
220        }
221    }