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.apache.commons.collections.IteratorUtils.toList;
019
020 import java.util.ArrayList;
021 import java.util.Collection;
022 import java.util.Collections;
023 import java.util.HashMap;
024 import java.util.List;
025 import java.util.Map;
026
027 import org.apache.commons.lang.StringUtils;
028 import org.kuali.kfs.gl.Constant;
029 import org.kuali.kfs.gl.businessobject.TransientBalanceInquiryAttributes;
030 import org.kuali.kfs.integration.ld.LaborLedgerObject;
031 import org.kuali.kfs.module.ld.LaborKeyConstants;
032 import org.kuali.kfs.module.ld.businessobject.AccountStatusCurrentFunds;
033 import org.kuali.kfs.module.ld.businessobject.July1PositionFunding;
034 import org.kuali.kfs.module.ld.businessobject.LaborObject;
035 import org.kuali.kfs.module.ld.businessobject.LedgerBalance;
036 import org.kuali.kfs.module.ld.businessobject.inquiry.AbstractLaborInquirableImpl;
037 import org.kuali.kfs.module.ld.businessobject.inquiry.CurrentFundsInquirableImpl;
038 import org.kuali.kfs.module.ld.businessobject.inquiry.PositionDataDetailsInquirableImpl;
039 import org.kuali.kfs.module.ld.dataaccess.LaborDao;
040 import org.kuali.kfs.module.ld.service.LaborInquiryOptionsService;
041 import org.kuali.kfs.module.ld.service.LaborLedgerBalanceService;
042 import org.kuali.kfs.sys.KFSConstants;
043 import org.kuali.kfs.sys.KFSPropertyConstants;
044 import org.kuali.kfs.sys.ObjectUtil;
045 import org.kuali.rice.kns.bo.BusinessObject;
046 import org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl;
047 import org.kuali.rice.kns.lookup.CollectionIncomplete;
048 import org.kuali.rice.kns.lookup.HtmlData;
049 import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
050 import org.kuali.rice.kns.service.BusinessObjectService;
051 import org.kuali.rice.kns.util.BeanPropertyComparator;
052 import org.kuali.rice.kns.util.GlobalVariables;
053 import org.kuali.rice.kns.util.KualiDecimal;
054 import org.kuali.rice.kns.web.ui.Row;
055
056 /**
057 * Service implementation for the CurrentFundsLookupableHelperServiceImpl class is the front-end for all current funds balance
058 * inquiry processing.
059 */
060 public class CurrentFundsLookupableHelperServiceImpl extends AbstractLookupableHelperServiceImpl {
061 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CurrentFundsLookupableHelperServiceImpl.class);
062 private LaborDao laborDao;
063 private LaborLedgerBalanceService balanceService;
064 private LaborInquiryOptionsService laborInquiryOptionsService;
065 private BusinessObjectService businessObjectService;
066
067 /**
068 * @see org.kuali.rice.kns.lookup.Lookupable#getInquiryUrl(org.kuali.rice.kns.bo.BusinessObject, java.lang.String)
069 */
070 @Override
071 public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
072 if (KFSPropertyConstants.POSITION_NUMBER.equals(propertyName)) {
073 LedgerBalance balance = (LedgerBalance) bo;
074 AbstractLaborInquirableImpl positionDataDetailsInquirable = new PositionDataDetailsInquirableImpl();
075
076 Map<String, String> fieldValues = new HashMap<String, String>();
077 fieldValues.put(propertyName, balance.getPositionNumber());
078
079 BusinessObject positionData = positionDataDetailsInquirable.getBusinessObject(fieldValues);
080
081 return positionData == null ? new AnchorHtmlData(KFSConstants.EMPTY_STRING, KFSConstants.EMPTY_STRING) : positionDataDetailsInquirable.getInquiryUrl(positionData, propertyName);
082 }
083 return (new CurrentFundsInquirableImpl()).getInquiryUrl(bo, propertyName);
084 }
085
086 /**
087 * Gets a list with the fields that will be displayed on page
088 *
089 * @param fieldValues list of fields that are used as a key to filter out data
090 * @see org.kuali.rice.kns.lookup.Lookupable#getSearchResults(java.util.Map)
091 */
092 @Override
093 public List getSearchResults(Map fieldValues) {
094 LOG.info("getSearchResults() - Entry");
095
096 boolean unbounded = false;
097 Long actualCountIfTruncated = new Long(0);
098
099 setBackLocation((String) fieldValues.get(KFSConstants.BACK_LOCATION));
100 setDocFormKey((String) fieldValues.get(KFSConstants.DOC_FORM_KEY));
101
102 // get the pending entry option. This method must be prior to the get search results
103 String pendingEntryOption = laborInquiryOptionsService.getSelectedPendingEntryOption(fieldValues);
104
105 // get the consolidation option
106 boolean isConsolidated = laborInquiryOptionsService.isConsolidationSelected(fieldValues, (Collection<Row>) getRows());
107
108 String searchObjectCodeVal = (String) fieldValues.get(KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
109 // Check for a valid labor object code for this inquiry
110 if (StringUtils.isNotBlank(searchObjectCodeVal)) {
111 Map objectCodeFieldValues = new HashMap();
112 objectCodeFieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, fieldValues.get(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR));
113 objectCodeFieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, fieldValues.get(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE));
114 objectCodeFieldValues.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, searchObjectCodeVal);
115
116 LaborLedgerObject foundObjectCode = (LaborLedgerObject) businessObjectService.findByPrimaryKey(LaborObject.class, objectCodeFieldValues);
117
118 if (foundObjectCode == null) {
119 GlobalVariables.getMessageMap().putError(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, LaborKeyConstants.ERROR_INVALID_LABOR_OBJECT_CODE, "2");
120 return new CollectionIncomplete(new ArrayList(), actualCountIfTruncated);
121 }
122 }
123
124 // Parse the map and call the DAO to process the inquiry
125 Collection<AccountStatusCurrentFunds> searchResultsCollection = buildCurrentFundsCollection(toList(laborDao.getCurrentFunds(fieldValues, isConsolidated)), isConsolidated, pendingEntryOption);
126
127 // update search results according to the selected pending entry option
128 laborInquiryOptionsService.updateCurrentFundsByPendingLedgerEntry(searchResultsCollection, fieldValues, pendingEntryOption, isConsolidated);
129
130 // gets the July1st budget amount column.
131 Collection<July1PositionFunding> july1PositionFundings = laborDao.getJuly1(fieldValues);
132 this.updateJuly1BalanceAmount(searchResultsCollection, july1PositionFundings, isConsolidated);
133
134 // sort list if default sort column given
135 List searchResults = (List) searchResultsCollection;
136 List defaultSortColumns = getDefaultSortColumns();
137 if (defaultSortColumns.size() > 0) {
138 Collections.sort(searchResults, new BeanPropertyComparator(defaultSortColumns, true));
139 }
140 return new CollectionIncomplete(searchResults, actualCountIfTruncated);
141 }
142
143 /**
144 * Adds the july1 budget amount to each account found in the
145 *
146 * @param searchResultsCollection collection with the list of current funds where the amount is added
147 * @param july1PositionFundings collection of current funds with july1st budget amounts
148 * @param isConsolidated
149 */
150 private void updateJuly1BalanceAmount(Collection<AccountStatusCurrentFunds> searchResultsCollection, Collection<July1PositionFunding> july1PositionFundings, boolean isConsolidated) {
151 for (July1PositionFunding july1PositionFunding : july1PositionFundings) {
152 for (AccountStatusCurrentFunds accountStatus : searchResultsCollection) {
153 boolean found = ObjectUtil.equals(accountStatus, july1PositionFunding, accountStatus.getKeyFieldList(isConsolidated));
154 if (found) {
155 accountStatus.setJuly1BudgetAmount(accountStatus.getJuly1BudgetAmount().add(july1PositionFunding.getJuly1BudgetAmount()));
156 }
157 }
158 }
159 }
160
161 /**
162 * Returns a list with the current funds.
163 *
164 * @param iterator the iterator of search results of account status
165 * @param isConsolidated determine if the consolidated result is desired
166 * @param pendingEntryOption the given pending entry option that can be no, approved or all
167 * @return the current funds collection
168 */
169 private Collection<AccountStatusCurrentFunds> buildCurrentFundsCollection(Collection collection, boolean isConsolidated, String pendingEntryOption) {
170 Collection<AccountStatusCurrentFunds> retval = null;
171
172 if (isConsolidated) {
173 retval = buildCosolidatedCurrentFundsCollection(collection, pendingEntryOption);
174 }
175 else {
176 retval = buildDetailedCurrentFundsCollection(collection, pendingEntryOption);
177 }
178 return retval;
179 }
180
181 /**
182 * Builds the current funds collection with consolidation option from an iterator
183 *
184 * @param iterator
185 * @param pendingEntryOption the selected pending entry option
186 * @return the consolidated current funds collection
187 */
188 private Collection<AccountStatusCurrentFunds> buildCosolidatedCurrentFundsCollection(Collection collection, String pendingEntryOption) {
189 Collection<AccountStatusCurrentFunds> retval = new ArrayList<AccountStatusCurrentFunds>();
190 for (Object collectionEntry : collection) {
191 if (collectionEntry.getClass().isArray()) {
192 int i = 0;
193 Object[] array = (Object[]) collectionEntry;
194 AccountStatusCurrentFunds cf = new AccountStatusCurrentFunds();
195 LOG.debug("element length " + array.length);
196 for (Object element : array) {
197 LOG.debug("I found this element " + element);
198 }
199
200 if (AccountStatusCurrentFunds.class.isAssignableFrom(getBusinessObjectClass())) {
201 try {
202 cf = (AccountStatusCurrentFunds) getBusinessObjectClass().newInstance();
203 }
204 catch (Exception e) {
205 LOG.warn("Using " + AccountStatusCurrentFunds.class + " for results because I couldn't instantiate the " + getBusinessObjectClass());
206 }
207 }
208 else {
209 LOG.warn("Using " + AccountStatusCurrentFunds.class + " for results because I couldn't instantiate the " + getBusinessObjectClass());
210 }
211
212 cf.setUniversityFiscalYear(new Integer(array[i++].toString()));
213 cf.setChartOfAccountsCode(array[i++].toString());
214 cf.setAccountNumber(array[i++].toString());
215
216 String subAccountNumber = Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER;
217 cf.setSubAccountNumber(subAccountNumber);
218
219 cf.setBalanceTypeCode(array[i++].toString());
220 cf.setFinancialObjectCode(array[i++].toString());
221
222 cf.setEmplid(array[i++].toString());
223 cf.setPositionNumber(array[i++].toString());
224
225 cf.setFinancialSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
226 cf.setObjectTypeCode(Constant.CONSOLIDATED_OBJECT_TYPE_CODE);
227
228 cf.setAccountLineAnnualBalanceAmount(new KualiDecimal(array[i++].toString()));
229 cf.setBeginningBalanceLineAmount(new KualiDecimal(array[i++].toString()));
230 cf.setContractsGrantsBeginningBalanceAmount(new KualiDecimal(array[i++].toString()));
231
232 cf.setMonth1Amount(new KualiDecimal(array[i++].toString()));
233
234 cf.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
235 cf.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
236 cf.setOutstandingEncum(getOutstandingEncum(cf));
237
238 cf.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
239 cf.getDummyBusinessObject().setConsolidationOption(Constant.CONSOLIDATION);
240
241 retval.add(cf);
242 }
243 }
244 return retval;
245 }
246
247 /**
248 * Builds the current funds collection with detail option from an iterator
249 *
250 * @param iterator the current funds iterator
251 * @param pendingEntryOption the selected pending entry option
252 * @return the detailed balance collection
253 */
254 private Collection<AccountStatusCurrentFunds> buildDetailedCurrentFundsCollection(Collection collection, String pendingEntryOption) {
255 Collection<AccountStatusCurrentFunds> retval = new ArrayList<AccountStatusCurrentFunds>();
256
257 for (LedgerBalance balance : ((Collection<LedgerBalance>) collection)) {
258 AccountStatusCurrentFunds cf = new AccountStatusCurrentFunds();
259 ObjectUtil.buildObject(cf, balance);
260
261 cf.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
262 cf.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
263 cf.setOutstandingEncum(getOutstandingEncum(cf));
264
265 cf.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
266 cf.getDummyBusinessObject().setConsolidationOption(Constant.DETAIL);
267
268 retval.add(cf);
269 }
270 return retval;
271 }
272
273 /**
274 * Gets the outstanding encumbrance amount
275 *
276 * @param AccountStatusCurrentFunds
277 * @param Map fieldValues
278 */
279 private KualiDecimal getOutstandingEncum(AccountStatusCurrentFunds bo) {
280 Map<String, String> fieldValues = new HashMap();
281 fieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, bo.getUniversityFiscalYear().toString());
282 fieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, bo.getChartOfAccountsCode());
283 fieldValues.put(KFSPropertyConstants.ACCOUNT_NUMBER, bo.getAccountNumber());
284
285 if (!bo.getSubAccountNumber().equals(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER)) {
286 fieldValues.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, bo.getSubAccountNumber());
287 }
288
289 fieldValues.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, bo.getFinancialObjectCode());
290
291 if (!bo.getFinancialSubObjectCode().equals(Constant.CONSOLIDATED_SUB_OBJECT_CODE)) {
292 fieldValues.put(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE, bo.getFinancialSubObjectCode());
293 }
294 fieldValues.put(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE, KFSConstants.BALANCE_TYPE_INTERNAL_ENCUMBRANCE); // Encumberance
295 // Balance
296 // Type
297 fieldValues.put(KFSPropertyConstants.EMPLID, bo.getEmplid());
298 LOG.debug("using " + fieldValues.values());
299 LOG.debug("using " + fieldValues.keySet());
300 return (KualiDecimal) laborDao.getEncumbranceTotal(fieldValues);
301 }
302
303 /**
304 * Sets the balanceService attribute value.
305 *
306 * @param balanceService The balanceService to set.
307 */
308 public void setBalanceService(LaborLedgerBalanceService balanceService) {
309 this.balanceService = balanceService;
310 }
311
312 /**
313 * Sets the laborDao attribute value.
314 *
315 * @param laborDao The laborDao to set.
316 */
317 public void setLaborDao(LaborDao laborDao) {
318 this.laborDao = laborDao;
319 }
320
321 /**
322 * Sets the laborInquiryOptionsService attribute value.
323 *
324 * @param laborInquiryOptionsService The laborInquiryOptionsService to set.
325 */
326 public void setLaborInquiryOptionsService(LaborInquiryOptionsService laborInquiryOptionsService) {
327 this.laborInquiryOptionsService = laborInquiryOptionsService;
328 }
329
330 /**
331 * Sets the businessObjectService attribute value.
332 *
333 * @param businessObjectService The businessObjectService to set.
334 */
335 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
336 this.businessObjectService = businessObjectService;
337 }
338
339 }