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.util;
017    
018    import java.util.ArrayList;
019    import java.util.Arrays;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    import org.apache.commons.lang.StringUtils;
026    import org.apache.ojb.broker.query.ReportQueryByCriteria;
027    import org.kuali.kfs.module.ld.LaborConstants;
028    import org.kuali.kfs.module.ld.businessobject.LedgerBalance;
029    import org.kuali.kfs.sys.KFSPropertyConstants;
030    import org.kuali.kfs.sys.ObjectUtil;
031    
032    /**
033     * Utility class for helping DAOs deal with building queries for the consolidation option
034     */
035    public class ConsolidationUtil {
036        private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory.getLog(ConsolidationUtil.class);
037    
038        /**
039         * wrap the given field name with SQL function "sum"
040         * 
041         * @param fieldName the given field name
042         * @return the wrapped field name with SQL function "sum"
043         */
044        public static final String sum(String fieldName) {
045            return "sum(" + fieldName + ")";
046        }
047    
048        /**
049         * This method builds the atrribute list used by balance searching
050         * 
051         * @param extendedFields extra fields
052         * @return List an attribute list
053         */
054        public static Collection<String> buildAttributeCollection(String... extendedFields) {
055            return buildAttributeCollection(Arrays.asList(extendedFields));
056        }
057    
058        /**
059         * This method builds the atrribute list used by balance searching
060         * 
061         * @param extendedFields extra fields
062         * @return Collection an attribute list
063         */
064        public static Collection<String> buildAttributeCollection(Collection<String> extendedFields) {
065            Collection<String> attributeList = buildGroupByCollection();
066    
067            attributeList.add(sum(KFSPropertyConstants.ACCOUNT_LINE_ANNUAL_BALANCE_AMOUNT));
068            attributeList.add(sum(KFSPropertyConstants.FINANCIAL_BEGINNING_BALANCE_LINE_AMOUNT));
069            attributeList.add(sum(KFSPropertyConstants.CONTRACTS_GRANTS_BEGINNING_BALANCE_AMOUNT));
070    
071            // add the entended elements into the list
072            attributeList.addAll(extendedFields);
073            return attributeList;
074        }
075    
076        /**
077         * Utility class for helping DAOs deal with building queries for the consolidation option
078         * 
079         * @param query Query to make consolidated
080         * @param extraFields fields included in the query
081         * @param ignoredFields to omit from the query
082         */
083        public static void buildConsolidatedQuery(ReportQueryByCriteria query, String... extraFields) {
084            Collection<String> attributeList = buildAttributeCollection(extraFields);
085            Collection<String> groupByList = buildGroupByCollection();
086    
087            attributeList.remove(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
088            groupByList.remove(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
089            attributeList.remove(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE);
090            groupByList.remove(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE);
091            attributeList.remove(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE);
092            groupByList.remove(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE);
093    
094            // set the selection attributes
095            String[] attributes = (String[]) attributeList.toArray(new String[attributeList.size()]);
096            query.setAttributes(attributes);
097            LOG.debug("Built Attributes for Query: " + attributeList.toString());
098    
099            // add the group criteria into the selection statement
100            String[] groupBy = (String[]) groupByList.toArray(new String[attributeList.size()]);
101            query.addGroupBy(groupBy);
102            LOG.debug("Built GroupBy for Query: " + groupByList.toString());
103        }
104    
105        /**
106         * This method builds group by attribute list used by balance searching
107         * 
108         * @return extraFields
109         * @return Collection an group by attribute list
110         */
111        public static Collection<String> buildGroupByCollection(Collection<String> extraFields) {
112            Collection<String> retval = new ArrayList();
113            retval.add(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR);
114            retval.add(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE);
115            retval.add(KFSPropertyConstants.ACCOUNT_NUMBER);
116            retval.add(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
117            retval.add(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE);
118            retval.add(KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
119            retval.add(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE);
120            retval.add(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE);
121            retval.add(KFSPropertyConstants.EMPLID);
122            retval.add(KFSPropertyConstants.POSITION_NUMBER);
123            retval.addAll(extraFields);
124            return retval;
125        }
126    
127        /**
128         * This method builds group by attribute list used by balance searching
129         * 
130         * @return extraFields
131         * @return Collection an group by attribute list
132         */
133        public static Collection<String> buildGroupByCollection(String... extraFields) {
134            return buildGroupByCollection(Arrays.asList(extraFields));
135        }
136    
137        /**
138         * Consolidates a collection of actual balances with a collection of A2 balances. The A2 balances are changed to AC, then
139         * matched by balance key with balances from the actual collection.
140         * 
141         * @param actualBalances - collection of actual balances (consolidatedBalanceTypeCode)
142         * @param effortBalances - collection of effort balances ('A2')
143         * @param consolidatedBalanceTypeCode - balance type to change A2 records to
144         * @return Collection<LedgerBalance> - collection with consolidated balance records
145         */
146        public static Collection<LedgerBalance> consolidateA2Balances(Collection<LedgerBalance> actualBalances, Collection<LedgerBalance> effortBalances, String consolidatedBalanceTypeCode, List<String> consolidationKeyList) {
147            Map<String, LedgerBalance> consolidatedBalanceMap = new HashMap<String, LedgerBalance>();
148            for (LedgerBalance effortBalance : effortBalances) {
149                effortBalance.setBalanceTypeCode(consolidatedBalanceTypeCode);
150                String consolidationKey = ObjectUtil.buildPropertyMap(effortBalance, consolidationKeyList).toString();
151                
152                if(consolidatedBalanceMap.containsKey(consolidationKey)) {
153                    LedgerBalance ledgerBalance = consolidatedBalanceMap.get(consolidationKey);
154                    sumLedgerBalances(ledgerBalance, effortBalance);
155                }
156                else {                            
157                    consolidatedBalanceMap.put(consolidationKey, effortBalance);
158                }
159            }
160            
161            for (LedgerBalance actualBalance : actualBalances) {
162                actualBalance.setBalanceTypeCode(consolidatedBalanceTypeCode);
163                String consolidationKey = ObjectUtil.buildPropertyMap(actualBalance, consolidationKeyList).toString();
164                
165                if(consolidatedBalanceMap.containsKey(consolidationKey)) {
166                    LedgerBalance ledgerBalance = consolidatedBalanceMap.get(consolidationKey);
167                    sumLedgerBalances(ledgerBalance, actualBalance);
168                }
169                else {              
170                    consolidatedBalanceMap.put(consolidationKey, actualBalance);
171                }
172            }
173    
174            return consolidatedBalanceMap.values();
175        }
176    
177        /**
178         * Adds the amounts fields of the second balance record to the first.
179         * 
180         * @param balance1 - LedgerBalance
181         * @param balance2 - LedgerBalance
182         */
183        public static void sumLedgerBalances(LedgerBalance balance1, LedgerBalance balance2) {
184            balance1.setAccountLineAnnualBalanceAmount(balance1.getAccountLineAnnualBalanceAmount().add(balance2.getAccountLineAnnualBalanceAmount()));
185            balance1.setBeginningBalanceLineAmount(balance1.getBeginningBalanceLineAmount().add(balance2.getBeginningBalanceLineAmount()));
186            balance1.setContractsGrantsBeginningBalanceAmount(balance1.getContractsGrantsBeginningBalanceAmount().add(balance2.getContractsGrantsBeginningBalanceAmount()));
187            balance1.setMonth1Amount(balance1.getMonth1Amount().add(balance2.getMonth1Amount()));
188            balance1.setMonth2Amount(balance1.getMonth2Amount().add(balance2.getMonth2Amount()));
189            balance1.setMonth3Amount(balance1.getMonth3Amount().add(balance2.getMonth3Amount()));
190            balance1.setMonth4Amount(balance1.getMonth4Amount().add(balance2.getMonth4Amount()));
191            balance1.setMonth5Amount(balance1.getMonth5Amount().add(balance2.getMonth5Amount()));
192            balance1.setMonth6Amount(balance1.getMonth6Amount().add(balance2.getMonth6Amount()));
193            balance1.setMonth7Amount(balance1.getMonth7Amount().add(balance2.getMonth7Amount()));
194            balance1.setMonth8Amount(balance1.getMonth8Amount().add(balance2.getMonth8Amount()));
195            balance1.setMonth9Amount(balance1.getMonth9Amount().add(balance2.getMonth9Amount()));
196            balance1.setMonth10Amount(balance1.getMonth10Amount().add(balance2.getMonth10Amount()));
197            balance1.setMonth11Amount(balance1.getMonth11Amount().add(balance2.getMonth11Amount()));
198            balance1.setMonth12Amount(balance1.getMonth12Amount().add(balance2.getMonth12Amount()));
199            balance1.setMonth13Amount(balance1.getMonth13Amount().add(balance2.getMonth13Amount()));
200        }
201    
202        /**
203         * wrap the attribute name based on the given flag: isAttributeNameNeeded
204         * 
205         * @param attributeName the given attribute name
206         * @param isAttributeNameNeeded the flag that indicates if the attribute name needs to be wrapped with consolidation
207         * @return the attribute name as it is if isAttributeNameNeeded is true; otherwise, the attribute name wrapped with
208         *         consolidation string
209         */
210        public static String wrapAttributeName(String attributeName, boolean isAttributeNameNeeded) {
211            return isAttributeNameNeeded ? attributeName : ConsolidationUtil.sum(attributeName);
212        }
213    }