/* * 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.fp.document.validation.impl; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import org.apache.commons.lang.StringUtils; 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.document.validation.AccountingDocumentValidationBase; import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent; import org.kuali.kfs.sys.service.impl.KfsParameterConstants; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; /** * Validates that, for accounting lines which are identified as capital asset accounting lines, * they are unique so they can be handled individually by the Capital Asset Builder module. */ public class CapitalAssetAccountingLineUniquenessEnforcementValidation extends AccountingDocumentValidationBase { @Override public boolean validate(AttributedDocumentEvent event) { Collection<AccountingLine> capitalAssetLines = getCapitalAssetAccountingLines( getAllAccountingLines() ); // no matching lines, nothing to validate if ( capitalAssetLines.isEmpty() ) { return true; } return validateLineUniqueness( capitalAssetLines ); } protected Collection<String> getCapitalAssetObjectSubTypes() { return getParameterService().getParameterValuesAsString( KfsParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, "FINANCIAL_PROCESSING_CAPITAL_OBJECT_SUB_TYPES"); // JHK: I don't like the use of the constant above - but this parameter exists in the CAB module // Fortunately, since Rice 2.0 - the statement above will not blow up if CAB is not installed. // It will just return an empty list which will short-circuit the validation. } protected Collection<AccountingLine> getCapitalAssetAccountingLines( Collection<AccountingLine> allLines ) { Collection<AccountingLine> capitalAssetAccountingLines = new ArrayList<AccountingLine>(allLines.size()); Collection<String> capitalAssetObjectSubTypes = getCapitalAssetObjectSubTypes(); // if none defined, exit if ( capitalAssetObjectSubTypes.isEmpty() ) { return capitalAssetAccountingLines; } for ( AccountingLine line : allLines ) { // we only care about expenses (not encumbrance or budget) // many documents leave the balance type blank when going to use the "default" of "AC" if ( StringUtils.isNotBlank( line.getBalanceTypeCode() ) && !StringUtils.equals( line.getBalanceTypeCode(), KFSConstants.BALANCE_TYPE_ACTUAL ) ) { continue; } // need to ensure that we have a financial object to test the sub type against - only refresh if necessary if ( StringUtils.isBlank(line.getFinancialObjectCode()) ) { continue; // no object code } if ( ObjectUtils.isNull( line.getObjectCode() ) || !StringUtils.equals(line.getChartOfAccountsCode(), line.getObjectCode().getChartOfAccountsCode()) || !StringUtils.equals(line.getFinancialObjectCode(), line.getObjectCode().getFinancialObjectCode()) ) { line.refreshReferenceObject(KFSPropertyConstants.OBJECT_CODE); } if ( ObjectUtils.isNull( line.getObjectCode() ) ) { continue; // invalid object code } if ( capitalAssetObjectSubTypes.contains( line.getObjectCode().getFinancialObjectSubTypeCode() ) ) { capitalAssetAccountingLines.add( line ); } } return capitalAssetAccountingLines; } protected boolean validateLineUniqueness( Collection<AccountingLine> capitalAssetAccountingLines ) { HashSet<String> uniqueLineKeys = new HashSet<String>(); for ( AccountingLine line : capitalAssetAccountingLines ) { if ( !uniqueLineKeys.add( getLineUniquenessKey(line) ) ) { GlobalVariables.getMessageMap().putError("sourceAccountingLines", KFSKeyConstants.ERROR_NONUNIQUE_CAPITAL_ASSET_ACCOUNTING_LINE); return false; } } return true; } protected String getLineUniquenessKey( AccountingLine line ) { StringBuilder sb = new StringBuilder(); sb.append( line.getChartOfAccountsCode() ); sb.append( line.getAccountNumber() ); sb.append( line.getSubAccountNumber() ); sb.append( line.getFinancialObjectCode() ); sb.append( line.getFinancialSubObjectCode() ); sb.append( line.getProjectCode() ); sb.append( line.getOrganizationReferenceId() ); return sb.toString(); } }