/* * 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.cam.document.service.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.businessobject.ObjectCode; import org.kuali.kfs.coa.service.ObjectCodeService; import org.kuali.kfs.module.cam.CamsConstants; 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.AssetLocation; import org.kuali.kfs.module.cam.businessobject.AssetPayment; import org.kuali.kfs.module.cam.businessobject.AssetType; import org.kuali.kfs.module.cam.document.service.AssetService; import org.kuali.kfs.module.cam.document.service.PaymentSummaryService; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.KFSConstants.DocumentStatusCodes; import org.kuali.kfs.sys.businessobject.UniversityDate; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.service.UniversityDateService; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.kew.api.WorkflowDocument; import org.kuali.rice.kns.document.MaintenanceDocument; import org.kuali.rice.krad.document.Document; import org.kuali.rice.krad.exception.ValidationException; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.util.ObjectUtils; public class AssetServiceImpl implements AssetService { protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetServiceImpl.class); private ParameterService parameterService; private PaymentSummaryService paymentSummaryService; private BusinessObjectService businessObjectService; public ParameterService getParameterService() { return parameterService; } public void setParameterService(ParameterService parameterService) { this.parameterService = parameterService; } public boolean isAssetMovableCheckByAsset(Asset asset) { asset.refreshReferenceObject(CamsPropertyConstants.Asset.CAPITAL_ASSET_TYPE); return asset.getCapitalAssetType().isMovingIndicator(); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetDepreciationStarted(org.kuali.kfs.module.cam.businessobject.Asset) */ public boolean isAssetDepreciationStarted(Asset asset) { // check non-persistent field accumulatedDepreciation first since it's the sum of // assetPayment.accumulatedPrimaryDepreciationAmount. If it's not set yet, we'll check assetPayment one by one. if (ObjectUtils.isNotNull(asset.getAccumulatedDepreciation()) && asset.getAccumulatedDepreciation().isPositive()) { return true; } else { for (AssetPayment assetPayment : asset.getAssetPayments()) { if (ObjectUtils.isNotNull(assetPayment.getAccumulatedPrimaryDepreciationAmount()) && assetPayment.getAccumulatedPrimaryDepreciationAmount().isPositive()) { return true; } } } return false; } public boolean isCapitalAsset(Asset asset) { return parameterService.getParameterValuesAsString(Asset.class, CamsConstants.Parameters.CAPITAL_ASSET_STATUS_CODES).contains(asset.getInventoryStatusCode()); } public boolean isAssetRetired(Asset asset) { return parameterService.getParameterValuesAsString(Asset.class, CamsConstants.Parameters.RETIRED_STATUS_CODES).contains(asset.getInventoryStatusCode()); } public boolean isInServiceDateChanged(Asset oldAsset, Asset newAsset) { return !(ObjectUtils.isNull(oldAsset.getCapitalAssetInServiceDate()) ? ObjectUtils.isNull(newAsset.getCapitalAssetInServiceDate()) : oldAsset.getCapitalAssetInServiceDate().equals(newAsset.getCapitalAssetInServiceDate())); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetFabrication(org.kuali.rice.kns.document.MaintenanceDocument) */ public boolean isAssetFabrication(MaintenanceDocument maintenanceDocument) { return maintenanceDocument.getNewMaintainableObject().getBusinessObject() instanceof Asset && maintenanceDocument.isNew(); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetLoaned(org.kuali.kfs.module.cam.businessobject.Asset) */ public boolean isAssetLoaned(Asset asset) { return ObjectUtils.isNotNull(asset.getExpectedReturnDate()) && ObjectUtils.isNull(asset.getLoanReturnDate()); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetTaggedInPriorFiscalYear(org.kuali.kfs.module.cam.businessobject.Asset) */ public boolean isAssetTaggedInPriorFiscalYear(Asset asset) { UniversityDateService universityDateService = SpringContext.getBean(UniversityDateService.class); return StringUtils.isNotBlank(asset.getCampusTagNumber()) && ObjectUtils.isNotNull(asset.getFinancialDocumentPostingYear()) && !universityDateService.getCurrentFiscalYear().equals(asset.getFinancialDocumentPostingYear()); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isTagNumberCheckExclude(org.kuali.kfs.module.cam.businessobject.Asset) */ public boolean isTagNumberCheckExclude(Asset asset) { String status = asset.getInventoryStatusCode(); return StringUtils.equalsIgnoreCase(status, CamsConstants.InventoryStatusCode.CAPITAL_ASSET_RETIRED) || StringUtils.equalsIgnoreCase(status, CamsConstants.InventoryStatusCode.NON_CAPITAL_ASSET_RETIRED) || StringUtils.equalsIgnoreCase(asset.getCampusTagNumber(), CamsConstants.Asset.NON_TAGGABLE_ASSET); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isOffCampusLocationEntered(org.kuali.kfs.module.cam.businessobject.Asset) */ public boolean isOffCampusLocationEntered(Asset asset) { AssetLocation offCampus = asset.getOffCampusLocation(); return StringUtils.isNotBlank(offCampus.getAssetLocationContactName()) || StringUtils.isNotBlank(offCampus.getAssetLocationStreetAddress()) || StringUtils.isNotBlank(offCampus.getAssetLocationCityName()) || StringUtils.isNotBlank(offCampus.getAssetLocationStateCode()) || StringUtils.isNotBlank(offCampus.getAssetLocationZipCode()) || StringUtils.isNotBlank(offCampus.getAssetLocationCountryCode()); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isFinancialObjectSubTypeCodeChanged(org.kuali.kfs.module.cam.businessobject.Asset, * org.kuali.kfs.module.cam.businessobject.Asset) */ public boolean isFinancialObjectSubTypeCodeChanged(Asset oldAsset, Asset newAsset) { return !StringUtils.equalsIgnoreCase(oldAsset.getFinancialObjectSubTypeCode(), newAsset.getFinancialObjectSubTypeCode()); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetTypeCodeChanged(org.kuali.kfs.module.cam.businessobject.Asset, * org.kuali.kfs.module.cam.businessobject.Asset) */ public boolean isAssetTypeCodeChanged(Asset oldAsset, Asset newAsset) { return !StringUtils.equalsIgnoreCase(oldAsset.getCapitalAssetTypeCode(), newAsset.getCapitalAssetTypeCode()); } public boolean isAssetDepreciableLifeLimitZero(Asset asset) { asset.refreshReferenceObject(CamsPropertyConstants.Asset.CAPITAL_ASSET_TYPE); AssetType capitalAssetType = asset.getCapitalAssetType(); if (ObjectUtils.isNotNull(capitalAssetType)) { return Integer.valueOf(0).equals(capitalAssetType.getDepreciableLifeLimit()); } return false; } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isCapitalAssetNumberDuplicate(java.lang.Long, java.lang.Long) */ public boolean isCapitalAssetNumberDuplicate(Long capitalAssetNumber1, Long capitalAssetNumber2) { if (capitalAssetNumber1 != null && capitalAssetNumber2 != null && capitalAssetNumber1.compareTo(capitalAssetNumber2) == 0) { return true; } return false; } /** * This method calls the service codes to calculate the summary fields for each asset * * @param asset */ public void setAssetSummaryFields(Asset asset) { if (ObjectUtils.isNotNull(asset)) { asset.setFederalContribution(paymentSummaryService.calculateFederalContribution(asset)); asset.setAccumulatedDepreciation(paymentSummaryService.calculatePrimaryAccumulatedDepreciation(asset)); asset.setBookValue(paymentSummaryService.calculatePrimaryBookValue(asset)); } } public PaymentSummaryService getPaymentSummaryService() { return paymentSummaryService; } public void setPaymentSummaryService(PaymentSummaryService paymentSummaryService) { this.paymentSummaryService = paymentSummaryService; } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetMovableCheckByPayment(java.lang.String) */ public boolean isAssetMovableCheckByPayment(String financialObjectSubTypeCode) { if (ObjectUtils.isNull(financialObjectSubTypeCode)) { return true; } if (parameterService.getParameterValuesAsString(Asset.class, CamsConstants.Parameters.MOVABLE_EQUIPMENT_OBJECT_SUB_TYPES).contains(financialObjectSubTypeCode)) { return true; } else if (parameterService.getParameterValuesAsString(Asset.class, CamsConstants.Parameters.NON_MOVABLE_EQUIPMENT_OBJECT_SUB_TYPES).contains(financialObjectSubTypeCode)) { return false; } else { throw new ValidationException("Could not determine movable or non-movable for this object sub-type code " + financialObjectSubTypeCode); } } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetMovableCheckByPayment(Asset) */ public boolean isAssetMovableCheckByPayment(Asset asset) { String financialObjectSubTypeCode = asset.getFinancialObjectSubTypeCode(); if (ObjectUtils.isNotNull(asset.getAssetPayments()) && !asset.getAssetPayments().isEmpty()) { // use the last payment, so it's more recent and less likely to hit an out-dated object code int size = asset.getAssetPayments().size(); AssetPayment lastAssetPayment = asset.getAssetPayments().get(size-1); lastAssetPayment.refreshReferenceObject(CamsPropertyConstants.AssetPayment.FINANCIAL_OBJECT); ObjectCodeService objectCodeService = (ObjectCodeService) SpringContext.getBean(ObjectCodeService.class); String chartCode = lastAssetPayment.getChartOfAccountsCode(); String finObjectCode = lastAssetPayment.getFinancialObjectCode(); ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(chartCode, finObjectCode); // if objectCode is null, we likely have hit an out-dated object code from some old payment if (ObjectUtils.isNotNull(objectCode)) { financialObjectSubTypeCode = objectCode.getFinancialObjectSubTypeCode(); } else { LOG.warn("Possibly out-dated object code " + finObjectCode + " for chart " + chartCode + " for current fiscal year in payments for asset " + asset.getCapitalAssetNumber()); } } return this.isAssetMovableCheckByPayment(financialObjectSubTypeCode); } public List<Asset> findActiveAssetsMatchingTagNumber(String campusTagNumber) { List<Asset> activeMatches = new ArrayList<Asset>(); // find all assets matching this tag number Map<String, String> params = new HashMap<String, String>(); params.put(CamsPropertyConstants.Asset.CAMPUS_TAG_NUMBER, campusTagNumber); Collection<Asset> tagMatches = SpringContext.getBean(BusinessObjectService.class).findMatching(Asset.class, params); if (tagMatches != null && !tagMatches.isEmpty()) { for (Asset asset : tagMatches) { // if found matching, check if status is not retired if (!isAssetRetired(asset)) { activeMatches.add(asset); } } } return activeMatches; } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#findAssetsMatchingTagNumber(java.lang.String) */ public Collection<Asset> findAssetsMatchingTagNumber(String campusTagNumber) { // find all assets matching this tag number Map<String, String> params = new HashMap<String, String>(); params.put(CamsPropertyConstants.Asset.CAMPUS_TAG_NUMBER, campusTagNumber); Collection<Asset> tagMatches = SpringContext.getBean(BusinessObjectService.class).findMatching(Asset.class, params); return tagMatches; } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isObjectSubTypeCompatible(java.util.List) */ public boolean isObjectSubTypeCompatible(List<String> financialObjectSubTypeCode) { if (financialObjectSubTypeCode == null || financialObjectSubTypeCode.size() <= 1) { return true; } List<String> subTypes = new ArrayList<String>( parameterService.getParameterValuesAsString(Asset.class, CamsConstants.Parameters.OBJECT_SUB_TYPE_GROUPS) ); String firstObjectSubType = (String) financialObjectSubTypeCode.get(0); List<String> validObjectSubTypes = new ArrayList<String>(); // Get the set for compatible object sub type code by the first financial object sub type code for (String subType : subTypes) { if (subType.contains(firstObjectSubType)) { validObjectSubTypes = Arrays.asList(StringUtils.split(subType, ",")); break; } } if (validObjectSubTypes.isEmpty()) { validObjectSubTypes.add(firstObjectSubType); } // Check in the whole list if all object sub type code are compatible. for (String subTypeCode : financialObjectSubTypeCode) { if (!validObjectSubTypes.contains(subTypeCode)) { return false; } } return true; } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#setSeparateHistory(org.kuali.kfs.module.cam.businessobject.Asset) */ public void setSeparateHistory(Asset asset) { // Find the asset this was separated from. It should only be one, error if more Map<String, String> paramsAssetGlobalDetail = new HashMap<String, String>(); paramsAssetGlobalDetail.put(CamsPropertyConstants.AssetGlobalDetail.CAPITAL_ASSET_NUMBER, asset.getCapitalAssetNumber().toString()); Collection<AssetGlobalDetail> assetGlobalDetails = SpringContext.getBean(BusinessObjectService.class).findMatching(AssetGlobalDetail.class, paramsAssetGlobalDetail); if (assetGlobalDetails.size() > 1) { throw new IllegalStateException("Asset #" + asset.getCapitalAssetNumber().toString() + " was created from more then one asset document."); } else if (assetGlobalDetails.size() == 1) { // Find the document associated to that Map<String, String> paramsAssetGlobal = new HashMap<String, String>(); paramsAssetGlobal.put(CamsPropertyConstants.AssetGlobal.DOCUMENT_NUMBER, assetGlobalDetails.iterator().next().getDocumentNumber()); AssetGlobal assetGlobal = (AssetGlobal) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(AssetGlobal.class, paramsAssetGlobal); // Only set it if it is in status approved if (DocumentStatusCodes.APPROVED.equals((assetGlobal.getDocumentHeader().getFinancialDocumentStatusCode()))) { asset.setSeparateHistory(assetGlobal); } } // Else no history, just return } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#getDocumentNumberThatSeparatedThisAsset(java.lang.Long) */ public List<String> getDocumentNumbersThatSeparatedThisAsset(Long capitalAssetNumber) { Map<String, String> paramsAssetGlobal = new HashMap<String, String>(); paramsAssetGlobal.put(CamsPropertyConstants.AssetGlobal.SEPARATE_SOURCE_CAPITAL_ASSET_NUMBER, capitalAssetNumber.toString()); Collection<AssetGlobal> assetGlobals = SpringContext.getBean(BusinessObjectService.class).findMatching(AssetGlobal.class, paramsAssetGlobal); List<String> separateDocumentNumbers = new ArrayList<String>(); for (Iterator<AssetGlobal> assetGlobalIter = assetGlobals.iterator(); assetGlobalIter.hasNext();) { AssetGlobal assetGlobal = assetGlobalIter.next(); if (DocumentStatusCodes.APPROVED.equals(assetGlobal.getDocumentHeader().getFinancialDocumentStatusCode())) { separateDocumentNumbers.add(assetGlobal.getDocumentNumber()); } } return separateDocumentNumbers; } /** * sets the posting year and posting month based on the asset creation date * * @param asset * @return none */ public void setFiscalPeriod(Asset asset) { if (asset.getCreateDate() == null) return; Map<String, Object> primaryKeys = new HashMap<String, Object>(); primaryKeys.put(KFSPropertyConstants.UNIVERSITY_DATE, asset.getCreateDate()); UniversityDate universityDate = (UniversityDate) businessObjectService.findByPrimaryKey(UniversityDate.class, primaryKeys); if (universityDate != null) { asset.setFinancialDocumentPostingYear(universityDate.getUniversityFiscalYear()); asset.setFinancialDocumentPostingPeriodCode(universityDate.getUniversityFiscalAccountingPeriod()); } } public void setBusinessObjectService(BusinessObjectService businessObjectService) { this.businessObjectService = businessObjectService; } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#getCurrentRouteLevels(org.kuali.rice.kew.api.WorkflowDocument) */ public Set<String> getCurrentRouteLevels(WorkflowDocument workflowDocument) { return workflowDocument.getCurrentNodeNames(); } /** * @see org.kuali.kfs.module.cam.document.service.AssetService#isMaintenanceDocumentEnroute(org.kuali.rice.kns.document.MaintenanceDocument) */ public boolean isDocumentEnrouting(Document document) { return document.getDocumentHeader().getWorkflowDocument().isEnroute(); } }