/*
* 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.module.cab.service.impl;
import static org.kuali.rice.core.api.criteria.PredicateFactory.and;
import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.kuali.kfs.coa.businessobject.ObjectCode;
import org.kuali.kfs.fp.businessobject.CapitalAccountingLines;
import org.kuali.kfs.fp.businessobject.CapitalAssetAccountsGroupDetails;
import org.kuali.kfs.fp.businessobject.CapitalAssetInformation;
import org.kuali.kfs.fp.businessobject.CapitalAssetInformationDetail;
import org.kuali.kfs.fp.document.AdvanceDepositDocument;
import org.kuali.kfs.fp.document.CapitalAccountingLinesDocumentBase;
import org.kuali.kfs.fp.document.CapitalAssetEditable;
import org.kuali.kfs.fp.document.CashReceiptDocument;
import org.kuali.kfs.fp.document.CreditCardReceiptDocument;
import org.kuali.kfs.fp.document.DistributionOfIncomeAndExpenseDocument;
import org.kuali.kfs.fp.document.GeneralErrorCorrectionDocument;
import org.kuali.kfs.fp.document.InternalBillingDocument;
import org.kuali.kfs.fp.document.IntraAccountAdjustmentDocument;
import org.kuali.kfs.fp.document.ProcurementCardDocument;
import org.kuali.kfs.fp.document.ServiceBillingDocument;
import org.kuali.kfs.fp.document.YearEndDistributionOfIncomeAndExpenseDocument;
import org.kuali.kfs.fp.document.YearEndGeneralErrorCorrectionDocument;
import org.kuali.kfs.integration.cab.CapitalAssetBuilderAssetTransactionType;
import org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService;
import org.kuali.kfs.integration.cam.CapitalAssetManagementModuleService;
import org.kuali.kfs.integration.purap.CapitalAssetLocation;
import org.kuali.kfs.integration.purap.CapitalAssetSystem;
import org.kuali.kfs.integration.purap.ExternalPurApItem;
import org.kuali.kfs.integration.purap.ItemCapitalAsset;
import org.kuali.kfs.integration.purap.PurchasingAccountsPayableModuleService;
import org.kuali.kfs.module.cab.CabConstants;
import org.kuali.kfs.module.cab.CabKeyConstants;
import org.kuali.kfs.module.cab.CabParameterConstants;
import org.kuali.kfs.module.cab.CabPropertyConstants;
import org.kuali.kfs.module.cab.businessobject.AssetTransactionType;
import org.kuali.kfs.module.cab.businessobject.GeneralLedgerEntry;
import org.kuali.kfs.module.cab.businessobject.GeneralLedgerEntryAsset;
import org.kuali.kfs.module.cab.businessobject.PretagDetail;
import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableDocument;
import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableItemAsset;
import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableLineAssetAccount;
import org.kuali.kfs.module.cab.document.service.GlLineService;
import org.kuali.kfs.module.cab.document.service.PurApInfoService;
import org.kuali.kfs.module.cam.CamsConstants;
import org.kuali.kfs.module.cam.CamsConstants.DocumentTypeName;
import org.kuali.kfs.module.cam.CamsKeyConstants;
import org.kuali.kfs.module.cam.CamsPropertyConstants;
import org.kuali.kfs.module.cam.businessobject.Asset;
import org.kuali.kfs.module.cam.businessobject.AssetGlobal;
import org.kuali.kfs.module.cam.businessobject.AssetGlobalDetail;
import org.kuali.kfs.module.cam.businessobject.AssetPaymentAssetDetail;
import org.kuali.kfs.module.cam.businessobject.AssetType;
import org.kuali.kfs.module.cam.document.service.AssetService;
import org.kuali.kfs.module.purap.PurapConstants;
import org.kuali.kfs.module.purap.PurapKeyConstants;
import org.kuali.kfs.module.purap.PurapParameterConstants;
import org.kuali.kfs.module.purap.PurapPropertyConstants;
import org.kuali.kfs.module.purap.businessobject.AccountsPayableItem;
import org.kuali.kfs.module.purap.businessobject.AvailabilityMatrix;
import org.kuali.kfs.module.purap.businessobject.PurApAccountingLine;
import org.kuali.kfs.module.purap.businessobject.PurApItem;
import org.kuali.kfs.module.purap.businessobject.PurchasingCapitalAssetItem;
import org.kuali.kfs.module.purap.businessobject.PurchasingItem;
import org.kuali.kfs.module.purap.businessobject.PurchasingItemBase;
import org.kuali.kfs.module.purap.document.AccountsPayableDocument;
import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
import org.kuali.kfs.module.purap.document.PurchasingDocument;
import org.kuali.kfs.module.purap.document.RequisitionDocument;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSKeyConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.businessobject.AccountingLine;
import org.kuali.kfs.sys.businessobject.Building;
import org.kuali.kfs.sys.businessobject.Room;
import org.kuali.kfs.sys.businessobject.SourceAccountingLine;
import org.kuali.kfs.sys.businessobject.TargetAccountingLine;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.document.AccountingDocument;
import org.kuali.kfs.sys.service.impl.KfsParameterConstants;
import org.kuali.rice.core.api.config.property.ConfigurationService;
import org.kuali.rice.core.api.criteria.PredicateFactory;
import org.kuali.rice.core.api.criteria.QueryByCriteria;
import org.kuali.rice.core.api.criteria.QueryByCriteria.Builder;
import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.coreservice.api.parameter.Parameter;
import org.kuali.rice.coreservice.api.parameter.ParameterRepositoryService;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kew.api.WorkflowDocument;
import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
import org.kuali.rice.kns.service.DataDictionaryService;
import org.kuali.rice.kns.service.DictionaryValidationService;
import org.kuali.rice.kns.util.KNSGlobalVariables;
import org.kuali.rice.krad.bo.DocumentHeader;
import org.kuali.rice.krad.datadictionary.AttributeDefinition;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.service.KualiModuleService;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.MessageMap;
import org.kuali.rice.krad.util.ObjectUtils;
import org.kuali.rice.location.api.campus.Campus;
import org.kuali.rice.location.api.campus.CampusService;
public class CapitalAssetBuilderModuleServiceImpl implements CapitalAssetBuilderModuleService {
private static final Logger LOG = Logger.getLogger(CapitalAssetBuilderModuleService.class);
protected GlLineService glLineService;
protected DataDictionaryService dataDictionaryService;
protected ParameterEvaluatorService parameterEvaluatorService;
protected ConfigurationService configurationService;
protected ParameterRepositoryService parameterRepositoryService;
protected BusinessObjectService businessObjectService;
protected ParameterService parameterService;
protected AssetService assetService;
protected PurApInfoService purApInfoService;
protected CapitalAssetManagementModuleService capitalAssetManagementModuleService;
protected KualiModuleService kualiModuleService;
protected BusinessObjectDictionaryService businessObjectDictionaryService;
protected CampusService campusService;
protected DictionaryValidationService dictionaryValidationService;
protected PurchasingAccountsPayableModuleService purchasingAccountsPayableModuleService;
protected static enum AccountCapitalObjectCode {
BOTH_NONCAP {
@Override
boolean validateAssetInfoAllowed(AccountingDocument accountingDocument, boolean isNewAssetBlank, boolean isUpdateAssetBlank) {
boolean valid = true;
// non capital object code, disallow the capital information entered.
if (!isNewAssetBlank || !isUpdateAssetBlank) {
// give error if data was entered
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_NUMBER, CabKeyConstants.CapitalAssetInformation.ERROR_ASSET_DO_NOT_ENTER_ANY_DATA);
valid = false;
}
return valid;
}
@Override
boolean isDocumentTypeRestricted(AccountingDocument accountingDocument) {
return false;
}
},
FROM_CAPITAL_TO_NONCAP {
@Override
boolean validateAssetInfoAllowed(AccountingDocument accountingDocument, boolean isNewAssetBlank, boolean isUpdateAssetBlank) {
boolean valid = validateAssetInfoEntered(isNewAssetBlank, isUpdateAssetBlank);
if (valid) {
if (isDocumentTypeRestricted(accountingDocument)) {
valid &= validateOnlyOneAssetInfoEntered(isNewAssetBlank, isUpdateAssetBlank);
}
// Capital on the FROM side and non-capital on the TO side, we only allow modify an asset.
else if (!isNewAssetBlank || isUpdateAssetBlank) {
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_NUMBER, CabKeyConstants.CapitalAssetInformation.ERROR_ASSET_UPDATE_ALLOW_ONLY);
valid = false;
}
}
return valid;
}
@Override
/**
* For Internal Billing, when credit capital on Income line, allow modify asset or create new asset.
*
* @see org.kuali.kfs.module.cab.service.impl.CapitalAssetBuilderModuleServiceImpl.AccountCapitalObjectCode#isDocumentTypeRestricted(org.kuali.kfs.sys.document.AccountingDocument)
*/
boolean isDocumentTypeRestricted(AccountingDocument accountingDocument) {
if (accountingDocument instanceof InternalBillingDocument) {
return true;
}
return false;
}
},
FROM_NONCAP_TO_CAPITAL {
@Override
boolean validateAssetInfoAllowed(AccountingDocument accountingDocument, boolean isNewAssetBlank, boolean isUpdateAssetBlank) {
boolean valid = validateAssetInfoEntered(isNewAssetBlank, isUpdateAssetBlank);
if (valid && isDocumentTypeRestricted(accountingDocument)) {
valid &= validateOnlyOneAssetInfoEntered(isNewAssetBlank, isUpdateAssetBlank);
}
return valid;
}
@Override
/**
* The document is restricted for all FP doc types
*
* @see org.kuali.kfs.module.cab.service.impl.CapitalAssetBuilderModuleServiceImpl.AccountCapitalObjectCode#isDocumentTypeRestricted(org.kuali.kfs.sys.document.AccountingDocument)
*/
boolean isDocumentTypeRestricted(AccountingDocument accountingDocument) {
return true;
}
},
BOTH_CAPITAL {
@Override
boolean validateAssetInfoAllowed(AccountingDocument accountingDocument, boolean isNewAssetBlank, boolean isUpdateAssetBlank) {
return validateAssetInfoEntered(isNewAssetBlank, isUpdateAssetBlank) && validateOnlyOneAssetInfoEntered(isNewAssetBlank, isUpdateAssetBlank);
}
@Override
boolean isDocumentTypeRestricted(AccountingDocument accountingDocument) {
return false;
}
};
/**
* Validate Asset Information is not blank.
*
* @param isNewAssetBlank
* @param isUpdateAssetBlank
* @return
*/
protected static boolean validateAssetInfoEntered(boolean isNewAssetBlank, boolean isUpdateAssetBlank) {
boolean valid = true;
// can modify existing or create new. Required to enter one of each type.
if (isNewAssetBlank && isUpdateAssetBlank) {
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_NUMBER, CabKeyConstants.CapitalAssetInformation.ERROR_ASSET_REQUIRE_DATA_ENTRY);
valid = false;
}
return valid;
}
/**
* Validate only either one asset information entered.
*
* @param isNewAssetBlank
* @param isUpdateAssetBlank
* @return
*/
protected static boolean validateOnlyOneAssetInfoEntered(boolean isNewAssetBlank, boolean isUpdateAssetBlank) {
boolean valid = true;
if (!isNewAssetBlank && !isUpdateAssetBlank) {
// Data exists on both crate new asset and update asset, give error
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_NUMBER, CabKeyConstants.CapitalAssetInformation.ERROR_ASSET_NEW_OR_UPDATE_ONLY);
valid = false;
}
return valid;
}
abstract boolean validateAssetInfoAllowed(AccountingDocument accoutingDocument, boolean isNewAssetBlank, boolean isUpdateAssetBlank);
abstract boolean isDocumentTypeRestricted(AccountingDocument accountingDocument);
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#getAllAssetTransactionTypes()
*/
@Override
public List<CapitalAssetBuilderAssetTransactionType> getAllAssetTransactionTypes() {
// RICE20: FIX ME!!!!! Someone did not understand the concept of "Externalizable" business objects...We can not
// necessarily retrieve them from the business object service
// Actually - using the EBO system here is not necessary at all
// Since this *IS* the implementation for the built in CAB module, it can use it's BO classes freely
Class<? extends CapitalAssetBuilderAssetTransactionType> assetTransactionTypeClass = this.getKualiModuleService().getResponsibleModuleService(CapitalAssetBuilderAssetTransactionType.class).getExternalizableBusinessObjectImplementation(CapitalAssetBuilderAssetTransactionType.class);
Map<String, Object> searchKeys = new HashMap<String, Object>();
searchKeys.put("active", "Y");
return (List<CapitalAssetBuilderAssetTransactionType>) businessObjectService.findMatching(assetTransactionTypeClass, searchKeys);
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#validatePurchasingAccountsPayableData(org.kuali.kfs.sys.document.AccountingDocument)
*/
@Override
public boolean validatePurchasingData(AccountingDocument accountingDocument) {
Boolean valid = true;
PurchasingDocument purchasingDocument = (PurchasingDocument) accountingDocument;
String systemTypeCode = purchasingDocument.getCapitalAssetSystemTypeCode();
String capitalAssetSystemStateCode = purchasingDocument.getCapitalAssetSystemStateCode();
String documentType = (purchasingDocument instanceof RequisitionDocument) ? "REQUISITION" : "PURCHASE_ORDER";
for (PurApItem item : purchasingDocument.getItems()) {
List accountingLines = item.getSourceAccountingLines();
for (Iterator iterator = accountingLines.iterator(); iterator.hasNext(); ) {
PurApAccountingLine accountingLine = (PurApAccountingLine) iterator.next();
String coa = accountingLine.getChartOfAccountsCode();
if (PurapConstants.CapitalAssetSystemTypes.INDIVIDUAL.equals(systemTypeCode)) {
valid &= validateIndividualCapitalAssetSystemFromPurchasing(capitalAssetSystemStateCode, purchasingDocument.getPurchasingCapitalAssetItems(), coa, documentType);
} else if (PurapConstants.CapitalAssetSystemTypes.ONE_SYSTEM.equals(systemTypeCode)) {
valid &= validateOneSystemCapitalAssetSystemFromPurchasing(capitalAssetSystemStateCode, purchasingDocument.getPurchasingCapitalAssetSystems(), purchasingDocument.getPurchasingCapitalAssetItems(), coa, documentType);
} else if (PurapConstants.CapitalAssetSystemTypes.MULTIPLE.equals(systemTypeCode)) {
valid &= validateMultipleSystemsCapitalAssetSystemFromPurchasing(capitalAssetSystemStateCode, purchasingDocument.getPurchasingCapitalAssetSystems(), purchasingDocument.getPurchasingCapitalAssetItems(), coa, documentType);
}
}
}
return valid;
}
@Override
public boolean validateAccountsPayableData(AccountingDocument accountingDocument) {
AccountsPayableDocument apDocument = (AccountsPayableDocument) accountingDocument;
boolean valid = true;
for (PurApItem purApItem : apDocument.getItems()) {
AccountsPayableItem accountsPayableItem = (AccountsPayableItem) purApItem;
// only run on ap items that were line items (not additional charge items) and were cams items
if ((!accountsPayableItem.getItemType().isAdditionalChargeIndicator()) && StringUtils.isNotEmpty(accountsPayableItem.getCapitalAssetTransactionTypeCode())) {
valid &= validateAccountsPayableItem(accountsPayableItem);
}
}
return valid;
}
/**
* Perform the item level capital asset validation to determine if the given document is not allowed to become an Automatic
* Purchase Order (APO). The APO is not allowed if any accounting strings on the document are using an object level indicated as
* capital via a parameter setting.
*/
@Override
public boolean doesAccountingLineFailAutomaticPurchaseOrderRules(AccountingLine accountingLine) {
PurApAccountingLine purapAccountingLine = (PurApAccountingLine) accountingLine;
purapAccountingLine.refreshNonUpdateableReferences();
return parameterEvaluatorService.getParameterEvaluator(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, CabParameterConstants.CapitalAsset.CAPITAL_ASSET_OBJECT_LEVELS, purapAccountingLine.getObjectCode().getFinancialObjectLevelCode()).evaluationSucceeds();
}
/**
* Perform the document level capital asset validation to determine if the given document is not allowed to become an Automatic
* Purchase Order (APO). The APO is not allowed if any capital asset items exist on the document.
*/
@Override
public boolean doesDocumentFailAutomaticPurchaseOrderRules(AccountingDocument accountingDocument) {
PurchasingDocument purchasingDocument = (PurchasingDocument) accountingDocument;
return ObjectUtils.isNotNull(purchasingDocument.getPurchasingCapitalAssetItems()) && !purchasingDocument.getPurchasingCapitalAssetItems().isEmpty();
}
public boolean validateAutomaticPurchaseOrderRule(AccountingDocument accountingDocument) {
PurchasingDocument purchasingDocument = (PurchasingDocument) accountingDocument;
for (PurApItem item : purchasingDocument.getItems()) {
if (doesItemNeedCapitalAsset(item.getItemTypeCode(), item.getSourceAccountingLines())) {
// if the item needs capital asset, we cannot have an APO, so return false.
return false;
}
}
return true;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#doesItemNeedCapitalAsset(java.lang.String, java.util.List)
*/
@Override
public boolean doesItemNeedCapitalAsset(String itemTypeCode, List accountingLines) {
if (PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE.equals(itemTypeCode)) {
// FIXME: Chris - this should be true but need to look to see where itemline number is referenced first
// return true;
return false;
}// else
for (Iterator iterator = accountingLines.iterator(); iterator.hasNext(); ) {
PurApAccountingLine accountingLine = (PurApAccountingLine) iterator.next();
accountingLine.refreshReferenceObject(KFSPropertyConstants.OBJECT_CODE);
if (ObjectUtils.isNotNull(accountingLine.getObjectCode()) && isCapitalAssetObjectCode(accountingLine.getObjectCode())) {
return true;
}
}
return false;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#validateUpdateCAMSView(org.kuali.kfs.sys.document.AccountingDocument)
*/
@Override
public boolean validateUpdateCAMSView(AccountingDocument accountingDocument) {
PurchasingDocument purchasingDocument = (PurchasingDocument) accountingDocument;
boolean valid = true;
for (PurApItem purapItem : purchasingDocument.getItems()) {
if (purapItem.getItemType().isLineItemIndicator()) {
if (!doesItemNeedCapitalAsset(purapItem.getItemTypeCode(), purapItem.getSourceAccountingLines())) {
PurchasingCapitalAssetItem camsItem = ((PurchasingItem) purapItem).getPurchasingCapitalAssetItem();
if (camsItem != null && !camsItem.isEmpty()) {
valid = false;
GlobalVariables.getMessageMap().putError("newPurchasingItemCapitalAssetLine", PurapKeyConstants.ERROR_CAPITAL_ASSET_ITEM_NOT_CAMS_ELIGIBLE, "in line item # " + purapItem.getItemLineNumber());
}
}
}
}
return valid;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#validateAddItemCapitalAssetBusinessRules(org.kuali.kfs.integration.purap.ItemCapitalAsset)
*/
@Override
public boolean validateAddItemCapitalAssetBusinessRules(ItemCapitalAsset asset) {
boolean valid = true;
if (asset.getCapitalAssetNumber() == null) {
valid = false;
} else {
valid = dictionaryValidationService.isBusinessObjectValid(asset);
}
if (!valid) {
String propertyName = "newPurchasingItemCapitalAssetLine." + PurapPropertyConstants.CAPITAL_ASSET_NUMBER;
String errorKey = PurapKeyConstants.ERROR_CAPITAL_ASSET_ASSET_NUMBER_MUST_BE_LONG_NOT_NULL;
GlobalVariables.getMessageMap().putError(propertyName, errorKey);
} else {
Map<String, String> params = new HashMap<String, String>();
params.put(KFSPropertyConstants.CAPITAL_ASSET_NUMBER, asset.getCapitalAssetNumber().toString());
Asset retrievedAsset = businessObjectService.findByPrimaryKey(Asset.class, params);
if (ObjectUtils.isNull(retrievedAsset)) {
valid = false;
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_NUMBER);
GlobalVariables.getMessageMap().putError("newPurchasingItemCapitalAssetLine." + KFSPropertyConstants.CAPITAL_ASSET_NUMBER, KFSKeyConstants.ERROR_EXISTENCE, label);
} else {
boolean isCapitalAsset = assetService.isCapitalAsset(retrievedAsset) && !assetService.isAssetRetired(retrievedAsset);
if (!isCapitalAsset) {
valid = false;
String propertyName = "newPurchasingItemCapitalAssetLine." + PurapPropertyConstants.CAPITAL_ASSET_NUMBER;
String errorKey = CabKeyConstants.CapitalAssetInformation.ERROR_ASSET_ACTIVE_CAPITAL_ASSET_REQUIRED;
GlobalVariables.getMessageMap().putError(propertyName, errorKey);
}
}
}
return valid;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#warningObjectLevelCapital(org.kuali.kfs.sys.document.AccountingDocument)
*/
@Override
public boolean warningObjectLevelCapital(AccountingDocument accountingDocument) {
org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument purapDocument = (org.kuali.kfs.module.purap.document.PurchasingAccountsPayableDocument) accountingDocument;
for (PurApItem item : purapDocument.getItems()) {
if (item.getItemType().isLineItemIndicator() && item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
if (!ObjectUtils.isNull(item.getItemUnitPrice())) {
List<PurApAccountingLine> accounts = item.getSourceAccountingLines();
BigDecimal unitPrice = item.getItemUnitPrice();
String itemIdentifier = item.getItemIdentifierString();
for (PurApAccountingLine account : accounts) {
ObjectCode objectCode = account.getObjectCode();
if (!validateLevelCapitalAssetIndication(unitPrice, objectCode, itemIdentifier)) {
// found an error
return false;
}
}
}
}
}
// no need for error
return true;
}
/**
* Validates the capital asset field requirements based on system parameter and chart for individual system type. This also
* calls validations for quantity on locations equal quantity on line items, validates that the transaction type allows asset
* number and validates the non quantity driven allowed indicator.
*
* @param systemState
* @param capitalAssetItems
* @param chartCode
* @param documentType
* @return
*/
protected boolean validateIndividualCapitalAssetSystemFromPurchasing(String systemState, List<PurchasingCapitalAssetItem> capitalAssetItems, String chartCode, String documentType) {
// For Individual Asset system type, the List of CapitalAssetSystems in the input parameter for
// validateAllFieldRequirementsByChart
// should be null. So we'll pass in a null here.
boolean valid = validateAllFieldRequirementsByChart(systemState, null, capitalAssetItems, chartCode, documentType, PurapConstants.CapitalAssetSystemTypes.INDIVIDUAL);
valid &= validateQuantityOnLocationsEqualsQuantityOnItem(capitalAssetItems, PurapConstants.CapitalAssetSystemTypes.INDIVIDUAL, systemState);
valid &= validateIndividualSystemPurchasingTransactionTypesAllowingAssetNumbers(capitalAssetItems);
valid &= validateNonQuantityDrivenAllowedIndicatorAndTradeIn(capitalAssetItems);
return valid;
}
/**
* Validates the capital asset field requirements based on system parameter and chart for one system type. This also calls
* validations that the transaction type allows asset number and validates the non quantity driven allowed indicator.
*
* @param systemState
* @param capitalAssetSystems
* @param capitalAssetItems
* @param chartCode
* @param documentType
* @return
*/
protected boolean validateOneSystemCapitalAssetSystemFromPurchasing(String systemState, List<CapitalAssetSystem> capitalAssetSystems, List<PurchasingCapitalAssetItem> capitalAssetItems, String chartCode, String documentType) {
boolean valid = validateAllFieldRequirementsByChart(systemState, capitalAssetSystems, capitalAssetItems, chartCode, documentType, PurapConstants.CapitalAssetSystemTypes.ONE_SYSTEM);
String capitalAssetTransactionType = capitalAssetItems.get(0).getCapitalAssetTransactionTypeCode();
String prefix = "document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_SYSTEMS + "[0].";
valid &= validatePurchasingTransactionTypesAllowingAssetNumbers(capitalAssetSystems.get(0), capitalAssetTransactionType, prefix);
valid &= validateNonQuantityDrivenAllowedIndicatorAndTradeIn(capitalAssetItems);
return valid;
}
/**
* Validates the capital asset field requirements based on system parameter and chart for multiple system type. This also calls
* validations that the transaction type allows asset number and validates the non quantity driven allowed indicator.
*
* @param systemState
* @param capitalAssetSystems
* @param capitalAssetItems
* @param chartCode
* @param documentType
* @return
*/
protected boolean validateMultipleSystemsCapitalAssetSystemFromPurchasing(String systemState, List<CapitalAssetSystem> capitalAssetSystems, List<PurchasingCapitalAssetItem> capitalAssetItems, String chartCode, String documentType) {
boolean valid = validateAllFieldRequirementsByChart(systemState, capitalAssetSystems, capitalAssetItems, chartCode, documentType, PurapConstants.CapitalAssetSystemTypes.MULTIPLE);
String capitalAssetTransactionType = capitalAssetItems.get(0).getCapitalAssetTransactionTypeCode();
String prefix = "document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_SYSTEMS + "[0].";
valid &= validatePurchasingTransactionTypesAllowingAssetNumbers(capitalAssetSystems.get(0), capitalAssetTransactionType, prefix);
valid &= validateNonQuantityDrivenAllowedIndicatorAndTradeIn(capitalAssetItems);
return valid;
}
/**
* Validates all the field requirements by chart. It obtains a List of parameters where the parameter names are like
* "CHARTS_REQUIRING%" then loop through these parameters. If the system type is individual then invoke the
* validateFieldRequirementByChartForIndividualSystemType for further validation, otherwise invoke the
* validateFieldRequirementByChartForOneOrMultipleSystemType for further validation.
*
* @param systemState
* @param capitalAssetSystems
* @param capitalAssetItems
* @param chartCode
* @param documentType
* @param systemType
* @return
*/
protected boolean validateAllFieldRequirementsByChart(String systemState, List<CapitalAssetSystem> capitalAssetSystems, List<PurchasingCapitalAssetItem> capitalAssetItems, String chartCode, String documentType, String systemType) {
boolean valid = true;
Builder qbc = QueryByCriteria.Builder.create();
qbc.setPredicates(and(
equal(CabPropertyConstants.Parameter.PARAMETER_NAMESPACE_CODE, CabConstants.Parameters.NAMESPACE),
equal(CabPropertyConstants.Parameter.PARAMETER_DETAIL_TYPE_CODE, CabConstants.Parameters.DETAIL_TYPE_DOCUMENT),
PredicateFactory.like(CabPropertyConstants.Parameter.PARAMETER_NAME, "CHARTS_REQUIRING%" + documentType)));
List<Parameter> results = parameterRepositoryService.findParameters(qbc.build()).getResults();
for (Parameter parameter : results) {
if (ObjectUtils.isNotNull(parameter)) {
if (systemType.equals(PurapConstants.CapitalAssetSystemTypes.INDIVIDUAL)) {
valid &= validateFieldRequirementByChartForIndividualSystemType(systemState, capitalAssetItems, chartCode, parameter.getName(), parameter.getValue());
} else {
valid &= validateFieldRequirementByChartForOneOrMultipleSystemType(systemType, systemState, capitalAssetSystems, capitalAssetItems, chartCode, parameter.getName(), parameter.getValue());
}
}
}
return valid;
}
/**
* Validates all the field requirements by chart. It obtains a List of parameters where the parameter names are like
* "CHARTS_REQUIRING%" then loop through these parameters. If any of the parameter's values is null, then return false
*
* @param accountingDocument
* @return
*/
@Override
public boolean validateAllFieldRequirementsByChart(AccountingDocument accountingDocument) {
PurchasingDocument purchasingDocument = (PurchasingDocument) accountingDocument;
String documentType = (purchasingDocument instanceof RequisitionDocument) ? "REQUISITION" : "PURCHASE_ORDER";
boolean valid = true;
for (PurApItem item : purchasingDocument.getItems()) {
String itemTypeCode = item.getItemTypeCode();
List accountingLines = item.getSourceAccountingLines();
for (Iterator iterator = accountingLines.iterator(); iterator.hasNext(); ) {
PurApAccountingLine accountingLine = (PurApAccountingLine) iterator.next();
String coa = accountingLine.getChartOfAccountsCode();
//rice20 not sure if this will work trying to replace getBean(ParameterService.class).retrieveParametersGivenLookupCriteria(criteria));
Builder qbc = QueryByCriteria.Builder.create();
qbc.setPredicates(and(
equal(CabPropertyConstants.Parameter.PARAMETER_NAMESPACE_CODE, CabConstants.Parameters.NAMESPACE),
equal(CabPropertyConstants.Parameter.PARAMETER_DETAIL_TYPE_CODE, CabConstants.Parameters.DETAIL_TYPE_DOCUMENT),
PredicateFactory.like(CabPropertyConstants.Parameter.PARAMETER_NAME, "CHARTS_REQUIRING%" + documentType),
PredicateFactory.like(CabPropertyConstants.Parameter.PARAMETER_VALUE, "%" + coa + "%")));
List<Parameter> results = (parameterRepositoryService.findParameters(qbc.build())).getResults();
for (Parameter parameter : results) {
if (ObjectUtils.isNotNull(parameter)) {
if (parameter.getValue() != null) {
return false;
}
}
}
}
}
return valid;
}
/**
* Validates for PURCHASING_OBJECT_SUB_TYPES parameter. If at least one object code of any accounting line entered is of this
* type, then return false.
*
* @param accountingDocument
* @return
*/
@Override
public boolean validatePurchasingObjectSubType(AccountingDocument accountingDocument) {
boolean valid = true;
PurchasingDocument purchasingDocument = (PurchasingDocument) accountingDocument;
for (PurApItem item : purchasingDocument.getItems()) {
String itemTypeCode = item.getItemTypeCode();
List accountingLines = item.getSourceAccountingLines();
for (Iterator iterator = accountingLines.iterator(); iterator.hasNext(); ) {
PurApAccountingLine accountingLine = (PurApAccountingLine) iterator.next();
accountingLine.refreshReferenceObject(KFSPropertyConstants.OBJECT_CODE);
if (ObjectUtils.isNotNull(accountingLine.getObjectCode()) && isCapitalAssetObjectCode(accountingLine.getObjectCode())) {
return false;
}
}
}
return valid;
}
/**
* Validates field requirement by chart for one or multiple system types.
*
* @param systemType
* @param systemState
* @param capitalAssetSystems
* @param capitalAssetItems
* @param chartCode
* @param parameterName
* @param parameterValueString
* @return
*/
protected boolean validateFieldRequirementByChartForOneOrMultipleSystemType(String systemType, String systemState, List<CapitalAssetSystem> capitalAssetSystems, List<PurchasingCapitalAssetItem> capitalAssetItems, String chartCode, String parameterName, String parameterValueString) {
boolean valid = true;
boolean needValidation = (parameterEvaluatorService.getParameterEvaluator(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, parameterName, chartCode).evaluationSucceeds());
if (needValidation) {
if (parameterName.startsWith("CHARTS_REQUIRING_LOCATIONS_ADDRESS")) {
return validateCapitalAssetLocationAddressFieldsOneOrMultipleSystemType(capitalAssetSystems);
}
String mappedName = PurapConstants.CAMS_REQUIREDNESS_FIELDS.REQUIREDNESS_FIELDS_BY_PARAMETER_NAMES.get(parameterName);
if (mappedName != null) {
// Check the availability matrix here, if this field doesn't exist according to the avail. matrix, then no need
// to validate any further.
String availableValue = getValueFromAvailabilityMatrix(mappedName, systemType, systemState);
if (availableValue.equals(PurapConstants.CapitalAssetAvailability.NONE)) {
return true;
}
// capitalAssetTransactionType field is off the item
if (mappedName.equals(PurapPropertyConstants.CAPITAL_ASSET_TRANSACTION_TYPE_CODE)) {
String[] mappedNames = {PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS, mappedName};
for (PurchasingCapitalAssetItem item : capitalAssetItems) {
StringBuffer keyBuffer = new StringBuffer("document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS + "[" + new Integer(item.getPurchasingItem().getItemLineNumber().intValue() - 1) + "].");
valid &= validateFieldRequirementByChartHelper(item, ArrayUtils.subarray(mappedNames, 1, mappedNames.length), keyBuffer, item.getPurchasingItem().getItemLineNumber());
}
}
// all the other fields are off the system.
else {
List<String> mappedNamesList = new ArrayList<String>();
mappedNamesList.add(PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_SYSTEMS);
if (mappedName.indexOf(".") < 0) {
mappedNamesList.add(mappedName);
} else {
mappedNamesList.addAll(mappedNameSplitter(mappedName));
}
// For One system type, we would only have 1 CapitalAssetSystem, however, for multiple we may have more than
// one systems in the future. Either way, this for loop should allow both the one system and multiple system
// types to work fine.
int count = 0;
for (CapitalAssetSystem system : capitalAssetSystems) {
StringBuffer keyBuffer = new StringBuffer("document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_SYSTEMS + "[" + new Integer(count) + "].");
valid &= validateFieldRequirementByChartHelper(system, ArrayUtils.subarray(mappedNamesList.toArray(), 1, mappedNamesList.size()), keyBuffer, null);
count++;
}
}
}
}
return valid;
}
/**
* Validates the field requirement by chart for individual system type.
*
* @param systemState
* @param capitalAssetItems
* @param chartCode
* @param parameterName
* @param parameterValueString
* @return
*/
protected boolean validateFieldRequirementByChartForIndividualSystemType(String systemState, List<PurchasingCapitalAssetItem> capitalAssetItems, String chartCode, String parameterName, String parameterValueString) {
boolean valid = true;
boolean needValidation = (parameterEvaluatorService.getParameterEvaluator(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, parameterName, chartCode).evaluationSucceeds());
if (needValidation) {
if (parameterName.startsWith("CHARTS_REQUIRING_LOCATIONS_ADDRESS")) {
return validateCapitalAssetLocationAddressFieldsForIndividualSystemType(capitalAssetItems);
}
String mappedName = PurapConstants.CAMS_REQUIREDNESS_FIELDS.REQUIREDNESS_FIELDS_BY_PARAMETER_NAMES.get(parameterName);
if (mappedName != null) {
// Check the availability matrix here, if this field doesn't exist according to the avail. matrix, then no need
// to validate any further.
String availableValue = getValueFromAvailabilityMatrix(mappedName, PurapConstants.CapitalAssetSystemTypes.INDIVIDUAL, systemState);
if (availableValue.equals(PurapConstants.CapitalAssetAvailability.NONE)) {
return true;
}
// capitalAssetTransactionType field is off the item
List<String> mappedNamesList = new ArrayList<String>();
if (mappedName.equals(PurapPropertyConstants.CAPITAL_ASSET_TRANSACTION_TYPE_CODE)) {
mappedNamesList.add(PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS);
mappedNamesList.add(mappedName);
}
// all the other fields are off the system which is off the item
else {
mappedNamesList.add(PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS);
mappedNamesList.add(PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_SYSTEM);
if (mappedName.indexOf(".") < 0) {
mappedNamesList.add(mappedName);
} else {
mappedNamesList.addAll(mappedNameSplitter(mappedName));
}
}
// For Individual system type, we'll always iterate through the item, then if the field is off the system, we'll get
// it through
// the purchasingCapitalAssetSystem of the item.
for (PurchasingCapitalAssetItem item : capitalAssetItems) {
StringBuffer keyBuffer = new StringBuffer("document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS + "[" + new Integer(item.getPurchasingItem().getItemLineNumber().intValue() - 1) + "].");
valid &= validateFieldRequirementByChartHelper(item, ArrayUtils.subarray(mappedNamesList.toArray(), 1, mappedNamesList.size()), keyBuffer, item.getPurchasingItem().getItemLineNumber());
}
}
}
return valid;
}
/**
* Utility method to split a long String using the "." as the delimiter then add each of the array element into a List of String
* and return the List of String.
*
* @param mappedName The String to be splitted.
* @return The List of String after being splitted, with the "." as delimiter.
*/
protected List<String> mappedNameSplitter(String mappedName) {
List<String> result = new ArrayList<String>();
String[] mappedNamesArray = mappedName.split("\\.");
for (int i = 0; i < mappedNamesArray.length; i++) {
result.add(mappedNamesArray[i]);
}
return result;
}
/**
* Validates the field requirement by chart recursively and give error messages when it returns false.
*
* @param bean The object to be used to obtain the property value
* @param mappedNames The array of Strings which when combined together, they form the field property
* @param errorKey The error key to be used for adding error messages to the error map.
* @param itemNumber The Integer that represents the item number that we're currently iterating.
* @return true if it passes the validation.
*/
protected boolean validateFieldRequirementByChartHelper(Object bean, Object[] mappedNames, StringBuffer errorKey, Integer itemNumber) {
boolean valid = true;
Object value = ObjectUtils.getPropertyValue(bean, (String) mappedNames[0]);
if (ObjectUtils.isNull(value)) {
errorKey.append(mappedNames[0]);
String fieldName = dataDictionaryService.getAttributeErrorLabel(bean.getClass(), (String) mappedNames[0]);
if (itemNumber != null) {
fieldName = fieldName + " in Item " + itemNumber;
}
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, fieldName);
return false;
} else if (value instanceof Collection) {
if (((Collection) value).isEmpty()) {
// if this collection doesn't contain anything, when it's supposed to contain some strings with values, return
// false.
errorKey.append(mappedNames[0]);
String mappedNameStr = (String) mappedNames[0];
String methodToInvoke = "get" + (mappedNameStr.substring(0, 1)).toUpperCase() + mappedNameStr.substring(1, mappedNameStr.length() - 1) + "Class";
Class offendingClass;
try {
offendingClass = (Class) bean.getClass().getMethod(methodToInvoke, (Class[]) null).invoke(bean, (Object[]) null);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
org.kuali.rice.krad.datadictionary.BusinessObjectEntry boe = dataDictionaryService.getDataDictionary().getBusinessObjectEntry(offendingClass.getSimpleName());
List<AttributeDefinition> offendingAttributes = boe.getAttributes();
AttributeDefinition offendingAttribute = offendingAttributes.get(0);
String fieldName = dataDictionaryService.getAttributeShortLabel(offendingClass, offendingAttribute.getName());
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, fieldName);
return false;
}
int count = 0;
for (Iterator iter = ((Collection) value).iterator(); iter.hasNext(); ) {
errorKey.append(mappedNames[0] + "[" + count + "].");
count++;
valid &= validateFieldRequirementByChartHelper(iter.next(), ArrayUtils.subarray(mappedNames, 1, mappedNames.length), errorKey, itemNumber);
}
return valid;
} else if (StringUtils.isBlank(value.toString())) {
errorKey.append(mappedNames[0]);
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, (String) mappedNames[0]);
return false;
} else if (mappedNames.length > 1) {
// this means we have not reached the end of a single field to be traversed yet, so continue with the recursion.
errorKey.append(mappedNames[0]).append(".");
valid &= validateFieldRequirementByChartHelper(value, ArrayUtils.subarray(mappedNames, 1, mappedNames.length), errorKey, itemNumber);
return valid;
} else {
return true;
}
}
protected String getValueFromAvailabilityMatrix(String fieldName, String systemType, String systemState) {
for (AvailabilityMatrix am : PurapConstants.CAMS_AVAILABILITY_MATRIX.MATRIX_LIST) {
if (am.fieldName.equals(fieldName) && am.systemState.equals(systemState) && am.systemType.equals(systemType)) {
return am.availableValue;
}
}
// if we can't find any matching from availability matrix, return null for now.
return null;
}
/**
* Validates that the total quantity on all locations equals to the quantity on the line item. This is only used for IND system
* type.
*
* @param capitalAssetItems
* @return true if the total quantity on all locations equals to the quantity on the line item.
*/
protected boolean validateQuantityOnLocationsEqualsQuantityOnItem(List<PurchasingCapitalAssetItem> capitalAssetItems, String systemType, String systemState) {
boolean valid = true;
String availableValue = getValueFromAvailabilityMatrix(PurapPropertyConstants.CAPITAL_ASSET_LOCATIONS + "." + PurapPropertyConstants.QUANTITY, systemType, systemState);
if (availableValue.equals(PurapConstants.CapitalAssetAvailability.NONE)) {
// If the location quantity isn't available on the document given the system type and system state, we don't need to
// validate this, just return true.
return true;
}
int count = 0;
for (PurchasingCapitalAssetItem item : capitalAssetItems) {
if (item.getPurchasingItem() != null && item.getPurchasingItem().getItemType().isQuantityBasedGeneralLedgerIndicator() && !item.getPurchasingCapitalAssetSystem().getCapitalAssetLocations().isEmpty()) {
KualiDecimal total = new KualiDecimal(0);
for (CapitalAssetLocation location : item.getPurchasingCapitalAssetSystem().getCapitalAssetLocations()) {
if (ObjectUtils.isNotNull(location.getItemQuantity())) {
total = total.add(location.getItemQuantity());
}
}
if (!item.getPurchasingItem().getItemQuantity().equals(total)) {
valid = false;
String errorKey = PurapKeyConstants.ERROR_CAPITAL_ASSET_LOCATIONS_QUANTITY_MUST_EQUAL_ITEM_QUANTITY;
String propertyName = "document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS + "[" + count + "]." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_SYSTEM + ".newPurchasingCapitalAssetLocationLine." + PurapPropertyConstants.QUANTITY;
GlobalVariables.getMessageMap().putError(propertyName, errorKey, Integer.toString(count + 1));
}
}
count++;
}
return valid;
}
/**
* Validates for the individual system type that for each of the items, the capitalAssetTransactionTypeCode matches the system
* parameter PURCHASING_ASSET_TRANSACTION_TYPES_ALLOWING_ASSET_NUMBERS, the method will return true but if it doesn't match the
* system parameter, then loop through each of the itemCapitalAssets. If there is any non-null capitalAssetNumber then return
* false.
*
* @param capitalAssetItems the List of PurchasingCapitalAssetItems on the document to be validated
* @return false if the capital asset transaction type does not match the system parameter that allows asset numbers but the
* itemCapitalAsset contains at least one asset numbers.
*/
protected boolean validateIndividualSystemPurchasingTransactionTypesAllowingAssetNumbers(List<PurchasingCapitalAssetItem> capitalAssetItems) {
boolean valid = true;
int count = 0;
for (PurchasingCapitalAssetItem capitalAssetItem : capitalAssetItems) {
String prefix = "document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS + "[" + count + "].";
valid &= validatePurchasingTransactionTypesAllowingAssetNumbers(capitalAssetItem.getPurchasingCapitalAssetSystem(), capitalAssetItem.getCapitalAssetTransactionTypeCode(), prefix);
count++;
}
return valid;
}
/**
* Generic validation that if the capitalAssetTransactionTypeCode does not match the system parameter
* PURCHASING_ASSET_TRANSACTION_TYPES_ALLOWING_ASSET_NUMBERS and at least one of the itemCapitalAssets contain a non-null
* capitalAssetNumber then return false. This method is used by one system and multiple system types as well as being used as a
* helper method for validateIndividualSystemPurchasingTransactionTypesAllowingAssetNumbers method.
*
* @param capitalAssetSystem the capitalAssetSystem containing a List of itemCapitalAssets to be validated.
* @param capitalAssetTransactionType the capitalAssetTransactionTypeCode containing asset numbers to be validated.
* @return false if the capital asset transaction type does not match the system parameter that allows asset numbers but the
* itemCapitalAsset contains at least one asset numbers.
*/
protected boolean validatePurchasingTransactionTypesAllowingAssetNumbers(CapitalAssetSystem capitalAssetSystem, String capitalAssetTransactionType, String prefix) {
boolean allowedAssetNumbers = (parameterEvaluatorService.getParameterEvaluator(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, CabParameterConstants.CapitalAsset.PURCHASING_ASSET_TRANSACTION_TYPES_ALLOWING_ASSET_NUMBERS, capitalAssetTransactionType).evaluationSucceeds());
if (allowedAssetNumbers) {
// If this is a transaction type that allows asset numbers, we don't need to validate anymore, just return true here.
return true;
} else {
for (ItemCapitalAsset asset : capitalAssetSystem.getItemCapitalAssets()) {
if (asset.getCapitalAssetNumber() != null) {
String propertyName = prefix + PurapPropertyConstants.CAPITAL_ASSET_TRANSACTION_TYPE_CODE;
GlobalVariables.getMessageMap().putError(propertyName, PurapKeyConstants.ERROR_CAPITAL_ASSET_ASSET_NUMBERS_NOT_ALLOWED_TRANS_TYPE, capitalAssetTransactionType);
return false;
}
}
}
return true;
}
/**
* TODO: rename this method removing trade in reference? Validates that if the non quantity drive allowed indicator on the
* capital asset transaction type is false and the item is of non quantity type
*
* @param capitalAssetItems The List of PurchasingCapitalAssetItem to be validated.
* @return false if the indicator is false and there is at least one non quantity items on the list.
*/
protected boolean validateNonQuantityDrivenAllowedIndicatorAndTradeIn(List<PurchasingCapitalAssetItem> capitalAssetItems) {
boolean valid = true;
int count = 0;
for (PurchasingCapitalAssetItem capitalAssetItem : capitalAssetItems) {
String prefix = "document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS + "[" + count + "].";
if (StringUtils.isNotBlank(capitalAssetItem.getCapitalAssetTransactionTypeCode())) {
// ((PurchasingCapitalAssetItemBase)
// capitalAssetItem).refreshReferenceObject(PurapPropertyConstants.CAPITAL_ASSET_TRANSACTION_TYPE);
if (!capitalAssetItem.getCapitalAssetTransactionType().getCapitalAssetNonquantityDrivenAllowIndicator()) {
if (!capitalAssetItem.getPurchasingItem().getItemType().isQuantityBasedGeneralLedgerIndicator()) {
String propertyName = prefix + PurapPropertyConstants.CAPITAL_ASSET_TRANSACTION_TYPE_CODE;
GlobalVariables.getMessageMap().putError(propertyName, PurapKeyConstants.ERROR_CAPITAL_ASSET_TRANS_TYPE_NOT_ALLOWING_NON_QUANTITY_ITEMS, capitalAssetItem.getCapitalAssetTransactionTypeCode());
valid &= false;
}
}
}
count++;
}
return valid;
}
/**
* Wrapper to do Capital Asset validations, generating errors instead of warnings. Makes sure that the given item's data
* relevant to its later possible classification as a Capital Asset is internally consistent, by marshaling and calling the
* methods marked as Capital Asset validations. This implementation assumes that all object codes are valid (real) object codes.
*
* @param recurringPaymentType The item's document's RecurringPaymentType
* @param item A PurchasingItemBase object
* @param apoCheck True if this check is for APO purposes
* @return True if the item passes all Capital Asset validations
*/
@Override
public boolean validateItemCapitalAssetWithErrors(String recurringPaymentTypeCode, ExternalPurApItem item, boolean apoCheck) {
PurchasingItemBase purchasingItem = (PurchasingItemBase) item;
List<String> previousErrorPath = GlobalVariables.getMessageMap().getErrorPath();
GlobalVariables.getMessageMap().clearErrorPath();
GlobalVariables.getMessageMap().addToErrorPath(PurapConstants.CAPITAL_ASSET_TAB_ERRORS);
boolean result = validatePurchasingItemCapitalAsset(recurringPaymentTypeCode, purchasingItem);
GlobalVariables.getMessageMap().clearErrorPath();
return result;
}
/**
* Makes sure that the given item's data relevant to its later possible classification as a Capital Asset is internally
* consistent, by marshaling and calling the methods marked as Capital Asset validations. This implementation assumes that all
* object codes are valid (real) object codes.
*
* @param recurringPaymentType The item's document's RecurringPaymentType
* @param item A PurchasingItemBase object
* @param warn A boolean which should be set to true if warnings are to be set on the calling document for most of the
* validations, rather than errors.
* @return True if the item passes all Capital Asset validations
*/
protected boolean validatePurchasingItemCapitalAsset(String recurringPaymentTypeCode, PurchasingItem item) {
boolean valid = true;
String capitalAssetTransactionTypeCode = "";
AssetTransactionType capitalAssetTransactionType = null;
String itemIdentifier = item.getItemIdentifierString();
if (item.getPurchasingCapitalAssetItem() != null) {
capitalAssetTransactionTypeCode = item.getPurchasingCapitalAssetItem().getCapitalAssetTransactionTypeCode();
// ((PurchasingCapitalAssetItemBase)
// item.getPurchasingCapitalAssetItem()).refreshReferenceObject(PurapPropertyConstants.CAPITAL_ASSET_TRANSACTION_TYPE);
capitalAssetTransactionType = (AssetTransactionType) item.getPurchasingCapitalAssetItem().getCapitalAssetTransactionType();
}
// These checks do not depend on Accounting Line information, but do depend on transaction type.
if (!StringUtils.isEmpty(capitalAssetTransactionTypeCode)) {
valid &= validateCapitalAssetTransactionTypeVersusRecurrence(capitalAssetTransactionType, recurringPaymentTypeCode, itemIdentifier);
}
return valid &= validatePurapItemCapitalAsset(item, capitalAssetTransactionType);
}
/**
* This method validates purapItem giving a transaction type.
*
* @param recurringPaymentType
* @param item
* @param warn
* @return
*/
protected boolean validatePurapItemCapitalAsset(PurApItem item, AssetTransactionType capitalAssetTransactionType) {
boolean valid = true;
String itemIdentifier = item.getItemIdentifierString();
boolean quantityBased = item.getItemType().isQuantityBasedGeneralLedgerIndicator();
BigDecimal itemUnitPrice = item.getItemUnitPrice();
HashSet<String> capitalOrExpenseSet = new HashSet<String>(); // For the first validation on every accounting line.
boolean performObjectCodeVersusTransactionTypeValidation = true;
if (item instanceof AccountsPayableItem) {
performObjectCodeVersusTransactionTypeValidation = false;
}
// Do the checks that depend on Accounting Line information.
for (PurApAccountingLine accountingLine : item.getSourceAccountingLines()) {
// Because of ObjectCodeCurrent, we had to refresh this.
accountingLine.refreshReferenceObject(KFSPropertyConstants.OBJECT_CODE);
ObjectCode objectCode = accountingLine.getObjectCode();
if (ObjectUtils.isNotNull(objectCode)) {
String capitalOrExpense = objectCodeCapitalOrExpense(objectCode);
capitalOrExpenseSet.add(capitalOrExpense); // HashSets accumulate distinct values (and nulls) only.
valid &= validateAccountingLinesNotCapitalAndExpense(capitalOrExpenseSet, itemIdentifier, objectCode);
if (performObjectCodeVersusTransactionTypeValidation) {
// Do the checks involving capital asset transaction type.
if (capitalAssetTransactionType != null) {
valid &= validateObjectCodeVersusTransactionType(objectCode, capitalAssetTransactionType, itemIdentifier, quantityBased);
}
}
}
}
return valid;
}
/**
* Capital Asset validation: An item cannot have among its associated accounting lines both object codes that indicate it is a
* Capital Asset, and object codes that indicate that the item is not a Capital Asset. Whether an object code indicates that the
* item is a Capital Asset is determined by whether its level is among a specific set of levels that are deemed acceptable for
* such items.
*
* @param capitalOrExpenseSet A HashSet containing the distinct values of either "Capital" or "Expense" that have been added to
* it.
* @param warn A boolean which should be set to true if warnings are to be set on the calling document
* @param itemIdentifier A String identifying the item for error display
* @param objectCode An ObjectCode, for error display
* @return True if the given HashSet contains at most one of either "Capital" or "Expense"
*/
protected boolean validateAccountingLinesNotCapitalAndExpense(HashSet<String> capitalOrExpenseSet, String itemIdentifier, ObjectCode objectCode) {
boolean valid = true;
// If the set contains more than one distinct string, fail.
if (capitalOrExpenseSet.size() > 1) {
GlobalVariables.getMessageMap().putError(KFSConstants.FINANCIAL_OBJECT_LEVEL_CODE_PROPERTY_NAME, CabKeyConstants.ERROR_ITEM_CAPITAL_AND_EXPENSE, itemIdentifier, objectCode.getFinancialObjectCodeName());
valid &= false;
}
return valid;
}
protected boolean validateLevelCapitalAssetIndication(BigDecimal unitPrice, ObjectCode objectCode, String itemIdentifier) {
String capitalAssetPriceThresholdParam = this.getParameterService().getParameterValueAsString(AssetGlobal.class, CabParameterConstants.CapitalAsset.CAPITALIZATION_LIMIT_AMOUNT);
BigDecimal priceThreshold = null;
try {
priceThreshold = new BigDecimal(capitalAssetPriceThresholdParam);
} catch (NumberFormatException nfe) {
throw new RuntimeException("the parameter for CAPITAL_ASSET_OBJECT_LEVELS came was not able to be converted to a number.", nfe);
}
if (unitPrice.compareTo(priceThreshold) >= 0) {
List<String> possibleCAMSObjectLevels = new ArrayList<String>(this.getParameterService().getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, CabParameterConstants.CapitalAsset.POSSIBLE_CAPITAL_ASSET_OBJECT_LEVELS));
if (possibleCAMSObjectLevels.contains(objectCode.getFinancialObjectLevelCode())) {
String warning = configurationService.getPropertyValueAsString(CabKeyConstants.WARNING_ABOVE_THRESHOLD_SUGESTS_CAPITAL_ASSET_LEVEL);
warning = StringUtils.replace(warning, "{0}", itemIdentifier);
warning = StringUtils.replace(warning, "{1}", priceThreshold.toString());
KNSGlobalVariables.getMessageList().add(warning);
return false;
}
}
return true;
}
/**
* Capital Asset validation: If the item has a transaction type, check that the transaction type is acceptable for the object
* code sub-types of all the object codes on the associated accounting lines.
*
* @param objectCode
* @param capitalAssetTransactionType
* @param warn A boolean which should be set to true if warnings are to be set on the calling document
* @param itemIdentifier
* @return
*/
protected boolean validateObjectCodeVersusTransactionType(ObjectCode objectCode, CapitalAssetBuilderAssetTransactionType capitalAssetTransactionType, String itemIdentifier, boolean quantityBasedItem) {
boolean valid = true;
String[] objectCodeSubTypes = {};
String itemTypeStr = null;
String alternativeItemTypeStr = null;
String capitalAssetSubtypeRequiredText = null;
if (isCapitalAssetObjectCode(objectCode)) {
if (quantityBasedItem) {
String capitalAssetQuantitySubtypeRequiredText = capitalAssetTransactionType.getCapitalAssetQuantitySubtypeRequiredText();
itemTypeStr = PurapConstants.ITEM_TYPE_QTY;
alternativeItemTypeStr = PurapConstants.ITEM_TYPE_NO_QTY;
capitalAssetSubtypeRequiredText = capitalAssetQuantitySubtypeRequiredText;
if (capitalAssetQuantitySubtypeRequiredText != null) {
objectCodeSubTypes = StringUtils.split(capitalAssetQuantitySubtypeRequiredText, ";");
}
} else {
String capitalAssetNonquantitySubtypeRequiredText = capitalAssetTransactionType.getCapitalAssetNonquantitySubtypeRequiredText();
itemTypeStr = PurapConstants.ITEM_TYPE_NO_QTY;
alternativeItemTypeStr = PurapConstants.ITEM_TYPE_QTY;
capitalAssetSubtypeRequiredText = capitalAssetNonquantitySubtypeRequiredText;
if (capitalAssetNonquantitySubtypeRequiredText != null) {
objectCodeSubTypes = StringUtils.split(capitalAssetNonquantitySubtypeRequiredText, ";");
}
}
boolean found = false;
for (String subType : objectCodeSubTypes) {
if (StringUtils.equals(subType, objectCode.getFinancialObjectSubTypeCode())) {
found = true;
break;
}
}
if (!found) {
List<String> errorPath = GlobalVariables.getMessageMap().getErrorPath();
if (errorPath != null && errorPath.isEmpty()) {
String errorPathPrefix = KFSConstants.DOCUMENT_PROPERTY_NAME + "." + PurapPropertyConstants.ITEM;
GlobalVariables.getMessageMap().addToErrorPath(errorPathPrefix);
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_CAPITAL_ASSET_TRANSACTION_TYPE, CabKeyConstants.ERROR_ITEM_TRAN_TYPE_OBJECT_CODE_SUBTYPE, itemIdentifier, itemTypeStr, capitalAssetTransactionType.getCapitalAssetTransactionTypeDescription(), objectCode.getFinancialObjectCodeName(), capitalAssetSubtypeRequiredText, alternativeItemTypeStr);
GlobalVariables.getMessageMap().removeFromErrorPath(errorPathPrefix);
} else {
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_CAPITAL_ASSET_TRANSACTION_TYPE, CabKeyConstants.ERROR_ITEM_TRAN_TYPE_OBJECT_CODE_SUBTYPE, itemIdentifier, itemTypeStr, capitalAssetTransactionType.getCapitalAssetTransactionTypeDescription(), objectCode.getFinancialObjectCodeName(), capitalAssetSubtypeRequiredText, alternativeItemTypeStr);
}
valid &= false;
}
}
return valid;
}
/**
* Capital Asset validation: If the item has a transaction type, check that if the document specifies that recurring payments
* are to be made, that the transaction type is one that is appropriate for this situation, and that if the document does not
* specify that recurring payments are to be made, that the transaction type is one that is appropriate for that situation.
*
* @param capitalAssetTransactionType
* @param recurringPaymentType
* @param warn A boolean which should be set to true if warnings are to be set on the calling document
* @param itemIdentifier
* @return
*/
protected boolean validateCapitalAssetTransactionTypeVersusRecurrence(CapitalAssetBuilderAssetTransactionType capitalAssetTransactionType, String recurringPaymentTypeCode, String itemIdentifier) {
boolean valid = true;
// If there is a tran type ...
if ((capitalAssetTransactionType != null) && (capitalAssetTransactionType.getCapitalAssetTransactionTypeCode() != null)) {
String recurringTransactionTypeCodes = this.getParameterService().getParameterValueAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, CabParameterConstants.CapitalAsset.RECURRING_CAMS_TRAN_TYPES);
if (StringUtils.isNotEmpty(recurringPaymentTypeCode)) { // If there is a recurring payment type ...
if (!StringUtils.contains(recurringTransactionTypeCodes, capitalAssetTransactionType.getCapitalAssetTransactionTypeCode())) {
// There should be a recurring tran type code.
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_CAPITAL_ASSET_TRANSACTION_TYPE, CabKeyConstants.ERROR_ITEM_WRONG_TRAN_TYPE, itemIdentifier, capitalAssetTransactionType.getCapitalAssetTransactionTypeDescription(), CabConstants.ValidationStrings.RECURRING);
valid &= false;
}
} else { // If the payment type is not recurring ...
// There should not be a recurring transaction type code.
if (StringUtils.contains(recurringTransactionTypeCodes, capitalAssetTransactionType.getCapitalAssetTransactionTypeCode())) {
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_CAPITAL_ASSET_TRANSACTION_TYPE, CabKeyConstants.ERROR_ITEM_WRONG_TRAN_TYPE, itemIdentifier, capitalAssetTransactionType.getCapitalAssetTransactionTypeDescription(), CabConstants.ValidationStrings.NON_RECURRING);
valid &= false;
}
}
} else { // If there is no transaction type ...
if (StringUtils.isNotEmpty(recurringPaymentTypeCode)) { // If there is a recurring payment type ...
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_CAPITAL_ASSET_TRANSACTION_TYPE, CabKeyConstants.ERROR_ITEM_NO_TRAN_TYPE, itemIdentifier, CabConstants.ValidationStrings.RECURRING);
valid &= false;
} else { // If the payment type is not recurring ...
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_CAPITAL_ASSET_TRANSACTION_TYPE, CabKeyConstants.ERROR_ITEM_NO_TRAN_TYPE, itemIdentifier, CabConstants.ValidationStrings.NON_RECURRING);
valid &= false;
}
}
return valid;
}
/**
* Utility wrapping isCapitalAssetObjectCode for the use of processItemCapitalAssetValidation.
*
* @param oc An ObjectCode
* @return A String indicating that the given object code is either Capital or Expense
*/
protected String objectCodeCapitalOrExpense(ObjectCode oc) {
String capital = CabConstants.ValidationStrings.CAPITAL;
String expense = CabConstants.ValidationStrings.EXPENSE;
return (isCapitalAssetObjectCode(oc) ? capital : expense);
}
/**
* Predicate to determine whether the given object code is of a specified object sub type required for purap cams.
*
* @param oc An ObjectCode
* @return True if the ObjectSubType is the one designated for capital assets.
*/
protected boolean isCapitalAssetObjectCode(ObjectCode oc) {
String capitalAssetObjectSubType = this.getParameterService().getParameterValueAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, PurapParameterConstants.CapitalAsset.PURCHASING_OBJECT_SUB_TYPES);
return (StringUtils.containsIgnoreCase(capitalAssetObjectSubType, oc.getFinancialObjectSubTypeCode()) ? true : false);
}
/**
* Not documented
*
* @param capitalAssetSystems
* @return
*/
protected boolean validateCapitalAssetLocationAddressFieldsOneOrMultipleSystemType(List<CapitalAssetSystem> capitalAssetSystems) {
boolean valid = true;
boolean isMoving = false;
int systemCount = 0;
for (CapitalAssetSystem system : capitalAssetSystems) {
List<CapitalAssetLocation> capitalAssetLocations = system.getCapitalAssetLocations();
StringBuffer errorKey = new StringBuffer("document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_SYSTEMS + "[" + new Integer(systemCount++) + "].");
errorKey.append("capitalAssetLocations");
int locationCount = 0;
for (CapitalAssetLocation location : capitalAssetLocations) {
errorKey.append("[" + locationCount++ + "].");
AssetType assetType = getAssetType(system.getCapitalAssetTypeCode());
isMoving = ObjectUtils.isNull(assetType) ? false : assetType.isMovingIndicator();
boolean ignoreBuilding = ObjectUtils.isNull(assetType) ? false : assetType.isRequiredBuildingIndicator();
valid &= validateCapitalAssetLocationAddressFields(location, isMoving, ignoreBuilding, errorKey);
}
}
return valid;
}
/**
* Not Documented
*
* @param capitalAssetItems
* @return
*/
protected boolean validateCapitalAssetLocationAddressFieldsForIndividualSystemType(List<PurchasingCapitalAssetItem> capitalAssetItems) {
boolean valid = true;
boolean isMoving = false;
for (PurchasingCapitalAssetItem item : capitalAssetItems) {
CapitalAssetSystem system = item.getPurchasingCapitalAssetSystem();
List<CapitalAssetLocation> capitalAssetLocations = system.getCapitalAssetLocations();
StringBuffer errorKey = new StringBuffer("document." + PurapPropertyConstants.PURCHASING_CAPITAL_ASSET_ITEMS + "[" + new Integer(item.getPurchasingItem().getItemLineNumber().intValue() - 1) + "].");
errorKey.append("purchasingCapitalAssetSystem.capitalAssetLocations");
int i = 0;
for (CapitalAssetLocation location : capitalAssetLocations) {
errorKey.append("[" + i++ + "].");
AssetType assetType = getAssetType(system.getCapitalAssetTypeCode());
isMoving = ObjectUtils.isNull(assetType) ? false : assetType.isMovingIndicator();
boolean isRequiredBuilding = ObjectUtils.isNull(assetType) ? false : assetType.isRequiredBuildingIndicator();
valid &= validateCapitalAssetLocationAddressFields(location, isMoving, isRequiredBuilding, errorKey);
}
}
return valid;
}
/**
* Not documented
*
* @param location
* @param ignoreRoom Is used to identify if room number should be validated. If true then room is ignored in this validation.
* @param errorKey
* @return
*/
protected boolean validateCapitalAssetLocationAddressFields(CapitalAssetLocation location, boolean isMoving, boolean isRequiredBuilding, StringBuffer errorKey) {
boolean valid = true;
if (!location.isOffCampusIndicator()) {
if (StringUtils.isBlank(location.getCampusCode())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_CAMPUS);
valid &= false;
}
}
if (isMoving) {
if (!location.isOffCampusIndicator()) {
// bulding and room required
if (StringUtils.isBlank(location.getBuildingRoomNumber())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_ROOM);
valid &= false;
}
if (StringUtils.isBlank(location.getBuildingCode())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_BUILDING);
valid &= false;
}
}
valid &= validateCapitalAssetAddressFields(location, errorKey);
} else {
// no room allowed
if (!StringUtils.isBlank(location.getBuildingRoomNumber())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), CamsKeyConstants.AssetLocation.ERROR_ASSET_LOCATION_ROOM_NUMBER_NONMOVEABLE, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_ROOM);
valid &= false;
}
if (isRequiredBuilding) {
// building required
if (!location.isOffCampusIndicator()) {
if (StringUtils.isBlank(location.getBuildingCode())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_BUILDING);
valid &= false;
}
}
valid &= validateCapitalAssetAddressFields(location, errorKey);
} else {
// no building allowed
if (!StringUtils.isBlank(location.getBuildingCode())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), CamsKeyConstants.AssetLocation.ERROR_ASSET_LOCATION_BUILDING_NONMOVEABLE, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_BUILDING);
valid &= false;
}
}
}
return valid;
}
protected boolean validateCapitalAssetAddressFields(CapitalAssetLocation location, StringBuffer errorKey) {
boolean valid = true;
if (StringUtils.isBlank(location.getCapitalAssetLine1Address())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_ADDRESS_LINE1);
valid &= false;
}
if (StringUtils.isBlank(location.getCapitalAssetCityName())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_CITY);
valid &= false;
}
if (StringUtils.isBlank(location.getCapitalAssetCountryCode())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_COUNTRY);
valid &= false;
} else if (location.getCapitalAssetCountryCode().equals(KFSConstants.COUNTRY_CODE_UNITED_STATES)) {
if (StringUtils.isBlank(location.getCapitalAssetStateCode())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_STATE);
valid &= false;
}
if (StringUtils.isBlank(location.getCapitalAssetPostalCode())) {
GlobalVariables.getMessageMap().putError(errorKey.toString(), KFSKeyConstants.ERROR_REQUIRED, PurapPropertyConstants.CAPITAL_ASSET_LOCATION_POSTAL_CODE);
valid &= false;
}
}
return valid;
}
protected boolean validateAccountsPayableItem(AccountsPayableItem apItem) {
boolean valid = true;
valid &= validatePurapItemCapitalAsset(apItem, (AssetTransactionType) apItem.getCapitalAssetTransactionType());
return valid;
}
// end of methods for purap
/**
* @param accountingDocument and capitalAssetInformation
* @return True if the FinancialProcessingData is valid.
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#validateFinancialProcessingData(org.kuali.kfs.sys.document.AccountingDocument,
* org.kuali.kfs.fp.businessobject.CapitalAssetInformation)
*/
@Override
public boolean validateFinancialProcessingData(AccountingDocument accountingDocument, CapitalAssetInformation capitalAssetInformation, int index) {
boolean valid = true;
// Check if we need to collect cams data
AccountCapitalObjectCode accountCapitalObjectCode = this.getCapitalAssetObjectSubTypeLinesFlag(accountingDocument);
boolean isNewAssetBlank = isNewAssetBlank(capitalAssetInformation);
boolean isUpdateAssetBlank = isUpdateAssetBlank(capitalAssetInformation);
// validate asset information provided by the user are allowed
valid = accountCapitalObjectCode.validateAssetInfoAllowed(accountingDocument, isNewAssetBlank, isUpdateAssetBlank);
if (valid) {
// non-capital object code, no further check needed for asset
if (AccountCapitalObjectCode.BOTH_NONCAP.equals(accountCapitalObjectCode)) {
return true;
} else {
if (!isUpdateAssetBlank) {
// Validate update Asset information
valid &= validateUpdateCapitalAssetField(capitalAssetInformation, accountingDocument, index);
} else {
// Validate New Asset information
valid &= checkNewCapitalAssetFieldsExist(capitalAssetInformation, accountingDocument, index);
if (valid) {
valid = validateNewCapitalAssetFields(capitalAssetInformation, index, accountingDocument);
}
}
}
}
return valid;
}
/**
* Get the Capital Asset Object Code from the accounting lines.
*
* @param accountingDocument
* @return getCapitalAssetObjectSubTypeLinesFlag = AccountCapitalObjectCode.NON_CAPITAL ==> no assetObjectSubType code
* AccountCapitalObjectCode.FROM_CAPITAL ==> assetObjectSubType code on source lines
* AccountCapitalObjectCode.FROM_CAPITAL ==> assetObjectSubType code on target lines
* AccountCapitalObjectCode.BOTH_CAPITAL ==> assetObjectSubType code on both source and target lines
*/
protected AccountCapitalObjectCode getCapitalAssetObjectSubTypeLinesFlag(AccountingDocument accountingDocument) {
List<String> financialProcessingCapitalObjectSubTypes = new ArrayList<String>(this.getParameterService().getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, CabParameterConstants.CapitalAsset.FINANCIAL_PROCESSING_CAPITAL_OBJECT_SUB_TYPES));
AccountCapitalObjectCode capitalAssetObjectSubTypeLinesFlag = AccountCapitalObjectCode.BOTH_NONCAP;
// Check if SourceAccountingLine has objectSub type code
List<SourceAccountingLine> sAccountingLines = accountingDocument.getSourceAccountingLines();
for (SourceAccountingLine sourceAccountingLine : sAccountingLines) {
ObjectCode objectCode = sourceAccountingLine.getObjectCode();
if (ObjectUtils.isNotNull(objectCode)) {
String objectSubTypeCode = objectCode.getFinancialObjectSubTypeCode();
if (financialProcessingCapitalObjectSubTypes.contains(objectSubTypeCode)) {
capitalAssetObjectSubTypeLinesFlag = AccountCapitalObjectCode.FROM_CAPITAL_TO_NONCAP;
break;
}
}
}
// Check if TargetAccountingLine has objectSub type code
List<TargetAccountingLine> tAccountingLines = accountingDocument.getTargetAccountingLines();
for (TargetAccountingLine targetAccountingLine : tAccountingLines) {
ObjectCode objectCode = targetAccountingLine.getObjectCode();
if (ObjectUtils.isNotNull(objectCode)) {
String objectSubTypeCode = objectCode.getFinancialObjectSubTypeCode();
if (financialProcessingCapitalObjectSubTypes.contains(objectSubTypeCode)) {
capitalAssetObjectSubTypeLinesFlag = capitalAssetObjectSubTypeLinesFlag == AccountCapitalObjectCode.FROM_CAPITAL_TO_NONCAP ? AccountCapitalObjectCode.BOTH_CAPITAL : AccountCapitalObjectCode.FROM_NONCAP_TO_CAPITAL;
break;
}
}
}
return capitalAssetObjectSubTypeLinesFlag;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#hasCapitalAssetObjectSubType(org.kuali.kfs.sys.document.AccountingDocument)
*/
@Override
public boolean hasCapitalAssetObjectSubType(AccountingDocument accountingDocument) {
final AccountCapitalObjectCode accountCapitalObjectCode = getCapitalAssetObjectSubTypeLinesFlag(accountingDocument);
return accountCapitalObjectCode != null && !accountCapitalObjectCode.equals(AccountCapitalObjectCode.BOTH_NONCAP);
}
/**
* To check if data exists on create new asset
*
* @param capitalAssetInformation
* @return boolean false if the new asset is not blank
*/
protected boolean isNewAssetBlank(CapitalAssetInformation capitalAssetInformation) {
boolean isBlank = true;
boolean createAsset = (StringUtils.equalsIgnoreCase(capitalAssetInformation.getCapitalAssetActionIndicator(), KFSConstants.CapitalAssets.CAPITAL_ASSET_CREATE_ACTION_INDICATOR) ? true : false);
if (createAsset && (ObjectUtils.isNotNull(capitalAssetInformation.getCapitalAssetTypeCode()) || ObjectUtils.isNotNull(capitalAssetInformation.getVendorName()) || ObjectUtils.isNotNull(capitalAssetInformation.getCapitalAssetQuantity()) || ObjectUtils.isNotNull(capitalAssetInformation.getCapitalAssetManufacturerName()) || ObjectUtils.isNotNull(capitalAssetInformation.getCapitalAssetManufacturerModelNumber()) || ObjectUtils.isNotNull(capitalAssetInformation.getCapitalAssetDescription()))) {
isBlank = false;
}
return isBlank;
}
/**
* To check if data exists on update asset
*
* @param capitalAssetInformation
* @return boolean false if the update asset is not blank
*/
protected boolean isUpdateAssetBlank(CapitalAssetInformation capitalAssetInformation) {
boolean isBlank = true;
boolean updateAsset = (StringUtils.equalsIgnoreCase(capitalAssetInformation.getCapitalAssetActionIndicator(), KFSConstants.CapitalAssets.CAPITAL_ASSET_MODIFY_ACTION_INDICATOR) ? true : false);
if (updateAsset && ObjectUtils.isNotNull(capitalAssetInformation.getCapitalAssetNumber())) {
isBlank = false;
}
return isBlank;
}
/**
* To validate if the asset is active
*
* @param capitalAssetManagementAsset the asset to be validated
* @return boolean false if the asset is not active
*/
protected boolean validateUpdateCapitalAssetField(CapitalAssetInformation capitalAssetInformation, AccountingDocument accountingDocument, int index) {
boolean valid = true;
Map<String, String> params = new HashMap<String, String>();
params.put(KFSPropertyConstants.CAPITAL_ASSET_NUMBER, capitalAssetInformation.getCapitalAssetNumber().toString());
Asset asset = businessObjectService.findByPrimaryKey(Asset.class, params);
List<Long> assetNumbers = new ArrayList<Long>();
assetNumbers.add(capitalAssetInformation.getCapitalAssetNumber());
MessageMap errors = GlobalVariables.getMessageMap();
errors.removeFromErrorPath(KFSPropertyConstants.CAPITAL_ASSET_INFORMATION + "[" + index + "].");
errors.removeFromErrorPath(capitalAssetInformation.getCapitalAssetActionIndicator().equalsIgnoreCase(KFSConstants.CapitalAssets.CAPITAL_ASSET_CREATE_ACTION_INDICATOR) ? KFSPropertyConstants.CAPITAL_ASSET_INFORMATION : KFSPropertyConstants.CAPITAL_ASSET_MODIFY_INFORMATION);
errors.removeFromErrorPath(KFSPropertyConstants.DOCUMENT);
String errorPathPrefix = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION + "[" + index + "]." + KFSPropertyConstants.CAPITAL_ASSET_NUMBER;
if (ObjectUtils.isNull(asset)) {
valid = false;
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_NUMBER);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix, KFSKeyConstants.ERROR_EXISTENCE, label);
} else if (!(this.getAssetService().isCapitalAsset(asset) && !this.getAssetService().isAssetRetired(asset))) {
// check asset status must be capital asset active.
valid = false;
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix, CabKeyConstants.CapitalAssetInformation.ERROR_ASSET_ACTIVE_CAPITAL_ASSET_REQUIRED);
} else {
String documentNumber = accountingDocument.getDocumentNumber();
String documentType = getDocumentTypeName(accountingDocument);
if (getCapitalAssetManagementModuleService().isFpDocumentEligibleForAssetLock(accountingDocument, documentType) && getCapitalAssetManagementModuleService().isAssetLocked(assetNumbers, documentType, documentNumber)) {
valid = false;
}
}
return valid;
}
/**
* Check if all required fields exist on new asset
*
* @param capitalAssetInformation the fields of add asset to be checked
* @return boolean false if a required field is missing
*/
protected boolean checkNewCapitalAssetFieldsExist(CapitalAssetInformation capitalAssetInformation, AccountingDocument accountingDocument, int caLineIndex) {
boolean valid = true;
if (StringUtils.isBlank(capitalAssetInformation.getCapitalAssetTypeCode())) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_TYPE_CODE);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_TYPE_CODE, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
if (capitalAssetInformation.getCapitalAssetQuantity() == null || capitalAssetInformation.getCapitalAssetQuantity() <= 0) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_QUANTITY);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_QUANTITY, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
//VENDOR_IS_REQUIRED_FOR_NON_MOVEABLE_ASSET parameter determines if we need to check
//vendor name entered.
String vendorNameRequired = getParameterService().getParameterValueAsString(Asset.class, CabParameterConstants.CapitalAsset.VENDOR_REQUIRED_FOR_NON_MOVEABLE_ASSET_IND);
if ("Y".equalsIgnoreCase(vendorNameRequired)) {
// skip vendor name required validation for procurement card document
if (!(accountingDocument instanceof ProcurementCardDocument) && StringUtils.isBlank(capitalAssetInformation.getVendorName())) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.VENDOR_NAME);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.VENDOR_NAME, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
}
//MANUFACTURER_IS_REQUIRED_FOR_NON_MOVEABLE_ASSET parameter determines if we need to check
//vendor name entered.
String manufacturerNameRequired = getParameterService().getParameterValueAsString(Asset.class, CabParameterConstants.CapitalAsset.MANUFACTURER_REQUIRED_FOR_NON_MOVEABLE_ASSET_IND);
if ("Y".equalsIgnoreCase(manufacturerNameRequired)) {
if (StringUtils.isBlank(capitalAssetInformation.getCapitalAssetManufacturerName())) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_MANUFACTURE_NAME);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_MANUFACTURE_NAME, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
}
if (StringUtils.isBlank(capitalAssetInformation.getCapitalAssetDescription())) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, CamsPropertyConstants.Asset.CAPITAL_ASSET_DESCRIPTION);
GlobalVariables.getMessageMap().putError(CamsPropertyConstants.Asset.CAPITAL_ASSET_DESCRIPTION, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
int index = 0;
List<CapitalAssetInformationDetail> capitalAssetInformationDetails = capitalAssetInformation.getCapitalAssetInformationDetails();
for (CapitalAssetInformationDetail dtl : capitalAssetInformationDetails) {
String errorPathPrefix = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION + "[" + caLineIndex + "]." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION_DETAILS;
if (StringUtils.isBlank(dtl.getCampusCode())) {
String label = this.getDataDictionaryService().getAttributeLabel(Campus.class, KFSPropertyConstants.CAMPUS_CODE);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.CAMPUS_CODE, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
if (StringUtils.isBlank(dtl.getBuildingCode())) {
String label = this.getDataDictionaryService().getAttributeLabel(Building.class, KFSPropertyConstants.BUILDING_CODE);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_CODE, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
// Room is not required for non-moveable
AssetType assetType = getAssetType(capitalAssetInformation.getCapitalAssetTypeCode());
if (ObjectUtils.isNull(assetType) || assetType.isMovingIndicator()) {
if (StringUtils.isBlank(dtl.getBuildingRoomNumber())) {
String label = this.getDataDictionaryService().getAttributeLabel(Room.class, KFSPropertyConstants.BUILDING_ROOM_NUMBER);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_ROOM_NUMBER, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
}
// Room number not allowed for non-moveable assets
if (ObjectUtils.isNotNull(assetType) && !assetType.isMovingIndicator()) {
if (StringUtils.isNotBlank(dtl.getBuildingRoomNumber())) {
String label = this.getDataDictionaryService().getAttributeLabel(Room.class, KFSPropertyConstants.BUILDING_ROOM_NUMBER);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_ASSET_LOCATION_ROOM_NUMBER_NONMOVEABLE, label);
valid = false;
}
}
index++;
}
return valid;
}
/**
* Check if all required fields exist on new asset
*
* @param capitalAssetInformation the fields of add asset to be checked
* @return boolean false if a required field is missing
* <p/>
* Deprecated - the method signature changed
*/
@Deprecated
protected boolean checkNewCapitalAssetFieldsExist(CapitalAssetInformation capitalAssetInformation, AccountingDocument accountingDocument) {
boolean valid = true;
if (StringUtils.isBlank(capitalAssetInformation.getCapitalAssetTypeCode())) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_TYPE_CODE);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_TYPE_CODE, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
if (capitalAssetInformation.getCapitalAssetQuantity() == null || capitalAssetInformation.getCapitalAssetQuantity() <= 0) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_QUANTITY);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_QUANTITY, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
//VENDOR_IS_REQUIRED_FOR_NON_MOVEABLE_ASSET parameter determines if we need to check
//vendor name entered.
String vendorNameRequired = getParameterService().getParameterValueAsString(Asset.class, CabParameterConstants.CapitalAsset.VENDOR_REQUIRED_FOR_NON_MOVEABLE_ASSET_IND);
if ("Y".equalsIgnoreCase(vendorNameRequired)) {
// skip vendor name required validation for procurement card document
if (!(accountingDocument instanceof ProcurementCardDocument) && StringUtils.isBlank(capitalAssetInformation.getVendorName())) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.VENDOR_NAME);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.VENDOR_NAME, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
}
//MANUFACTURER_IS_REQUIRED_FOR_NON_MOVEABLE_ASSET parameter determines if we need to check
//vendor name entered.
String manufacturerNameRequired = getParameterService().getParameterValueAsString(Asset.class, CabParameterConstants.CapitalAsset.MANUFACTURER_REQUIRED_FOR_NON_MOVEABLE_ASSET_IND);
if ("Y".equalsIgnoreCase(manufacturerNameRequired)) {
if (StringUtils.isBlank(capitalAssetInformation.getCapitalAssetManufacturerName())) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_MANUFACTURE_NAME);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_MANUFACTURE_NAME, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
}
if (StringUtils.isBlank(capitalAssetInformation.getCapitalAssetDescription())) {
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, CamsPropertyConstants.Asset.CAPITAL_ASSET_DESCRIPTION);
GlobalVariables.getMessageMap().putError(CamsPropertyConstants.Asset.CAPITAL_ASSET_DESCRIPTION, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
int index = 0;
List<CapitalAssetInformationDetail> capitalAssetInformationDetails = capitalAssetInformation.getCapitalAssetInformationDetails();
for (CapitalAssetInformationDetail dtl : capitalAssetInformationDetails) {
String errorPathPrefix = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION + "." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION_DETAILS;
if (StringUtils.isBlank(dtl.getCampusCode())) {
String label = this.getDataDictionaryService().getAttributeLabel(Campus.class, KFSPropertyConstants.CAMPUS_CODE);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.CAMPUS_CODE, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
if (StringUtils.isBlank(dtl.getBuildingCode())) {
String label = this.getDataDictionaryService().getAttributeLabel(Building.class, KFSPropertyConstants.BUILDING_CODE);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_CODE, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
// Room is not required for non-moveable
AssetType assetType = getAssetType(capitalAssetInformation.getCapitalAssetTypeCode());
if (ObjectUtils.isNull(assetType) || assetType.isMovingIndicator()) {
if (StringUtils.isBlank(dtl.getBuildingRoomNumber())) {
String label = this.getDataDictionaryService().getAttributeLabel(Room.class, KFSPropertyConstants.BUILDING_ROOM_NUMBER);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_ROOM_NUMBER, KFSKeyConstants.ERROR_REQUIRED, label);
valid = false;
}
}
// Room number not allowed for non-moveable assets
if (ObjectUtils.isNotNull(assetType) && !assetType.isMovingIndicator()) {
if (StringUtils.isNotBlank(dtl.getBuildingRoomNumber())) {
String label = this.getDataDictionaryService().getAttributeLabel(Room.class, KFSPropertyConstants.BUILDING_ROOM_NUMBER);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_ASSET_LOCATION_ROOM_NUMBER_NONMOVEABLE, label);
valid = false;
}
}
index++;
}
return valid;
}
/**
* To validate new asset information
*
* @param capitalAssetInformation the information of add asset to be validated
* @param index index of the capital asset line
* @return boolean false if data is incorrect
*/
protected boolean validateNewCapitalAssetFields(CapitalAssetInformation capitalAssetInformation, int index, AccountingDocument accountingDocument) {
boolean valid = true;
if (!isAssetTypeExisting(capitalAssetInformation.getCapitalAssetTypeCode().toString())) {
valid = false;
String label = this.getDataDictionaryService().getAttributeLabel(CapitalAssetInformation.class, KFSPropertyConstants.CAPITAL_ASSET_TYPE_CODE);
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_TYPE_CODE, KFSKeyConstants.ERROR_EXISTENCE, label);
}
valid &= validateTotalNumberOfAssetTagLines(capitalAssetInformation);
if (valid) {
valid &= validateAssetTagLocationLines(capitalAssetInformation, index, accountingDocument);
}
return valid;
}
/**
* validates only the tag numbers because we need to check all the tags within
* the document for duplicates.
*
* @param accountingDocument
* @return true if duplicate tags else return false.
* @see
*/
@Override
public boolean validateAssetTags(AccountingDocument accountingDocument) {
boolean valid = true;
List<TagRecord> allTags = new ArrayList<TagRecord>();
CapitalAssetEditable capitalAssetEditable = (CapitalAssetEditable) accountingDocument;
List<CapitalAssetInformation> capitalAssets = capitalAssetEditable.getCapitalAssetInformation();
int indexCapital = 0;
for (CapitalAssetInformation capitalAsset : capitalAssets) {
if (KFSConstants.CapitalAssets.CAPITAL_ASSET_CREATE_ACTION_INDICATOR.equals(capitalAsset.getCapitalAssetActionIndicator())) {
List<CapitalAssetInformationDetail> capitalAssetInformationDetails = capitalAsset.getCapitalAssetInformationDetails();
int index = 0;
for (CapitalAssetInformationDetail dtl : capitalAssetInformationDetails) {
dtl.refreshReferenceObject("building");
//if building is inactiv then validation fails....
if (ObjectUtils.isNotNull(dtl.getBuilding()) && !dtl.getBuilding().isActive()) {
String errorPathPrefix = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION + "[" + indexCapital + "]." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION_DETAILS;
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_CODE, KFSKeyConstants.ERROR_DOCUMENT_CAPITAL_ASSET_DETAIL_INACTIVE_BUILDING_NOT_ALLOWED, dtl.getBuildingCode());
valid &= false;
}
dtl.refreshReferenceObject("room");
//if room is inactiv then validation fails....
if (ObjectUtils.isNotNull(dtl.getRoom()) && !dtl.getRoom().isActive()) {
String errorPathPrefix = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION + "[" + indexCapital + "]." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION_DETAILS;
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_ROOM_NUMBER, KFSKeyConstants.ERROR_DOCUMENT_CAPITAL_ASSET_DETAIL_INACTIVE_ROOM_NOT_ALLOWED, dtl.getBuildingRoomNumber());
valid &= false;
}
index++;
businessObjectDictionaryService.performForceUppercase(dtl);
if (StringUtils.isNotBlank(dtl.getCapitalAssetTagNumber()) && !dtl.getCapitalAssetTagNumber().equalsIgnoreCase(CamsConstants.Asset.NON_TAGGABLE_ASSET)) {
allTags.add(new TagRecord(dtl.getCapitalAssetTagNumber(), capitalAsset.getCapitalAssetLineNumber(), dtl.getCapitalAssetLineNumber(), dtl.getItemLineNumber()));
}
}
}
indexCapital++;
}
for (TagRecord tagRecord : allTags) {
if (isTagDuplicated(allTags, tagRecord)) {
tagRecord.setDuplicate(true);
valid &= false;
}
}
for (TagRecord tagRecord : allTags) {
if (tagRecord.isDuplicate()) {
int indexAsset = 0;
for (CapitalAssetInformation capitalAsset : capitalAssets) {
if (KFSConstants.CapitalAssets.CAPITAL_ASSET_CREATE_ACTION_INDICATOR.equals(capitalAsset.getCapitalAssetActionIndicator())) {
List<CapitalAssetInformationDetail> capitalAssetInformationDetails = capitalAsset.getCapitalAssetInformationDetails();
int index = 0;
for (CapitalAssetInformationDetail dtl : capitalAssetInformationDetails) {
if (dtl.getCapitalAssetTagNumber().equals(tagRecord.getTagNumber())) {
String errorPathPrefix = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION + "[" + indexAsset + "]." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION_DETAILS;
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.CAPITAL_ASSET_TAG_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_CAMPUS_TAG_NUMBER_DUPLICATE, tagRecord.getTagNumber());
}
index++;
}
}
indexAsset++;
}
}
}
return valid;
}
/**
* checks the tag records for a given asset number and sets duplicate flag to
* true if found.
*
* @param allTags
* @param tagRecord
* @return true if duplicate else false
*/
protected boolean isTagDuplicated(List<TagRecord> allTags, TagRecord tagRecord) {
boolean duplicate = false;
if (!this.getAssetService().findActiveAssetsMatchingTagNumber(tagRecord.getTagNumber()).isEmpty()) {
// Tag number is already in use
return true;
}
int duplicateCount = 0;
for (TagRecord checkTagRecord : allTags) {
if (checkTagRecord.getTagNumber().equals(tagRecord.getTagNumber())) {
//found duplicate...
duplicateCount++;
}
}
if (duplicateCount > 1) {
tagRecord.setDuplicate(true);
return true;
}
return duplicate;
}
/**
* public class to hold the the records representing the capital asset
* detail lines containing tag information
*/
public final class TagRecord {
protected String tagNumber;
protected int assetLineNumber;
protected int assetDetailLineNumber;
protected int assetItemLineNumber;
protected boolean duplicate;
public TagRecord(String tagNumber, int assetLineNumber, int assetDetailLineNumber, int itemLineNumber) {
this.tagNumber = tagNumber;
this.assetLineNumber = assetLineNumber;
this.assetDetailLineNumber = assetDetailLineNumber;
this.assetItemLineNumber = itemLineNumber;
this.duplicate = false;
}
/**
* Gets the tagNumber attribute.
*
* @return Returns the tagNumber
*/
public String getTagNumber() {
return tagNumber;
}
/**
* Gets the assetLineNumber attribute.
*
* @return Returns the assetLineNumber
*/
public int getAssetLineNumber() {
return assetLineNumber;
}
/**
* Gets the assetDetailLineNumber attribute.
*
* @return Returns the assetDetailLineNumber
*/
public int getAssetDetailLineNumber() {
return assetDetailLineNumber;
}
/**
* Sets the tagNumber attribute.
*
* @param tagNumber The tagNumber to set.
*/
public void setTagNumber(String tagNumber) {
this.tagNumber = tagNumber;
}
/**
* Sets the assetLineNumeber attribute.
*
* @param assetLineNumber The assetLineNumber to set.
*/
public void setAssetLineNumber(int assetLineNumber) {
this.assetLineNumber = assetLineNumber;
}
/**
* Sets the assetDetailLineNumber attribute.
*
* @param assetDetailLineNumber The assetDetailLineNumber to set.
*/
public void setAssetDetailLineNumber(int assetDetailLineNumber) {
this.assetDetailLineNumber = assetDetailLineNumber;
}
/**
* Gets the assetItemLineNumber attribute.
*
* @return Returns the assetItemLineNumber
*/
public int getAssetItemLineNumber() {
return assetItemLineNumber;
}
/**
* Sets the assetItemLineNumber attribute.
*
* @param assetItemLineNumber The assetItemLineNumber to set.
*/
public void setAssetItemLineNumber(int assetItemLineNumber) {
this.assetItemLineNumber = assetItemLineNumber;
}
/**
* Gets the duplicate attribute.
*
* @return Returns the duplicate
*/
public boolean isDuplicate() {
return duplicate;
}
/**
* Sets the duplicate attribute.
*
* @param duplicate The duplicate to set.
*/
public void setDuplicate(boolean duplicate) {
this.duplicate = duplicate;
}
}
/**
* validates asset tag location lines for existence of any duplicate tag/location details.
* Collects all the detail lines for all the capital assets and then checks if there
* are any duplicates.
*
* @param capitalAssetInformation
* @param capitalAssets
* @param capitalAssetIndex index of the capital asset line
* @return true if duplicate else false
*/
protected boolean validateAssetTagLocationLines(CapitalAssetInformation capitalAssetInformation, int capitalAssetIndex, AccountingDocument accountingDocument) {
boolean valid = true;
CapitalAssetEditable capitalAssetEditable = (CapitalAssetEditable) accountingDocument;
List<CapitalAssetInformation> capitalAssets = capitalAssetEditable.getCapitalAssetInformation();
List<CapitalAssetInformationDetail> capitalAssetInformationDetails = capitalAssetInformation.getCapitalAssetInformationDetails();
int index = 0;
for (CapitalAssetInformationDetail dtl : capitalAssetInformationDetails) {
// We have to explicitly call this DD service to upper case each field. This may not be the best place and maybe form
// populate is a better place but we CAMS team don't own FP document. This is the best we can do for now.
businessObjectDictionaryService.performForceUppercase(dtl);
String errorPathPrefix = KFSPropertyConstants.DOCUMENT + "." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION + "[" + capitalAssetIndex + "]." + KFSPropertyConstants.CAPITAL_ASSET_INFORMATION_DETAILS;
Campus campus = campusService.getCampus(dtl.getCampusCode());
if (ObjectUtils.isNull(campus)) {
valid = false;
String label = this.getDataDictionaryService().getAttributeLabel(Campus.class, KFSPropertyConstants.CAMPUS_CODE);
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.CAMPUS_CODE, KFSKeyConstants.ERROR_EXISTENCE, label);
}
Map<String, String> params;
params = new HashMap<String, String>();
params.put(KFSPropertyConstants.CAMPUS_CODE, dtl.getCampusCode());
params.put(KFSPropertyConstants.BUILDING_CODE, dtl.getBuildingCode());
Building building = businessObjectService.findByPrimaryKey(Building.class, params);
if (ObjectUtils.isNull(building)) {
valid = false;
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_CODE, CamsKeyConstants.AssetLocationGlobal.ERROR_INVALID_BUILDING_CODE, dtl.getBuildingCode(), dtl.getCampusCode());
}
params = new HashMap<String, String>();
params.put(KFSPropertyConstants.CAMPUS_CODE, dtl.getCampusCode());
params.put(KFSPropertyConstants.BUILDING_CODE, dtl.getBuildingCode());
params.put(KFSPropertyConstants.BUILDING_ROOM_NUMBER, dtl.getBuildingRoomNumber());
Room room = businessObjectService.findByPrimaryKey(Room.class, params);
AssetType assetType = getAssetType(capitalAssetInformation.getCapitalAssetTypeCode());
if (ObjectUtils.isNull(room) && (ObjectUtils.isNull(assetType) || assetType.isMovingIndicator())) {
valid = false;
GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(errorPathPrefix + "[" + index + "]" + "." + KFSPropertyConstants.BUILDING_ROOM_NUMBER, CamsKeyConstants.AssetLocationGlobal.ERROR_INVALID_ROOM_NUMBER, dtl.getBuildingRoomNumber(), dtl.getBuildingCode(), dtl.getCampusCode());
}
index++;
}
return valid;
}
/**
* Check assetTypeCode existence.
*
* @param assetTypeCode
* @return
*/
@Override
public boolean isAssetTypeExisting(String assetTypeCode) {
AssetType assetType = getAssetType(assetTypeCode);
return ObjectUtils.isNotNull(assetType);
}
/**
* Retrieve the Asset type from the provided assetType Code
*
* @param assetTypeCode
* @return {@link AssetType}
*/
protected AssetType getAssetType(String assetTypeCode) {
Map<String, String> params = new HashMap<String, String>();
params.put(KFSPropertyConstants.CAPITAL_ASSET_TYPE_CODE, assetTypeCode);
AssetType assetType = businessObjectService.findByPrimaryKey(AssetType.class, params);
return assetType;
}
/**
* Validate asset quantity the user entered matching the number of asset tag lines.
*
* @param capitalAssetInformation
* @return
*/
protected boolean validateTotalNumberOfAssetTagLines(CapitalAssetInformation capitalAssetInformation) {
boolean valid = true;
Integer userInputAssetQuantity = capitalAssetInformation.getCapitalAssetQuantity();
if (userInputAssetQuantity != null && (ObjectUtils.isNull(capitalAssetInformation.getCapitalAssetInformationDetails()) || capitalAssetInformation.getCapitalAssetInformationDetails().isEmpty())) {
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_QUANTITY, CabKeyConstants.CapitalAssetInformation.ERROR_ASSET_TAG_LINE_REQUIRED);
valid = false;
} else if (userInputAssetQuantity != null && userInputAssetQuantity.intValue() != capitalAssetInformation.getCapitalAssetInformationDetails().size()) {
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.CAPITAL_ASSET_QUANTITY, CabKeyConstants.CapitalAssetInformation.ERROR_ASSET_QUANTITY_NOT_MATCHING_TAG_LINES);
valid = false;
}
return valid;
}
/**
* To check if the tag number is duplicate or in use
*
* @param capitalAssetInformation, capitalAssetInformationDetail
* @return boolean false if data is duplicate or in use
*/
protected boolean isTagNumberDuplicate(List<CapitalAssetInformationDetail> capitalAssetInformationDetails, CapitalAssetInformationDetail dtl) {
boolean duplicateTag = false;
int tagCounter = 0;
if (!this.getAssetService().findActiveAssetsMatchingTagNumber(dtl.getCapitalAssetTagNumber()).isEmpty()) {
// Tag number is already in use
duplicateTag = true;
} else {
for (CapitalAssetInformationDetail capitalAssetInfoDetl : capitalAssetInformationDetails) {
if (capitalAssetInfoDetl.getCapitalAssetTagNumber().equalsIgnoreCase(dtl.getCapitalAssetTagNumber().toString())) {
tagCounter++;
}
}
if (tagCounter > 1) {
// Tag number already exists in the collection
duplicateTag = true;
}
}
return duplicateTag;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#notifyRouteStatusChange(java.lang.String,
* java.lang.String)
*/
@Override
public void notifyRouteStatusChange(DocumentHeader documentHeader) {
WorkflowDocument workflowDocument = documentHeader.getWorkflowDocument();
String documentNumber = documentHeader.getDocumentNumber();
String documentType = workflowDocument.getDocumentTypeName();
if (workflowDocument.isCanceled() || workflowDocument.isDisapproved()) {
// release CAB line items
activateCabPOLines(documentNumber);
activateCabGlLines(documentNumber);
}
if (workflowDocument.isProcessed()) {
// update CAB GL lines if fully processed
updatePOLinesStatusAsProcessed(documentNumber);
updateGlLinesStatusAsProcessed(documentNumber);
// report asset numbers to PO
Integer poId = getPurchaseOrderIdentifier(documentNumber);
if (poId != null) {
List<Long> assetNumbers = null;
if (DocumentTypeName.ASSET_ADD_GLOBAL.equalsIgnoreCase(documentType)) {
assetNumbers = getAssetNumbersFromAssetGlobal(documentNumber);
} else if (DocumentTypeName.ASSET_PAYMENT.equalsIgnoreCase(documentType)) {
assetNumbers = getAssetNumbersFromAssetPayment(documentNumber);
}
if (!assetNumbers.isEmpty()) {
String noteText = buildNoteTextForPurApDoc(documentType, assetNumbers);
purchasingAccountsPayableModuleService.addAssignedAssetNumbers(poId, workflowDocument.getInitiatorPrincipalId(), noteText);
}
}
}
}
/**
* update cab non-PO lines status code for item/account/glEntry to 'P' as fully processed when possible
*
* @param documentNumber
*/
protected void updateGlLinesStatusAsProcessed(String documentNumber) {
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CabPropertyConstants.PurchasingAccountsPayableItemAsset.CAMS_DOCUMENT_NUMBER, documentNumber);
Collection<GeneralLedgerEntryAsset> matchingGlAssets = businessObjectService.findMatching(GeneralLedgerEntryAsset.class, fieldValues);
if (matchingGlAssets != null && !matchingGlAssets.isEmpty()) {
for (GeneralLedgerEntryAsset generalLedgerEntryAsset : matchingGlAssets) {
GeneralLedgerEntry generalLedgerEntry = generalLedgerEntryAsset.getGeneralLedgerEntry();
// update gl status as processed
if (generalLedgerEntry.getTransactionLedgerEntryAmount().compareTo(generalLedgerEntry.getTransactionLedgerSubmitAmount()) == 0) {
generalLedgerEntry.setActivityStatusCode(CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS);
businessObjectService.save(generalLedgerEntry);
}
// Release asset lock for the entire document if all transactions have been processed.
// Otherwise, release asset lock for the processed asset line only
if (isFpDocumentFullyProcessed(generalLedgerEntry)) {
getCapitalAssetManagementModuleService().deleteAssetLocks(generalLedgerEntry.getDocumentNumber(), null);
} else {
getCapitalAssetManagementModuleService().deleteAssetLocks(generalLedgerEntry.getDocumentNumber(), generalLedgerEntryAsset.getCapitalAssetBuilderLineNumber() == null ? CamsConstants.defaultLockingInformation : generalLedgerEntryAsset.getCapitalAssetBuilderLineNumber().toString());
}
}
}
}
/**
* Check all generalLedgerEntries from the same FP document are fully processed.
*
* @param generalLedgerEntry
* @return
*/
protected boolean isFpDocumentFullyProcessed(GeneralLedgerEntry generalLedgerEntry) {
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CabPropertyConstants.GeneralLedgerEntry.DOCUMENT_NUMBER, generalLedgerEntry.getDocumentNumber());
Collection<GeneralLedgerEntry> matchingGlEntries = businessObjectService.findMatching(GeneralLedgerEntry.class, fieldValues);
for (GeneralLedgerEntry glEntry : matchingGlEntries) {
if (!CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS.equals(glEntry.getActivityStatusCode())) {
return false;
}
}
return true;
}
/**
* update CAB PO lines status code for item/account/glEntry to 'P' as fully processed when possible
*
* @param documentNumber
*/
protected void updatePOLinesStatusAsProcessed(String documentNumber) {
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CabPropertyConstants.PurchasingAccountsPayableItemAsset.CAMS_DOCUMENT_NUMBER, documentNumber);
Collection<PurchasingAccountsPayableItemAsset> matchingAssets = businessObjectService.findMatching(PurchasingAccountsPayableItemAsset.class, fieldValues);
if (matchingAssets != null && !matchingAssets.isEmpty()) {
// Map<Long, GeneralLedgerEntry> updateGlLines = new HashMap<Long, GeneralLedgerEntry>();
// update item and account status code to 'P' as fully processed
for (PurchasingAccountsPayableItemAsset itemAsset : matchingAssets) {
itemAsset.setActivityStatusCode(CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS);
for (PurchasingAccountsPayableLineAssetAccount assetAccount : itemAsset.getPurchasingAccountsPayableLineAssetAccounts()) {
assetAccount.setActivityStatusCode(CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS);
GeneralLedgerEntry generalLedgerEntry = assetAccount.getGeneralLedgerEntry();
// updateGlLines.put(generalLedgerEntry.getGeneralLedgerAccountIdentifier(), generalLedgerEntry);
if (isGlEntryFullyProcessed(generalLedgerEntry)) {
generalLedgerEntry.setActivityStatusCode(CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS);
businessObjectService.save(generalLedgerEntry);
}
}
// update cab document status code to 'P' as all its items fully processed
PurchasingAccountsPayableDocument purapDocument = itemAsset.getPurchasingAccountsPayableDocument();
if (isDocumentFullyProcessed(purapDocument)) {
purapDocument.setActivityStatusCode(CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS);
}
businessObjectService.save(purapDocument);
String lockingInformation = null;
PurchaseOrderDocument poDocument = getPurApInfoService().getCurrentDocumentForPurchaseOrderIdentifier(purapDocument.getPurchaseOrderIdentifier());
// Only individual system will lock on item line number. other system will using preq/cm doc nbr as the locking
// key
if (PurapConstants.CapitalAssetTabStrings.INDIVIDUAL_ASSETS.equalsIgnoreCase(poDocument.getCapitalAssetSystemTypeCode())) {
lockingInformation = itemAsset.getAccountsPayableLineItemIdentifier().toString();
}
// release the asset lock no matter if it's Asset global or Asset Payment since the CAB user can create Asset global
// doc even if Purap Asset numbers existing.
if (isAccountsPayableItemLineFullyProcessed(purapDocument, lockingInformation)) {
getCapitalAssetManagementModuleService().deleteAssetLocks(purapDocument.getDocumentNumber(), lockingInformation);
}
}
}
}
/**
* If lockingInformation is not empty, check all item lines from the same PurAp item are fully processed. If lockingInformation
* is empty, we check all items from the same PREQ/CM document processed as fully processed.
*
* @param itemAsset
* @return
*/
protected boolean isAccountsPayableItemLineFullyProcessed(PurchasingAccountsPayableDocument purapDocument, String lockingInformation) {
for (PurchasingAccountsPayableItemAsset item : purapDocument.getPurchasingAccountsPayableItemAssets()) {
if ((StringUtils.isBlank(lockingInformation) && !CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS.equals(item.getActivityStatusCode())) || (StringUtils.isNotBlank(lockingInformation) && item.getAccountsPayableLineItemIdentifier().equals(lockingInformation) && !CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS.equals(item.getActivityStatusCode()))) {
return false;
}
}
return true;
}
/**
* Check if Gl Entry related accounts are fully processed
*
* @param glEntry
* @return
*/
protected boolean isGlEntryFullyProcessed(GeneralLedgerEntry glEntry) {
for (PurchasingAccountsPayableLineAssetAccount account : glEntry.getPurApLineAssetAccounts()) {
if (!CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS.equalsIgnoreCase(account.getActivityStatusCode())) {
return false;
}
}
return true;
}
/**
* Check if PurApDocument related items are fully processed.
*
* @param purapDocument
* @return
*/
protected boolean isDocumentFullyProcessed(PurchasingAccountsPayableDocument purapDocument) {
for (PurchasingAccountsPayableItemAsset item : purapDocument.getPurchasingAccountsPayableItemAssets()) {
if (!CabConstants.ActivityStatusCode.PROCESSED_IN_CAMS.equalsIgnoreCase(item.getActivityStatusCode())) {
return false;
}
}
return true;
}
/**
* Build the appropriate note text being set to the purchase order document.
*
* @param documentType
* @param assetNumbers
* @return
*/
protected String buildNoteTextForPurApDoc(String documentType, List<Long> assetNumbers) {
StringBuffer noteText = new StringBuffer();
if (DocumentTypeName.ASSET_ADD_GLOBAL.equalsIgnoreCase(documentType)) {
noteText.append("Asset Numbers have been created for this document: ");
} else {
noteText.append("Existing Asset Numbers have been applied for this document: ");
}
if (assetNumbers != null || assetNumbers.size() > 0) {
noteText.append(assetNumbers.get(0).toString());
if (assetNumbers.size() > 1) {
noteText.append(",....,");
noteText.append(assetNumbers.get(assetNumbers.size() - 1).toString());
}
}
return noteText.toString();
}
/**
* Acquire asset numbers from CAMS asset payment document.
*
* @param documentNumber
* @param assetNumbers
*/
protected List<Long> getAssetNumbersFromAssetGlobal(String documentNumber) {
List<Long> assetNumbers = new ArrayList<Long>();
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CamsPropertyConstants.AssetGlobalDetail.DOCUMENT_NUMBER, documentNumber);
Collection<AssetGlobalDetail> assetGlobalDetails = businessObjectService.findMatching(AssetGlobalDetail.class, fieldValues);
for (AssetGlobalDetail detail : assetGlobalDetails) {
assetNumbers.add(detail.getCapitalAssetNumber());
}
return assetNumbers;
}
/**
* Acquire asset numbers from CAMS asset global document.
*
* @param documentNumber
* @param assetNumbers
*/
protected List<Long> getAssetNumbersFromAssetPayment(String documentNumber) {
List<Long> assetNumbers = new ArrayList<Long>();
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CamsPropertyConstants.DOCUMENT_NUMBER, documentNumber);
Collection<AssetPaymentAssetDetail> paymentAssetDetails = businessObjectService.findMatching(AssetPaymentAssetDetail.class, fieldValues);
for (AssetPaymentAssetDetail detail : paymentAssetDetails) {
if (ObjectUtils.isNotNull(detail.getAsset())) {
assetNumbers.add(detail.getCapitalAssetNumber());
}
}
return assetNumbers;
}
/**
* Query PurchasingAccountsPayableItemAsset and return the purchaseOrderIdentifier if the given documentNumber is initiated from
* the PurAp line.
*
* @param documentNumber
* @return
*/
protected Integer getPurchaseOrderIdentifier(String camsDocumentNumber) {
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CabPropertyConstants.PurchasingAccountsPayableItemAsset.CAMS_DOCUMENT_NUMBER, camsDocumentNumber);
Collection<PurchasingAccountsPayableItemAsset> matchingItems = businessObjectService.findMatching(PurchasingAccountsPayableItemAsset.class, fieldValues);
for (PurchasingAccountsPayableItemAsset item : matchingItems) {
if (ObjectUtils.isNull(item.getPurchasingAccountsPayableDocument())) {
item.refreshReferenceObject(CabPropertyConstants.PurchasingAccountsPayableItemAsset.PURCHASING_ACCOUNTS_PAYABLE_DOCUMENT);
}
return item.getPurchasingAccountsPayableDocument().getPurchaseOrderIdentifier();
}
return null;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#getCurrentPurchaseOrderDocumentNumber(java.lang.String)
*/
@Override
public String getCurrentPurchaseOrderDocumentNumber(String camsDocumentNumber) {
Integer poId = getPurchaseOrderIdentifier(camsDocumentNumber);
if (poId != null) {
PurchaseOrderDocument poDocument = getPurApInfoService().getCurrentDocumentForPurchaseOrderIdentifier(poId);
if (ObjectUtils.isNotNull(poDocument)) {
return poDocument.getDocumentNumber();
}
}
return null;
}
/**
* Activates CAB GL Lines
*
* @param documentNumber String
*/
protected void activateCabGlLines(String documentNumber) {
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CabPropertyConstants.PurchasingAccountsPayableItemAsset.CAMS_DOCUMENT_NUMBER, documentNumber);
Collection<GeneralLedgerEntryAsset> matchingGlAssets = getBusinessObjectService().findMatching(GeneralLedgerEntryAsset.class, fieldValues);
if (matchingGlAssets != null && !matchingGlAssets.isEmpty()) {
Integer capitalAssetLineNumber = 0;
GeneralLedgerEntry generalLedgerEntry = new GeneralLedgerEntry();
//get the capital asset number from these entry asset records...
for (GeneralLedgerEntryAsset generalLedgerEntryAsset : matchingGlAssets) {
capitalAssetLineNumber = generalLedgerEntryAsset.getCapitalAssetBuilderLineNumber();
generalLedgerEntry = generalLedgerEntryAsset.getGeneralLedgerEntry();
break;
}
//get the capital asset information....
CapitalAssetInformation capitalAssetInformation = glLineService.findCapitalAssetInformation(generalLedgerEntry.getDocumentNumber(), capitalAssetLineNumber);
List<CapitalAssetAccountsGroupDetails> groupAccountingLines = capitalAssetInformation.getCapitalAssetAccountsGroupDetails();
Collection<GeneralLedgerEntry> documentGlEntries = glLineService.findAllGeneralLedgerEntry(generalLedgerEntry.getDocumentNumber());
for (CapitalAssetAccountsGroupDetails accountingLine : groupAccountingLines) {
//find the matching GL entry for this accounting line.
Collection<GeneralLedgerEntry> glEntries = glLineService.findMatchingGeneralLedgerEntries(documentGlEntries, accountingLine);
for (GeneralLedgerEntry glEntry : glEntries) {
reduceTransactionSumbitGlEntryAmount(glEntry, accountingLine.getAmount());
}
}
//mark the capital asseet processed indicator as false so it can be processed again
capitalAssetInformation.setCapitalAssetProcessedIndicator(false);
getBusinessObjectService().save(capitalAssetInformation);
//if all the capital assets have been unprocessed, make sure to set the transaction
//submit gl entry amount on gl entry lines to 0.00
resetTransactionSumbitGlEntryAmounts(generalLedgerEntry);
}
//remove the gl entry asset records for this gl entry.
getBusinessObjectService().delete(new ArrayList<GeneralLedgerEntryAsset>(matchingGlAssets));
}
/**
* reduces the submit amount by the amount on the accounting line. When submit amount equals
* transaction ledger amount, the activity status code is marked as in route status.
*
* @param matchingGLEntry
* @param accountLineAmount
*/
protected void reduceTransactionSumbitGlEntryAmount(GeneralLedgerEntry matchingGLEntry, KualiDecimal accountLineAmount) {
//reduces submitted amount on the gl entry and save the results.
KualiDecimal submitTotalAmount = KualiDecimal.ZERO;
if (ObjectUtils.isNotNull(matchingGLEntry.getTransactionLedgerSubmitAmount())) {
submitTotalAmount = matchingGLEntry.getTransactionLedgerSubmitAmount();
}
matchingGLEntry.setTransactionLedgerSubmitAmount(submitTotalAmount.subtract(accountLineAmount.abs()));
if (matchingGLEntry.getTransactionLedgerSubmitAmount().isLessThan(matchingGLEntry.getTransactionLedgerEntryAmount())) {
matchingGLEntry.setActivityStatusCode(CabConstants.ActivityStatusCode.NEW);
}
//save the updated gl entry in CAB
businessObjectService.save(matchingGLEntry);
}
/**
* Helper method to retrieve the capital assets on the document and check if they have all been
* marked as unprocessed. If so, reset TransactionSumbitGlEntryAmount on each gl entry line,
* and mark activity indicator flag to "N" (new)
*
* @param glEntry
* @return true if amounts are reset to 0.00 else return false
*/
protected boolean resetTransactionSumbitGlEntryAmounts(GeneralLedgerEntry glEntry) {
List<CapitalAssetInformation> capitalAssets = glLineService.findAllCapitalAssetInformation(glEntry.getDocumentNumber());
for (CapitalAssetInformation capitalAsset : capitalAssets) {
if (capitalAsset.isCapitalAssetProcessedIndicator()) {
//processed capital asset exists so do not continue...
return false;
}
}
Collection<GeneralLedgerEntry> glLines = glLineService.findAllGeneralLedgerEntry(glEntry.getDocumentNumber());
for (GeneralLedgerEntry glLine : glLines) {
glLine.setTransactionLedgerSubmitAmount(KualiDecimal.ZERO);
glLine.setActivityStatusCode(CabConstants.ActivityStatusCode.NEW);
}
getBusinessObjectService().save(new ArrayList<GeneralLedgerEntry>(glLines));
return true;
}
/**
* Activates PO Lines
*
* @param documentNumber String
*/
protected void activateCabPOLines(String documentNumber) {
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CabPropertyConstants.PurchasingAccountsPayableItemAsset.CAMS_DOCUMENT_NUMBER, documentNumber);
Collection<PurchasingAccountsPayableItemAsset> matchingPoAssets = businessObjectService.findMatching(PurchasingAccountsPayableItemAsset.class, fieldValues);
if (matchingPoAssets != null && !matchingPoAssets.isEmpty()) {
for (PurchasingAccountsPayableItemAsset itemAsset : matchingPoAssets) {
PurchasingAccountsPayableDocument purapDocument = itemAsset.getPurchasingAccountsPayableDocument();
purapDocument.setActivityStatusCode(CabConstants.ActivityStatusCode.MODIFIED);
businessObjectService.save(purapDocument);
itemAsset.setActivityStatusCode(CabConstants.ActivityStatusCode.MODIFIED);
businessObjectService.save(itemAsset);
List<PurchasingAccountsPayableLineAssetAccount> lineAssetAccounts = itemAsset.getPurchasingAccountsPayableLineAssetAccounts();
for (PurchasingAccountsPayableLineAssetAccount assetAccount : lineAssetAccounts) {
assetAccount.setActivityStatusCode(CabConstants.ActivityStatusCode.MODIFIED);
businessObjectService.save(assetAccount);
GeneralLedgerEntry generalLedgerEntry = assetAccount.getGeneralLedgerEntry();
KualiDecimal submitAmount = generalLedgerEntry.getTransactionLedgerSubmitAmount();
if (submitAmount == null) {
submitAmount = KualiDecimal.ZERO;
}
submitAmount = submitAmount.subtract(assetAccount.getItemAccountTotalAmount());
generalLedgerEntry.setTransactionLedgerSubmitAmount(submitAmount);
generalLedgerEntry.setActivityStatusCode(CabConstants.ActivityStatusCode.MODIFIED);
businessObjectService.save(generalLedgerEntry);
}
}
}
}
/**
* gets the document type based on the instance of a class
*
* @param accountingDocument
* @return
*/
protected String getDocumentTypeName(AccountingDocument accountingDocument) {
String documentTypeName = null;
if (accountingDocument instanceof YearEndGeneralErrorCorrectionDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.YEAR_END_GENERAL_ERROR_CORRECTION;
} else if (accountingDocument instanceof YearEndDistributionOfIncomeAndExpenseDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.YEAR_END_DISTRIBUTION_OF_INCOME_AND_EXPENSE;
} else if (accountingDocument instanceof ServiceBillingDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.SERVICE_BILLING;
} else if (accountingDocument instanceof GeneralErrorCorrectionDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.GENERAL_ERROR_CORRECTION;
} else if (accountingDocument instanceof CashReceiptDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.CASH_RECEIPT;
} else if (accountingDocument instanceof AdvanceDepositDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.ADVANCE_DEPOSIT;
} else if (accountingDocument instanceof CreditCardReceiptDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.CREDIT_CARD_RECEIPT;
} else if (accountingDocument instanceof DistributionOfIncomeAndExpenseDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.DISTRIBUTION_OF_INCOME_AND_EXPENSE;
} else if (accountingDocument instanceof InternalBillingDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.INTERNAL_BILLING;
} else if (accountingDocument instanceof ProcurementCardDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.PROCUREMENT_CARD;
} else if (accountingDocument instanceof IntraAccountAdjustmentDocument) {
documentTypeName = KFSConstants.FinancialDocumentTypeCodes.INTRA_ACCOUNT_ADJUSTMENT;
} else {
throw new RuntimeException("Invalid FP document type.");
}
return documentTypeName;
}
public BusinessObjectService getBusinessObjectService() {
return businessObjectService;
}
public DataDictionaryService getDataDictionaryService() {
return dataDictionaryService;
}
/**
* Get the Capital Asset Object Code from the accounting lines.
*
* @param accountingLine
* @return true if the accounting line has an object code that belongs to
* OBJECT_SUB_TYPE_GROUPS system paramters list else return false;
*/
@Override
public boolean hasCapitalAssetObjectSubType(AccountingLine accountingLine) {
Collection<String> financialProcessingCapitalObjectSubTypes = getParameterService().getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, CabParameterConstants.CapitalAsset.FINANCIAL_PROCESSING_CAPITAL_OBJECT_SUB_TYPES);
ObjectCode objectCode = accountingLine.getObjectCode();
if (ObjectUtils.isNotNull(objectCode)) {
return financialProcessingCapitalObjectSubTypes.contains(objectCode.getFinancialObjectSubTypeCode());
}
return false;
}
/**
* Get the Capital Asset Object Code from the accounting lines.
*
* @param accountingLine
* @return true if the accounting line has an object code that belongs to
* CAPITAL_OBJECT_SUB_TYPES system paramters list else return false;
*/
public boolean hasCAMSCapitalAssetObjectSubType(AccountingLine line) {
Collection<String> capitalObjectSubTypes = getParameterService().getParameterValuesAsString(
AssetGlobal.class, CamsConstants.Parameters.CAPITAL_OBJECT_SUB_TYPES);
ObjectCode objectCode = line.getObjectCode();
if (ObjectUtils.isNotNull(objectCode)) {
return capitalObjectSubTypes.contains(objectCode.getFinancialObjectSubTypeCode());
}
return false;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#validateAllCapitalAccountingLinesProcessed(org.kuali.kfs.sys.document.AccountingDocument)
*/
@Override
public boolean validateAllCapitalAccountingLinesProcessed(AccountingDocument accountingDocumentForValidation) {
LOG.debug("validateCapitalAccountingLines - start");
boolean isValid = true;
if (accountingDocumentForValidation instanceof CapitalAssetEditable == false) {
return true;
}
CapitalAccountingLinesDocumentBase capitalAccountingLinesDocumentBase = (CapitalAccountingLinesDocumentBase) accountingDocumentForValidation;
List<CapitalAccountingLines> capitalAccountingLines = capitalAccountingLinesDocumentBase.getCapitalAccountingLines();
isValid = allCapitalAccountingLinesProcessed(capitalAccountingLines);
return isValid;
}
/**
* checks if all the lines have been selected for processing by checking the selectLine property
* on each capital accounting line.
*
* @param capitalAccountingLines
* @return true if all lines have been selected else return false
*/
protected boolean allCapitalAccountingLinesProcessed(List<CapitalAccountingLines> capitalAccountingLines) {
LOG.debug("allCapitalAccountingLinesProcessed - start");
boolean processed = true;
for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
if (!capitalAccountingLine.isSelectLine()) {
processed = false;
GlobalVariables.getMessageMap().putError(KFSConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_FOR_CAPITALIZATION_NOT_PROCESSED);
break;
}
}
return processed;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#validateTotalAmountMatch(org.kuali.kfs.sys.document.AccountingDocument)
*/
@Override
public boolean validateTotalAmountMatch(AccountingDocument accountingDocumentForValidation) {
LOG.debug("validateTotalAmountMatch - start");
boolean isValid = true;
if (accountingDocumentForValidation instanceof CapitalAssetEditable == false) {
return true;
}
CapitalAccountingLinesDocumentBase capitalAccountingLinesDocumentBase = (CapitalAccountingLinesDocumentBase) accountingDocumentForValidation;
List<CapitalAccountingLines> capitalAccountingLines = capitalAccountingLinesDocumentBase.getCapitalAccountingLines();
CapitalAssetEditable capitalAssetEditable = (CapitalAssetEditable) accountingDocumentForValidation;
List<CapitalAssetInformation> capitalAssets = capitalAssetEditable.getCapitalAssetInformation();
isValid = totalAmountMatchForCapitalAccountingLinesAndCapitalAssets(capitalAccountingLines, capitalAssets);
return isValid;
}
/**
* compares the total amount from capital accounting lines to the
* capital assets totals amount.
*
* @param capitalAccountingLines
* @param capitalAssets
* @return true if two amounts are equal else return false
*/
protected boolean totalAmountMatchForCapitalAccountingLinesAndCapitalAssets(List<CapitalAccountingLines> capitalAccountingLines, List<CapitalAssetInformation> capitalAssets) {
boolean totalAmountMatched = true;
KualiDecimal capitalAccountingLinesTotals = KualiDecimal.ZERO;
KualiDecimal capitalAAssetTotals = KualiDecimal.ZERO;
for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
capitalAccountingLinesTotals = capitalAccountingLinesTotals.add(capitalAccountingLine.getAmount());
}
for (CapitalAssetInformation capitalAsset : capitalAssets) {
capitalAAssetTotals = capitalAAssetTotals.add(capitalAsset.getCapitalAssetLineAmount());
}
if (capitalAccountingLinesTotals.isGreaterThan(capitalAAssetTotals)) {
//not all the accounting lines amounts have been distributed to capital assets
GlobalVariables.getMessageMap().putError(KFSConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINES_NOT_ALL_TOTALS_DISTRIBUTED_TO_CAPITAL_ASSETS);
return false;
}
if (capitalAccountingLinesTotals.isLessThan(capitalAAssetTotals)) {
//not all the accounting lines amounts have been distributed to capital assets
GlobalVariables.getMessageMap().putError(KFSConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINES_MORE_TOTALS_DISTRIBUTED_TO_CAPITAL_ASSETS);
return false;
}
return totalAmountMatched;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#validateCapitlAssetsAmountToAccountingLineAmount(org.kuali.kfs.sys.document.AccountingDocument)
*/
@Override
public boolean validateCapitlAssetsAmountToAccountingLineAmount(AccountingDocument accountingDocument) {
boolean valid = true;
CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) accountingDocument;
List<CapitalAccountingLines> capitalAccountingLines = caldb.getCapitalAccountingLines();
List<CapitalAssetInformation> capitalAssetInformation = caldb.getCapitalAssetInformation();
for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
if (capitalAccountingLine.getAmount().isLessThan(getCapitalAccountingLineAmountAllocated(capitalAssetInformation, capitalAccountingLine))) {
GlobalVariables.getMessageMap().putError(KFSConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_CAPITAL_ASSETS_AMOUNTS_GREATER_THAN_CAPITAL_ACCOUNTING_LINE, capitalAccountingLine.getSequenceNumber().toString(), capitalAccountingLine.getLineType(), capitalAccountingLine.getChartOfAccountsCode(), capitalAccountingLine.getAccountNumber(), capitalAccountingLine.getFinancialObjectCode());
valid = false;
}
}
return valid;
}
/**
* sums the capital assets amount distributed so far for a given capital accounting line
*
* @param currentCapitalAssetInformation
* @param existingCapitalAsset
* @return capitalAssetsAmount amount that has been distributed for the specific capital accounting line
*/
protected KualiDecimal getCapitalAccountingLineAmountAllocated(List<CapitalAssetInformation> currentCapitalAssetInformation, CapitalAccountingLines capitalAccountingLine) {
//check the capital assets records totals
KualiDecimal capitalAccountingLineAmount = KualiDecimal.ZERO;
for (CapitalAssetInformation capitalAsset : currentCapitalAssetInformation) {
List<CapitalAssetAccountsGroupDetails> groupAccountLines = capitalAsset.getCapitalAssetAccountsGroupDetails();
for (CapitalAssetAccountsGroupDetails groupAccountLine : groupAccountLines) {
if (groupAccountLine.getCapitalAssetLineNumber().compareTo(capitalAsset.getCapitalAssetLineNumber()) == 0 &&
groupAccountLine.getSequenceNumber().compareTo(capitalAccountingLine.getSequenceNumber()) == 0 &&
groupAccountLine.getFinancialDocumentLineTypeCode().equals(KFSConstants.SOURCE.equals(capitalAccountingLine.getLineType()) ? KFSConstants.SOURCE_ACCT_LINE_TYPE_CODE : KFSConstants.TARGET_ACCT_LINE_TYPE_CODE) &&
groupAccountLine.getChartOfAccountsCode().equals(capitalAccountingLine.getChartOfAccountsCode()) &&
groupAccountLine.getAccountNumber().equals(capitalAccountingLine.getAccountNumber()) &&
groupAccountLine.getFinancialObjectCode().equals(capitalAccountingLine.getFinancialObjectCode())) {
capitalAccountingLineAmount = capitalAccountingLineAmount.add(groupAccountLine.getAmount());
}
}
}
return capitalAccountingLineAmount;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#validateCapitalAccountingLines(org.kuali.kfs.sys.document.AccountingDocument)
*/
@Override
public boolean validateCapitalAccountingLines(AccountingDocument accountingDocumentForValidation) {
LOG.debug("validateCapitalAccountingLines - start");
boolean isValid = true;
if (accountingDocumentForValidation instanceof CapitalAssetEditable == false) {
return true;
}
CapitalAccountingLinesDocumentBase capitalAccountingLinesDocumentBase = (CapitalAccountingLinesDocumentBase) accountingDocumentForValidation;
List<CapitalAccountingLines> capitalAccountingLines = capitalAccountingLinesDocumentBase.getCapitalAccountingLines();
CapitalAssetEditable capitalAssetEditable = (CapitalAssetEditable) accountingDocumentForValidation;
List<CapitalAssetInformation> capitalAssets = capitalAssetEditable.getCapitalAssetInformation();
isValid = capitalAssetExistsForCapitalAccountingLinesProcessed(capitalAccountingLines, capitalAssets);
return isValid;
}
/**
* Check FP document eligibility by document type for CAB Extract batch.
*
* @param documentType
* @return
*/
@Override
public boolean isDocumentEligibleForCABBatch(String documentType) {
boolean eligible = true;
List<String> excludedDocTypeCodes = new ArrayList<String>(parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_BATCH.class, CabConstants.Parameters.DOCUMENT_TYPES));
// check with the docTypeCodes system parameter
if (excludedDocTypeCodes.contains(documentType)) {
eligible = false;
}
return eligible;
}
@Override
public List<String> getBatchIncludedObjectSubTypes() {
List<String> includedFinancialObjectSubTypeCodes = new ArrayList<String>(parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_BATCH.class, CabConstants.Parameters.OBJECT_SUB_TYPES));
return includedFinancialObjectSubTypeCodes;
}
@Override
public List<String> getBatchExcludedChartCodes() {
List<String> excludedChartCodes = new ArrayList<String>(parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_BATCH.class, CabConstants.Parameters.CHARTS));
return excludedChartCodes;
}
@Override
public List<String> getBatchExcludedSubFundCodes() {
List<String> excludedSubFundCodes = new ArrayList<String>(parameterService.getParameterValuesAsString(KfsParameterConstants.CAPITAL_ASSET_BUILDER_BATCH.class, CabConstants.Parameters.SUB_FUND_GROUPS));
return excludedSubFundCodes;
}
/**
* Check FP document individual Capital Asset line eligibility for CAB Extract Batch
*
* @param assetLine
* @param postingYear
* @return
*/
@Override
public boolean isAssetLineEligibleForCABBatch(
CapitalAssetInformation assetLine, Integer postingYear,
List<String> includedFinancialObjectSubTypeCodes,
List<String> excludedChartCodes, List<String> excludedSubFundCodes) {
boolean eligible = true;
List<CapitalAssetAccountsGroupDetails> acctDetailLines = assetLine.getCapitalAssetAccountsGroupDetails();
for (CapitalAssetAccountsGroupDetails detailLine : acctDetailLines) {
eligible = true;
// This is clumsy since we're not persistent posting year
ObjectCode objectCodeBO = retrieveFinancialObject(postingYear, detailLine);
// check with the CAB-financialObjectSubTypeCodes system parameter
if (ObjectUtils.isNotNull(objectCodeBO) && includedFinancialObjectSubTypeCodes != null && !includedFinancialObjectSubTypeCodes.contains(objectCodeBO.getFinancialObjectSubTypeCode())) {
eligible = false;
}
// check with the CAB-charOfAccountCode system parameter
if (eligible && excludedChartCodes != null && excludedChartCodes.contains(detailLine.getChartOfAccountsCode())) {
eligible = false;
}
// check with the CAB-subFundCodes system parameter
if (eligible && excludedSubFundCodes != null && ObjectUtils.isNotNull(detailLine.getAccount()) && excludedSubFundCodes.contains(detailLine.getAccount().getSubFundGroupCode())) {
eligible = false;
}
// As long as one accounting line has capital asset transaction, it will be extract to CAB.
if (eligible) {
break;
}
}
// If none of the accounting line eligible for CAB batch, CAB batch won't take the FP document into CAB
return eligible;
}
/**
* Retrieving Object BO from table
*
* @param postingYear
* @param acctDetailLine
* @return
*/
protected ObjectCode retrieveFinancialObject(Integer postingYear,
CapitalAssetAccountsGroupDetails acctDetailLine) {
ObjectCode financialObject = null;
if (ObjectUtils.isNotNull(acctDetailLine)) {
Map<String, Object> primaryKeys = new HashMap<String, Object>();
primaryKeys.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, postingYear);
primaryKeys.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, acctDetailLine.getChartOfAccountsCode());
primaryKeys.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, acctDetailLine.getFinancialObjectCode());
financialObject = businessObjectService.findByPrimaryKey(ObjectCode.class, primaryKeys);
}
return financialObject;
}
/**
* @param capitalAccountingLines
* @param capitalAssets
* @return true capital assets exists for all the capital accounting lines.
*/
protected boolean capitalAssetExistsForCapitalAccountingLinesProcessed(List<CapitalAccountingLines> capitalAccountingLines, List<CapitalAssetInformation> capitalAssets) {
LOG.debug("capitalAssetExistsForCapitalAccountingLinesProcessed - start");
boolean exists = true;
for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
if (!capitalAssetExist(capitalAccountingLine, capitalAssets)) {
GlobalVariables.getMessageMap().putError(KFSConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_FOR_CAPITALIZATION_HAS_NO_CAPITAL_ASSET, capitalAccountingLine.getSequenceNumber().toString(), capitalAccountingLine.getLineType(), capitalAccountingLine.getChartOfAccountsCode(), capitalAccountingLine.getAccountNumber(), capitalAccountingLine.getFinancialObjectCode());
return false;
}
}
return exists;
}
/**
* checks if capital asset exists for the given capital accounting line.
*
* @param capitalAccountingLine
* @param capitalAssetInformation
* @return true if capital accounting line has a capital asset information else return false
*/
protected boolean capitalAssetExist(CapitalAccountingLines capitalAccountingLine, List<CapitalAssetInformation> capitalAssetInformation) {
boolean exists = false;
if (ObjectUtils.isNull(capitalAssetInformation) && capitalAssetInformation.size() <= 0) {
return exists;
}
for (CapitalAssetInformation capitalAsset : capitalAssetInformation) {
List<CapitalAssetAccountsGroupDetails> groupAccountLines = capitalAsset.getCapitalAssetAccountsGroupDetails();
for (CapitalAssetAccountsGroupDetails groupAccountLine : groupAccountLines) {
if (groupAccountLine.getCapitalAssetLineNumber().compareTo(capitalAsset.getCapitalAssetLineNumber()) == 0 &&
groupAccountLine.getSequenceNumber().compareTo(capitalAccountingLine.getSequenceNumber()) == 0 &&
groupAccountLine.getFinancialDocumentLineTypeCode().equals(KFSConstants.SOURCE.equals(capitalAccountingLine.getLineType()) ? KFSConstants.SOURCE_ACCT_LINE_TYPE_CODE : KFSConstants.TARGET_ACCT_LINE_TYPE_CODE) &&
groupAccountLine.getChartOfAccountsCode().equals(capitalAccountingLine.getChartOfAccountsCode()) &&
groupAccountLine.getAccountNumber().equals(capitalAccountingLine.getAccountNumber()) &&
groupAccountLine.getFinancialObjectCode().equals(capitalAccountingLine.getFinancialObjectCode())) {
return true;
}
}
}
return exists;
}
/**
* @see org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService#markProcessedGLEntryLine(java.lang.String)
*/
@Override
public boolean markProcessedGLEntryLine(String documentNumber) {
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(CabPropertyConstants.PurchasingAccountsPayableItemAsset.CAMS_DOCUMENT_NUMBER, documentNumber);
Collection<GeneralLedgerEntryAsset> matchingGlAssets = businessObjectService.findMatching(GeneralLedgerEntryAsset.class, fieldValues);
if (matchingGlAssets != null && !matchingGlAssets.isEmpty()) {
for (GeneralLedgerEntryAsset generalLedgerEntryAsset : matchingGlAssets) {
GeneralLedgerEntry generalLedgerEntry = generalLedgerEntryAsset.getGeneralLedgerEntry();
// update gl status as processed
if (glLineService.findUnprocessedCapitalAssetInformation(generalLedgerEntry.getDocumentNumber()) == 0) {
generalLedgerEntry.setActivityStatusCode(CabConstants.ActivityStatusCode.ENROUTE);
} else {
generalLedgerEntry.setActivityStatusCode(CabConstants.ActivityStatusCode.NEW);
}
businessObjectService.save(generalLedgerEntry);
}
}
return true;
}
public void setGlLineService(GlLineService glLineService) {
this.glLineService = glLineService;
}
public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
this.dataDictionaryService = dataDictionaryService;
}
public void setParameterEvaluatorService(ParameterEvaluatorService parameterEvaluatorService) {
this.parameterEvaluatorService = parameterEvaluatorService;
}
public void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
public void setParameterRepositoryService(ParameterRepositoryService parameterRepositoryService) {
this.parameterRepositoryService = parameterRepositoryService;
}
public ParameterService getParameterService() {
return parameterService;
}
public void setParameterService(ParameterService parameterService) {
this.parameterService = parameterService;
}
public void setBusinessObjectService(BusinessObjectService businessObjectService) {
this.businessObjectService = businessObjectService;
}
public void setAssetService(AssetService assetService) {
this.assetService = assetService;
}
public void setPurApInfoService(PurApInfoService purApInfoService) {
this.purApInfoService = purApInfoService;
}
public void setCapitalAssetManagementModuleService(CapitalAssetManagementModuleService capitalAssetManagementModuleService) {
this.capitalAssetManagementModuleService = capitalAssetManagementModuleService;
}
public void setKualiModuleService(KualiModuleService kualiModuleService) {
this.kualiModuleService = kualiModuleService;
}
public AssetService getAssetService() {
return assetService;
}
public PurApInfoService getPurApInfoService() {
return purApInfoService;
}
public CapitalAssetManagementModuleService getCapitalAssetManagementModuleService() {
return capitalAssetManagementModuleService;
}
public KualiModuleService getKualiModuleService() {
return kualiModuleService;
}
public void setBusinessObjectDictionaryService(BusinessObjectDictionaryService businessObjectDictionaryService) {
this.businessObjectDictionaryService = businessObjectDictionaryService;
}
public void setCampusService(CampusService campusService) {
this.campusService = campusService;
}
public void setDictionaryValidationService(DictionaryValidationService dictionaryValidationService) {
this.dictionaryValidationService = dictionaryValidationService;
}
public void setPurchasingAccountsPayableModuleService(PurchasingAccountsPayableModuleService purchasingAccountsPayableModuleService) {
this.purchasingAccountsPayableModuleService = purchasingAccountsPayableModuleService;
}
@Override
public void reactivatePretagDetails(String campusTagNumber) {
if (campusTagNumber != null && !campusTagNumber.isEmpty()) {
Map<String, String> map = new HashMap<String, String>();
map.put(CabPropertyConstants.PretagDetail.CAMPUS_TAG_NUMBER, campusTagNumber);
List<PretagDetail> pretagDetailList = (List<PretagDetail>) SpringContext.getBean(BusinessObjectService.class).findMatching(PretagDetail.class, map);
if (ObjectUtils.isNotNull(pretagDetailList)) {
for (PretagDetail pretagDetail : pretagDetailList) {
pretagDetail.setActive(true);
SpringContext.getBean(BusinessObjectService.class).save(pretagDetail);
}
}
}
}
@Override
public void filterNonCapitalAssets(List<CapitalAssetInformation> infos) {
// do nothing here- this is where the institution would place it's own implementation if desired
return;
}
}