/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.gl.businessobject.lookup; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.gl.Constant; import org.kuali.kfs.gl.service.impl.StringHelper; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.document.service.DebitDeterminerService; import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService; import org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl; import org.kuali.rice.kns.lookup.HtmlData; import org.kuali.rice.kns.web.struts.form.LookupForm; import org.kuali.rice.kns.web.ui.Column; import org.kuali.rice.kns.web.ui.Field; import org.kuali.rice.kns.web.ui.ResultRow; import org.kuali.rice.kns.web.ui.Row; import org.kuali.rice.krad.bo.BusinessObject; import org.kuali.rice.krad.lookup.CollectionIncomplete; import org.kuali.rice.krad.util.BeanPropertyComparator; import org.kuali.rice.krad.util.ObjectUtils; /** * The abstract parent class for GL Lookupables, providing base implementations of methods * to make adding new lookupable reports easier */ public abstract class AbstractGeneralLedgerLookupableHelperServiceImpl extends AbstractLookupableHelperServiceImpl { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AbstractGeneralLedgerLookupableHelperServiceImpl.class); protected GeneralLedgerPendingEntryService generalLedgerPendingEntryService; protected DebitDeterminerService debitDeterminerService; /** * This method overides that in parent class so that the maintainance actions are surpressed * * @returns links to edit and copy maintenance action for the current maintenance record. For GL balance inquire, there are no * maintenance links. */ @Override public List<HtmlData> getCustomActionUrls(BusinessObject bo, List pkNames) { return super.getEmptyActionUrls(); } /** * This method tests if the user selects to see the general ledger pending entries * * @param fieldValues the map containing the search fields and values * @return the value of pending entry option */ protected String getSelectedPendingEntryOption(Map fieldValues) { // truncate the non-property filed String pendingEntryOption = (String) fieldValues.get(Constant.PENDING_ENTRY_OPTION); fieldValues.remove(Constant.PENDING_ENTRY_OPTION); return pendingEntryOption; } /** * This method tests if the user selects to see the Debit/Credit entries * * @param fieldValues the map containing the search fields and values * @return the value of pending entry option */ protected String getDebitCreditOption(Map fieldValues) { // truncate the non-property filed String debitCreditOption = (String) fieldValues.get(Constant.DEBIT_CREDIT_OPTION); fieldValues.remove(Constant.DEBIT_CREDIT_OPTION); return debitCreditOption; } /** * This method tests if the user selects to see the reports by monthly or accumulated * * @param fieldValues the map containing the search fields and values * @return the value of amount view option */ protected String getSelectedAmountViewOption(Map fieldValues) { String amountViewOption = Constant.EMPTY_STRING; if (fieldValues.containsKey(Constant.AMOUNT_VIEW_OPTION)) { amountViewOption = (String) fieldValues.get(Constant.AMOUNT_VIEW_OPTION); // truncate the non-property filed fieldValues.remove(Constant.AMOUNT_VIEW_OPTION); } return amountViewOption; } /** * This method tests if the user selects to see the details or consolidated results * * @param fieldValues the map containing the search fields and values * @return true if consolidation is selected and subaccount is not specified * * KRAD Conversion: Lookupable performs checking for a particular attribute and return true or false. * This method is called from AccountBalanceLookupableHelperServiceImpl.java, BalanceLookupableHelperServiceImpl.java, * CashBalanceLookupableHelperServiceImpl.java in gl module. */ protected boolean isConsolidationSelected(Map fieldValues) { // truncate the non-property filed String consolidationOption = (String) fieldValues.get(Constant.CONSOLIDATION_OPTION); fieldValues.remove(Constant.CONSOLIDATION_OPTION); // detail option would be used if (Constant.DETAIL.equals(consolidationOption)) { return false; } // if the subAccountNumber is specified, detail option could be used String subAccountNumber = (String) fieldValues.get(KFSPropertyConstants.SUB_ACCOUNT_NUMBER); if (!StringUtils.isBlank(subAccountNumber)) { this.changeFieldValue(Constant.CONSOLIDATION_OPTION, Constant.DETAIL); return false; } // if the subObjectCode is specified, detail option could be used String subObjectCode = (String) fieldValues.get(KFSPropertyConstants.SUB_OBJECT_CODE); if (!StringUtils.isBlank(subObjectCode)) { this.changeFieldValue(Constant.CONSOLIDATION_OPTION, Constant.DETAIL); return false; } // if the objectTypeCode is specified, detail option could be used String objectTypeCode = (String) fieldValues.get(KFSPropertyConstants.OBJECT_TYPE_CODE); if (!StringUtils.isBlank(objectTypeCode)) { this.changeFieldValue(Constant.CONSOLIDATION_OPTION, Constant.DETAIL); return false; } return true; } /** * This method tests if the user selects to see the results with cost share subaccount * * @param fieldValues the map containing the search fields and values * @return true if inclusive option is selected */ protected boolean isCostShareInclusive(Map fieldValues) { // TODO: is this method being called? // truncate the non-property filed String costShareOption = (String) fieldValues.get(Constant.COST_SHARE_OPTION); fieldValues.remove(Constant.COST_SHARE_OPTION); if (costShareOption.equals(Constant.COST_SHARE_INCLUDE)) { return true; } return false; } /** * build the serach result list from the given collection and the number of all qualified search results * * @param searchResultsCollection the given search results, which may be a subset of the qualified search results * @param actualSize the number of all qualified search results * @return the serach result list with the given results and actual size */ protected List buildSearchResultList(Collection searchResultsCollection, Long actualSize) { CollectionIncomplete results = new CollectionIncomplete(searchResultsCollection, actualSize); // sort list if default sort column given List searchResults = results; List defaultSortColumns = getDefaultSortColumns(); if (defaultSortColumns.size() > 0) { Collections.sort(results, new BeanPropertyComparator(defaultSortColumns, true)); } return searchResults; } @Override public Collection performLookup(LookupForm lookupForm, Collection resultTable, boolean bounded) { Map fieldsForLookup = new HashMap(lookupForm.getFieldsForLookup()); String debitCreditOption = getDebitCreditOption(fieldsForLookup); Collection displayList = super.performLookup(lookupForm, resultTable, bounded); updateByDebitCreditOption(resultTable, debitCreditOption); return displayList; } protected void updateByDebitCreditOption(Collection resultTable , String debitCreditOption) { if (Constant.DEBIT_CREDIT_EXCLUDE.equals(debitCreditOption)){ for(Object table : resultTable) { ResultRow row = (ResultRow)table; List<Column> columns = row.getColumns(); ArrayList<Column> newColumnList = new ArrayList<Column>(); String debitCreditCode = null; String objectType = null; Column amountCol = null; boolean setAmount = false ; for(Column col: columns) { String propertyName = col.getPropertyName(); if (propertyName.equals(KFSPropertyConstants.TRANSACTION_DEBIT_CREDIT_CODE)) { debitCreditCode = col.getPropertyValue(); } else if (!propertyName.equals(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT)){ newColumnList.add(col); } if(propertyName.equals(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE)) { objectType = col.getPropertyValue(); } if (propertyName.equals(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT)) { amountCol = col; } // determine the amount sign if (!newColumnList.contains(amountCol)) { if ((!StringHelper.isNullOrEmpty(objectType)) && (!StringHelper.isNullOrEmpty(debitCreditCode)) && ObjectUtils.isNotNull(amountCol)) { String amount = debitDeterminerService.getConvertedAmount(objectType, debitCreditCode, amountCol.getPropertyValue()); amountCol.setPropertyValue(amount); newColumnList.add(amountCol); } } } row.setColumns(newColumnList); } } } /** * This method is used to update amounts of the given entries with the corresponding pending amounts. It is a factory that * executes the update methods of individual derived classes. * * @param entryCollection a collection of balance entries * @param fieldValues the map containing the search fields and values * @param pendingEntryOption flag whether the approved entries or all entries will be processed * @param isCostShareInclusive flag whether the user selects to see the results with cost share subaccount * @param isConsolidated flag whether the results are consolidated or not */ protected void updateByPendingLedgerEntry(Collection entryCollection, Map fieldValues, String pendingEntryOption, boolean isConsolidated, boolean isCostShareInclusive) { // determine if search results need to be updated by pending ledger entries if (Constant.ALL_PENDING_ENTRY.equals(pendingEntryOption)) { updateEntryCollection(entryCollection, fieldValues, false, isConsolidated, isCostShareInclusive); } else if (Constant.APPROVED_PENDING_ENTRY.equals(pendingEntryOption)) { updateEntryCollection(entryCollection, fieldValues, true, isConsolidated, isCostShareInclusive); } } /** * This method is an abstract method and implemented to update the given entry collection by the children classes. It is called * by updateByPendingLedgerEntry method. * * @param entryCollection a collection of balance entries * @param fieldValues the map containing the search fields and values * @param isApproved flag whether the approved entries or all entries will be processed * @param isCostShareInclusive flag whether the user selects to see the results with cost share subaccount * @param isConsolidated flag whether the results are consolidated or not */ protected abstract void updateEntryCollection(Collection entryCollection, Map fieldValues, boolean isApproved, boolean isConsolidated, boolean isCostShareInclusive); // change the value of the field with the given field name into the given field value private void changeFieldValue(String fieldName, String fieldValue) { for (Iterator rowIterator = getRows().iterator(); rowIterator.hasNext();) { Row row = (Row) rowIterator.next(); for (Iterator fieldIterator = row.getFields().iterator(); fieldIterator.hasNext();) { Field field = (Field) fieldIterator.next(); if (field.getPropertyName().equals(fieldName)) { field.setPropertyValue(fieldValue); } } } } protected GeneralLedgerPendingEntryService getGeneralLedgerPendingEntryService() { return generalLedgerPendingEntryService; } public void setGeneralLedgerPendingEntryService(GeneralLedgerPendingEntryService generalLedgerPendingEntryService) { this.generalLedgerPendingEntryService = generalLedgerPendingEntryService; } protected DebitDeterminerService getDebitDeterminerService() { return debitDeterminerService; } public void setDebitDeterminerService(DebitDeterminerService debitDeterminerService) { this.debitDeterminerService = debitDeterminerService; } }