/* * 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; } }