/*
* 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.Iterator;
import java.util.List;
import java.util.Map;
import org.kuali.kfs.gl.Constant;
import org.kuali.kfs.gl.GeneralLedgerConstants;
import org.kuali.kfs.gl.OJBUtility;
import org.kuali.kfs.gl.batch.service.BalanceCalculator;
import org.kuali.kfs.gl.businessobject.Balance;
import org.kuali.kfs.gl.businessobject.TransientBalanceInquiryAttributes;
import org.kuali.kfs.gl.businessobject.inquiry.BalanceInquirableImpl;
import org.kuali.kfs.gl.service.BalanceService;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.kns.lookup.HtmlData;
import org.kuali.rice.kns.web.ui.Field;
import org.kuali.rice.kns.web.ui.Row;
import org.kuali.rice.krad.bo.BusinessObject;
/**
* An extension of KualiLookupableImpl to support balance lookups
*/
public class BalanceLookupableHelperServiceImpl extends AbstractGeneralLedgerLookupableHelperServiceImpl {
private BalanceCalculator postBalance;
private BalanceService balanceService;
private Map fieldValues;
/**
* Returns the url for any drill down links within the lookup
* @param bo the business object with a property being drilled down on
* @param propertyName the name of the property being drilled down on
* @return a String with the URL of the property
* @see org.kuali.rice.kns.lookup.Lookupable#getInquiryUrl(org.kuali.rice.krad.bo.BusinessObject, java.lang.String)
*/
@Override
public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
return (new BalanceInquirableImpl()).getInquiryUrl(bo, propertyName);
}
/**
* Generates the list of search results for this inquiry
* @param fieldValues the field values of the query to carry out
* @return List the search results returned by the lookup
* @see org.kuali.rice.kns.lookup.Lookupable#getSearchResults(java.util.Map)
*
* KRAD Conversion: Lookupable modifies the search results based on the fields consolidated.
* But all field definitions are in data dictionary.
*/
@Override
public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues) {
setBackLocation((String) fieldValues.get(KFSConstants.BACK_LOCATION));
setDocFormKey((String) fieldValues.get(KFSConstants.DOC_FORM_KEY));
// get the pending entry option. This method must be prior to the get search results
String pendingEntryOption = this.getSelectedPendingEntryOption(fieldValues);
// KFSMI-410: need to get this before getting isConsolidated because this value will be removed.
String consolidationOption = (String) fieldValues.get(GeneralLedgerConstants.DummyBusinessObject.CONSOLIDATION_OPTION);
// test if the consolidation option is selected or not
boolean isConsolidated = isConsolidationSelected(fieldValues);
// KFSMI-410: added one more node for consolidationOption
if (consolidationOption.equals(Constant.EXCLUDE_SUBACCOUNTS)){
fieldValues.put(Constant.SUB_ACCOUNT_OPTION, KFSConstants.getDashSubAccountNumber());
isConsolidated = false;
}
// get Amount View Option and determine if the results has to be accumulated
String amountViewOption = getSelectedAmountViewOption(fieldValues);
boolean isAccumulated = amountViewOption.equals(Constant.ACCUMULATE);
// get the search result collection
Iterator balanceIterator = balanceService.findBalance(fieldValues, isConsolidated);
Collection searchResultsCollection = this.buildBalanceCollection(balanceIterator, isConsolidated, pendingEntryOption);
// update search results according to the selected pending entry option
updateByPendingLedgerEntry(searchResultsCollection, fieldValues, pendingEntryOption, isConsolidated, false);
// perform the accumulation of the amounts
this.accumulate(searchResultsCollection, isAccumulated);
// get the actual size of all qualified search results
Integer recordCount = balanceService.getBalanceRecordCount(fieldValues, isConsolidated);
Long actualSize = OJBUtility.getResultActualSize(searchResultsCollection, recordCount, fieldValues, new Balance());
return this.buildSearchResultList(searchResultsCollection, actualSize);
}
/**
* This method builds the balance collection based on the input iterator
*
* @param iterator the iterator of search results of balance
* @param isConsolidated determine if the consolidated result is desired
* @param pendingEntryOption the given pending entry option that can be no, approved or all
* @return the balance collection
*/
private Collection buildBalanceCollection(Iterator iterator, boolean isConsolidated, String pendingEntryOption) {
Collection balanceCollection = null;
if (isConsolidated) {
balanceCollection = buildConsolidatedBalanceCollection(iterator, pendingEntryOption);
}
else {
balanceCollection = buildDetailedBalanceCollection(iterator, pendingEntryOption);
}
return balanceCollection;
}
/**
* This method builds the balance collection with consolidation option from an iterator
*
* @param iterator th iterator of balance results
* @param pendingEntryOption the selected pending entry option
* @return the consolidated balance collection
*/
private Collection buildConsolidatedBalanceCollection(Iterator iterator, String pendingEntryOption) {
Collection balanceCollection = new ArrayList();
while (iterator.hasNext()) {
Object collectionEntry = iterator.next();
if (collectionEntry.getClass().isArray()) {
int i = 0;
Object[] array = (Object[]) collectionEntry;
Balance balance = new Balance();
balance.setUniversityFiscalYear(new Integer(array[i++].toString()));
balance.setChartOfAccountsCode(array[i++].toString());
balance.setAccountNumber(array[i++].toString());
String subAccountNumber = Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER;
balance.setSubAccountNumber(subAccountNumber);
balance.setBalanceTypeCode(array[i++].toString());
balance.setObjectCode(array[i++].toString());
balance.setSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
balance.setObjectTypeCode(Constant.CONSOLIDATED_OBJECT_TYPE_CODE);
balance.setAccountLineAnnualBalanceAmount(new KualiDecimal(array[i++].toString()));
balance.setBeginningBalanceLineAmount(new KualiDecimal(array[i++].toString()));
balance.setContractsGrantsBeginningBalanceAmount(new KualiDecimal(array[i++].toString()));
balance.setMonth1Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth2Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth3Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth4Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth5Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth6Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth7Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth8Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth9Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth10Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth11Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth12Amount(new KualiDecimal(array[i++].toString()));
balance.setMonth13Amount(new KualiDecimal(array[i].toString()));
balance.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
balance.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
balanceCollection.add(balance);
}
}
return balanceCollection;
}
/**
* This method builds the balance collection with detail option from an iterator
*
* @param iterator the balance iterator
* @param pendingEntryOption the selected pending entry option
* @return the detailed balance collection
*/
private Collection buildDetailedBalanceCollection(Iterator iterator, String pendingEntryOption) {
Collection balanceCollection = new ArrayList();
while (iterator.hasNext()) {
Balance balance = (Balance) (iterator.next());
balance.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
balance.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
balanceCollection.add(balance);
}
return balanceCollection;
}
/**
* This method updates the balance collection with accumulated amounts if required (isAccumulated is true)
*
* @param balanceCollection the balance collection to be updated
* @param isAccumulated determine if the accumulated result is desired
*/
protected void accumulate(Collection balanceCollection, boolean isAccumulated) {
if (isAccumulated) {
for (Iterator iterator = balanceCollection.iterator(); iterator.hasNext();) {
Balance balance = (Balance) (iterator.next());
accumulateByBalance(balance, isAccumulated);
}
}
}
/**
* This method computes the accumulate amount of the given balance and updates its fields
*
* @param balance the given balance object
* @param isAccumulated determine if the accumulated result is desired
*/
private void accumulateByBalance(Balance balance, boolean isAccumulated) {
KualiDecimal annualAmount = balance.getAccountLineAnnualBalanceAmount();
KualiDecimal beginningAmount = balance.getBeginningBalanceLineAmount();
KualiDecimal CGBeginningAmount = balance.getContractsGrantsBeginningBalanceAmount();
KualiDecimal month0Amount = beginningAmount.add(CGBeginningAmount);
KualiDecimal month1Amount = balance.getMonth1Amount();
month1Amount = accumulateAmount(month1Amount, month0Amount, isAccumulated);
balance.setMonth1Amount(month1Amount);
KualiDecimal month2Amount = balance.getMonth2Amount();
month2Amount = accumulateAmount(month2Amount, month1Amount, isAccumulated);
balance.setMonth2Amount(month2Amount);
KualiDecimal month3Amount = balance.getMonth3Amount();
month3Amount = accumulateAmount(month3Amount, month2Amount, isAccumulated);
balance.setMonth3Amount(month3Amount);
KualiDecimal month4Amount = balance.getMonth4Amount();
month4Amount = accumulateAmount(month4Amount, month3Amount, isAccumulated);
balance.setMonth4Amount(month4Amount);
KualiDecimal month5Amount = balance.getMonth5Amount();
month5Amount = accumulateAmount(month5Amount, month4Amount, isAccumulated);
balance.setMonth5Amount(month5Amount);
KualiDecimal month6Amount = balance.getMonth6Amount();
month6Amount = accumulateAmount(month6Amount, month5Amount, isAccumulated);
balance.setMonth6Amount(month6Amount);
KualiDecimal month7Amount = balance.getMonth7Amount();
month7Amount = accumulateAmount(month7Amount, month6Amount, isAccumulated);
balance.setMonth7Amount(month7Amount);
KualiDecimal month8Amount = balance.getMonth8Amount();
month8Amount = accumulateAmount(month8Amount, month7Amount, isAccumulated);
balance.setMonth8Amount(month8Amount);
KualiDecimal month9Amount = balance.getMonth9Amount();
month9Amount = accumulateAmount(month9Amount, month8Amount, isAccumulated);
balance.setMonth9Amount(month9Amount);
KualiDecimal month10Amount = balance.getMonth10Amount();
month10Amount = accumulateAmount(month10Amount, month9Amount, isAccumulated);
balance.setMonth10Amount(month10Amount);
KualiDecimal month11Amount = balance.getMonth11Amount();
month11Amount = accumulateAmount(month11Amount, month10Amount, isAccumulated);
balance.setMonth11Amount(month11Amount);
KualiDecimal month12Amount = balance.getMonth12Amount();
month12Amount = accumulateAmount(month12Amount, month11Amount, isAccumulated);
balance.setMonth12Amount(month12Amount);
KualiDecimal month13Amount = balance.getMonth13Amount();
month13Amount = accumulateAmount(month13Amount, month12Amount, isAccumulated);
balance.setMonth13Amount(month13Amount);
}
/**
* This method converts the amount from String and adds it with the input addend
*
* @param stringAugend a String-type augend
* @param addend an addend
* @param isAccumulated determine if the accumulated result is desired
* @return the accumulated amount if accumulate option is selected; otherwise, the input amount itself
*/
private KualiDecimal accumulateAmount(Object stringAugend, KualiDecimal addend, boolean isAccumulated) {
KualiDecimal augend = new KualiDecimal(stringAugend.toString());
if (isAccumulated) {
augend = augend.add(addend);
}
return augend;
}
/**
* Updates pending entries before their results are included in the lookup results
*
* @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 isConsolidated flag whether the results are consolidated or not
* @param isCostShareExcluded flag whether the user selects to see the results with cost share subaccount
* @see org.kuali.module.gl.web.lookupable.AbstractGLLookupableImpl#updateEntryCollection(java.util.Collection, java.util.Map,
* boolean, boolean, boolean)
*/
public void updateEntryCollection(Collection entryCollection, Map fieldValues, boolean isApproved, boolean isConsolidated, boolean isCostShareInclusive) {
// convert the field names of balance object into corresponding ones of pending entry object
Map pendingEntryFieldValues = BusinessObjectFieldConverter.convertToTransactionFieldValues(fieldValues);
// go through the pending entries to update the balance collection
Iterator pendingEntryIterator = getGeneralLedgerPendingEntryService().findPendingLedgerEntriesForBalance(pendingEntryFieldValues, isApproved);
while (pendingEntryIterator.hasNext()) {
GeneralLedgerPendingEntry pendingEntry = (GeneralLedgerPendingEntry) pendingEntryIterator.next();
// if consolidated, change the following fields into the default values for consolidation
if (isConsolidated) {
pendingEntry.setSubAccountNumber(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER);
pendingEntry.setFinancialSubObjectCode(Constant.CONSOLIDATED_SUB_OBJECT_CODE);
pendingEntry.setFinancialObjectTypeCode(Constant.CONSOLIDATED_OBJECT_TYPE_CODE);
}
Balance balance = postBalance.findBalance(entryCollection, pendingEntry);
String pendingEntryOption = isApproved ? Constant.APPROVED_PENDING_ENTRY : Constant.ALL_PENDING_ENTRY;
balance.setDummyBusinessObject(new TransientBalanceInquiryAttributes());
balance.getDummyBusinessObject().setPendingEntryOption(pendingEntryOption);
postBalance.updateBalance(pendingEntry, balance);
}
}
/**
* Sets the postBalance attribute value.
*
* @param postBalance The postBalance to set.
*/
public void setPostBalance(BalanceCalculator postBalance) {
this.postBalance = postBalance;
}
/**
* Sets the balanceService attribute value.
*
* @param balanceService The balanceService to set.
*/
public void setBalanceService(BalanceService balanceService) {
this.balanceService = balanceService;
}
/**
* @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#getRows()
*/
@Override
public List<Row> getRows() {
List<Row> superResults = super.getRows();
if (superResults != null) {
for (Row row : superResults) {
for (Field field : row.getFields()) {
if (KFSPropertyConstants.ACCOUNT_NUMBER.equals(field.getPropertyName())) {
// because of limitations in BO Metadata service, the account quickfinder was going to prior year account instead of account, therefore
// need to force it to go to Account (or whatever's mapped to the "account" reference in OJB
Class clazz = getPersistenceStructureService().getBusinessObjectAttributeClass(businessObjectClass, KFSPropertyConstants.ACCOUNT);
field.setQuickFinderClassNameImpl(clazz.getName());
return superResults;
}
}
}
}
return superResults;
}
}