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