org.kuali.kfs.module.cam.document.validation.impl.AssetRetirementGlobalRule.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.kfs.module.cam.document.validation.impl.AssetRetirementGlobalRule.java

Source

/*
 * 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.validation.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.coa.businessobject.ObjectCode;
import org.kuali.kfs.coa.service.ObjectCodeService;
import org.kuali.kfs.integration.cam.CapitalAssetManagementModuleService;
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.AssetObjectCode;
import org.kuali.kfs.module.cam.businessobject.AssetPayment;
import org.kuali.kfs.module.cam.businessobject.AssetRetirementGlobal;
import org.kuali.kfs.module.cam.businessobject.AssetRetirementGlobalDetail;
import org.kuali.kfs.module.cam.document.gl.AssetRetirementGeneralLedgerPendingEntrySource;
import org.kuali.kfs.module.cam.document.service.AssetObjectCodeService;
import org.kuali.kfs.module.cam.document.service.AssetPaymentService;
import org.kuali.kfs.module.cam.document.service.AssetRetirementService;
import org.kuali.kfs.module.cam.document.service.AssetService;
import org.kuali.kfs.sys.KFSKeyConstants;
import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.document.authorization.FinancialSystemMaintenanceDocumentAuthorizerBase;
import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
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.kns.maintenance.rules.MaintenanceDocumentRuleBase;
import org.kuali.rice.kns.service.DataDictionaryService;
import org.kuali.rice.krad.bo.DocumentHeader;
import org.kuali.rice.krad.bo.PersistableBusinessObject;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.service.DocumentDictionaryService;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.KRADPropertyConstants;
import org.kuali.rice.krad.util.ObjectUtils;

/**
 * Business rules applicable to AssetLocationGlobal documents.
 */
public class AssetRetirementGlobalRule extends MaintenanceDocumentRuleBase {

    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
            .getLogger(AssetRetirementGlobalRule.class);

    protected PersistableBusinessObject bo;

    /**
     * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#setupConvenienceObjects()
     */
    @Override
    public void setupConvenienceObjects() {
        AssetRetirementGlobal newRetirementGlobal = (AssetRetirementGlobal) super.getNewBo();
        newRetirementGlobal.refreshNonUpdateableReferences();
        for (AssetRetirementGlobalDetail detail : newRetirementGlobal.getAssetRetirementGlobalDetails()) {
            detail.refreshNonUpdateableReferences();
        }
    }

    /**
     * Forces the processing of rules when saving.
     *
     * @param document MaintenanceDocument
     * @return boolean true when valid; Namely we need to enforce foreign key constraints else
     *         processCustomSaveDocumentBusinessRules does not force user back to the document for error correction.
     * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#isDocumentValidForSave(org.kuali.rice.kns.document.MaintenanceDocument)
     */
    @Override
    protected boolean isDocumentValidForSave(MaintenanceDocument document) {
        boolean valid = super.isDocumentValidForSave(document);

        if (valid) {
            AssetRetirementGlobal assetRetirementGlobal = (AssetRetirementGlobal) document
                    .getNewMaintainableObject().getBusinessObject();

            setupConvenienceObjects();
            valid &= assetRetirementValidation(assetRetirementGlobal, document);
        }

        return valid;
    }

    /**
     * Processes rules when saving this global.
     *
     * @param document MaintenanceDocument type of document to be processed.
     * @return boolean true when success
     * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
     */
    @Override
    protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
        boolean valid = true;
        AssetRetirementGlobal assetRetirementGlobal = (AssetRetirementGlobal) document.getNewMaintainableObject()
                .getBusinessObject();

        setupConvenienceObjects();
        valid &= assetRetirementValidation(assetRetirementGlobal, document);

        if ((valid && super.processCustomSaveDocumentBusinessRules(document))
                && !getAssetRetirementService().isAssetRetiredByMerged(assetRetirementGlobal)
                && !allPaymentsFederalOwned(assetRetirementGlobal)) {
            // Check if Asset Object Code and Object code exists and active.
            if (valid &= validateObjectCodesForGLPosting(assetRetirementGlobal)) {
                // create poster
                AssetRetirementGeneralLedgerPendingEntrySource assetRetirementGlPoster = new AssetRetirementGeneralLedgerPendingEntrySource(
                        (FinancialSystemDocumentHeader) document.getDocumentHeader());
                // create postables
                getAssetRetirementService().createGLPostables(assetRetirementGlobal, assetRetirementGlPoster);

                if (SpringContext.getBean(GeneralLedgerPendingEntryService.class)
                        .generateGeneralLedgerPendingEntries(assetRetirementGlPoster)) {
                    assetRetirementGlobal
                            .setGeneralLedgerPendingEntries(assetRetirementGlPoster.getPendingEntries());
                } else {
                    assetRetirementGlPoster.getPendingEntries().clear();
                }
            }
        }

        // add doc header description if retirement reason is "MERGED"
        if (CamsConstants.AssetRetirementReasonCode.MERGED
                .equals(assetRetirementGlobal.getRetirementReasonCode())) {
            if (!document.getDocumentHeader().getDocumentDescription().toLowerCase()
                    .contains(CamsConstants.AssetRetirementGlobal.MERGE_AN_ASSET_DESCRIPTION.toLowerCase())) {
                Integer maxDocumentDescription = ddService.getAttributeMaxLength(DocumentHeader.class,
                        KRADPropertyConstants.DOCUMENT_DESCRIPTION);
                String documentDescription = CamsConstants.AssetRetirementGlobal.MERGE_AN_ASSET_DESCRIPTION + " "
                        + document.getDocumentHeader().getDocumentDescription();
                documentDescription = StringUtils.left(documentDescription, maxDocumentDescription);
                document.getDocumentHeader().setDocumentDescription(documentDescription);
            }
        }
        // get asset locks
        List<Long> capitalAssetNumbers = retrieveAssetNumbersForLocking(assetRetirementGlobal);
        valid &= !this.getCapitalAssetManagementModuleService().isAssetLocked(capitalAssetNumbers,
                DocumentTypeName.ASSET_RETIREMENT_GLOBAL, document.getDocumentNumber());

        return valid;
    }

    protected List<Long> retrieveAssetNumbersForLocking(AssetRetirementGlobal assetRetirementGlobal) {
        List<Long> capitalAssetNumbers = new ArrayList<Long>();
        if (getAssetRetirementService().isAssetRetiredByMerged(assetRetirementGlobal)
                && assetRetirementGlobal.getMergedTargetCapitalAssetNumber() != null) {
            capitalAssetNumbers.add(assetRetirementGlobal.getMergedTargetCapitalAssetNumber());
        }

        for (AssetRetirementGlobalDetail retirementDetail : assetRetirementGlobal
                .getAssetRetirementGlobalDetails()) {
            if (retirementDetail.getCapitalAssetNumber() != null) {
                capitalAssetNumbers.add(retirementDetail.getCapitalAssetNumber());
            }
        }
        return capitalAssetNumbers;
    }

    @Override
    protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
        boolean valid = super.processCustomRouteDocumentBusinessRules(document);

        WorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
        // adding asset locks
        if (!GlobalVariables.getMessageMap().hasErrors() && (workflowDoc.isInitiated() || workflowDoc.isSaved())) {
            valid &= setAssetLocks(document);

        }
        return valid;
    }

    protected boolean setAssetLocks(MaintenanceDocument document) {
        AssetRetirementGlobal assetRetirementGlobal = (AssetRetirementGlobal) document.getNewMaintainableObject()
                .getBusinessObject();
        // get asset locks
        return this.getCapitalAssetManagementModuleService().storeAssetLocks(
                retrieveAssetNumbersForLocking(assetRetirementGlobal), document.getDocumentNumber(),
                DocumentTypeName.ASSET_RETIREMENT_GLOBAL, null);
    }

    protected CapitalAssetManagementModuleService getCapitalAssetManagementModuleService() {
        return SpringContext.getBean(CapitalAssetManagementModuleService.class);
    }

    /**
     * Check if all asset payments are federal owned.
     *
     * @param assetRetirementGlobal
     * @return
     */
    protected boolean allPaymentsFederalOwned(AssetRetirementGlobal assetRetirementGlobal) {
        List<AssetRetirementGlobalDetail> assetRetirementGlobalDetails = assetRetirementGlobal
                .getAssetRetirementGlobalDetails();
        for (AssetRetirementGlobalDetail assetRetirementGlobalDetail : assetRetirementGlobalDetails) {
            for (AssetPayment assetPayment : assetRetirementGlobalDetail.getAsset().getAssetPayments()) {
                if (!getAssetPaymentService().isPaymentFederalOwned(assetPayment)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Validate Asset Object Codes and Fin Object Codes eligible for GL Posting.
     *
     * @param assetRetirementGlobal
     * @return
     */
    protected boolean validateObjectCodesForGLPosting(AssetRetirementGlobal assetRetirementGlobal) {
        boolean valid = true;
        List<AssetRetirementGlobalDetail> assetRetirementGlobalDetails = assetRetirementGlobal
                .getAssetRetirementGlobalDetails();
        Asset asset = null;
        List<AssetPayment> assetPayments = null;

        for (AssetRetirementGlobalDetail assetRetirementGlobalDetail : assetRetirementGlobalDetails) {
            asset = assetRetirementGlobalDetail.getAsset();
            assetPayments = asset.getAssetPayments();
            for (AssetPayment assetPayment : assetPayments) {
                if (!getAssetPaymentService().isPaymentFederalOwned(assetPayment)) {
                    // validate Asset Object Code and Financial Object Codes respectively
                    if (valid &= validateAssetObjectCode(asset, assetPayment)) {
                        valid &= validateFinancialObjectCodes(asset, assetPayment);
                    }
                }
            }
        }

        return valid;
    }

    /**
     * Check Financial Object Code for GLPE.
     *
     * @param asset
     * @param assetPayment
     * @return
     */
    protected boolean validateFinancialObjectCodes(Asset asset, AssetPayment assetPayment) {
        AssetPaymentService assetPaymentService = getAssetPaymentService();
        boolean valid = true;
        ObjectCodeService objectCodeService = (ObjectCodeService) SpringContext.getBean(ObjectCodeService.class);
        ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(
                assetPayment.getChartOfAccountsCode(), assetPayment.getFinancialObjectCode());

        AssetObjectCode assetObjectCode = getAssetObjectCodeService().findAssetObjectCode(
                asset.getOrganizationOwnerChartOfAccountsCode(), objectCode.getFinancialObjectSubTypeCode());
        if (assetPaymentService.isPaymentEligibleForCapitalizationGLPosting(assetPayment)) {
            // check for capitalization financial object code existing.
            assetObjectCode
                    .refreshReferenceObject(CamsPropertyConstants.AssetObjectCode.CAPITALIZATION_FINANCIAL_OBJECT);
            valid &= validateFinObjectCodeForGLPosting(asset.getOrganizationOwnerChartOfAccountsCode(),
                    assetObjectCode.getCapitalizationFinancialObjectCode(),
                    assetObjectCode.getCapitalizationFinancialObject(),
                    CamsConstants.GLPostingObjectCodeType.CAPITALIZATION);
        }
        if (assetPaymentService.isPaymentEligibleForAccumDeprGLPosting(assetPayment)) {
            // check for accumulate depreciation financial Object Code existing
            assetObjectCode.refreshReferenceObject(
                    CamsPropertyConstants.AssetObjectCode.ACCUMULATED_DEPRECIATION_FINANCIAL_OBJECT);
            valid &= validateFinObjectCodeForGLPosting(asset.getOrganizationOwnerChartOfAccountsCode(),
                    assetObjectCode.getAccumulatedDepreciationFinancialObjectCode(),
                    assetObjectCode.getAccumulatedDepreciationFinancialObject(),
                    CamsConstants.GLPostingObjectCodeType.ACCUMMULATE_DEPRECIATION);
        }
        if (assetPaymentService.isPaymentEligibleForOffsetGLPosting(assetPayment)) {
            // check for offset financial object code existing.
            valid &= validateFinObjectCodeForGLPosting(asset.getOrganizationOwnerChartOfAccountsCode(),
                    SpringContext.getBean(ParameterService.class).getParameterValueAsString(
                            AssetRetirementGlobal.class,
                            CamsConstants.Parameters.DEFAULT_GAIN_LOSS_DISPOSITION_OBJECT_CODE),
                    getAssetRetirementService()
                            .getOffsetFinancialObject(asset.getOrganizationOwnerChartOfAccountsCode()),
                    CamsConstants.GLPostingObjectCodeType.OFFSET_AMOUNT);
        }
        return valid;
    }

    /**
     * check existence and active status for given financial Object Code BO.
     *
     * @param chartCode
     * @param finObjectCode
     * @param finObject
     * @return
     */
    protected boolean validateFinObjectCodeForGLPosting(String chartOfAccountsCode, String finObjectCode,
            ObjectCode finObject, String glPostingType) {
        boolean valid = true;
        // not defined in Asset Object Code table
        if (StringUtils.isBlank(finObjectCode)) {
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.GLPosting.ERROR_OBJECT_CODE_FROM_ASSET_OBJECT_CODE_NOT_FOUND,
                    new String[] { glPostingType, chartOfAccountsCode });
            valid = false;
        }
        // check Object Code existing
        else if (ObjectUtils.isNull(finObject)) {
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.GLPosting.ERROR_OBJECT_CODE_FROM_ASSET_OBJECT_CODE_INVALID,
                    new String[] { glPostingType, finObjectCode, chartOfAccountsCode });
            valid = false;
        }
        // check Object Code active
        else if (!finObject.isActive()) {
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.GLPosting.ERROR_OBJECT_CODE_FROM_ASSET_OBJECT_CODE_INACTIVE,
                    new String[] { glPostingType, finObjectCode, chartOfAccountsCode });
            valid = false;
        }
        return valid;
    }

    /**
     * Asset Object Code must exist as an active status.
     *
     * @param asset
     * @param assetPayment
     * @return
     */
    protected boolean validateAssetObjectCode(Asset asset, AssetPayment assetPayment) {
        boolean valid = true;
        ObjectCodeService objectCodeService = (ObjectCodeService) SpringContext.getBean(ObjectCodeService.class);
        ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(
                assetPayment.getChartOfAccountsCode(), assetPayment.getFinancialObjectCode());

        AssetObjectCode assetObjectCode = getAssetObjectCodeService().findAssetObjectCode(
                asset.getOrganizationOwnerChartOfAccountsCode(), objectCode.getFinancialObjectSubTypeCode());
        // check Asset Object Code existing.
        if (ObjectUtils.isNull(assetObjectCode)) {
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.GLPosting.ERROR_ASSET_OBJECT_CODE_NOT_FOUND,
                    new String[] { asset.getOrganizationOwnerChartOfAccountsCode(),
                            objectCode.getFinancialObjectSubTypeCode() });
            valid = false;
        }
        // check Asset Object Code active
        else if (!assetObjectCode.isActive()) {
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.GLPosting.ERROR_ASSET_OBJECT_CODE_INACTIVE,
                    new String[] { asset.getOrganizationOwnerChartOfAccountsCode(),
                            objectCode.getFinancialObjectSubTypeCode() });
            valid = false;
        }

        return valid;
    }

    /**
     * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument,
     *      java.lang.String, org.kuali.rice.krad.bo.PersistableBusinessObject)
     */
    @Override
    public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName,
            PersistableBusinessObject line) {
        boolean success = true;
        AssetRetirementGlobalDetail assetRetirementGlobalDetail = (AssetRetirementGlobalDetail) line;
        AssetRetirementGlobal assetRetirementGlobal = (AssetRetirementGlobal) document.getDocumentBusinessObject();

        if (!checkEmptyValue(assetRetirementGlobalDetail.getCapitalAssetNumber())) {
            GlobalVariables.getMessageMap().putError(
                    CamsPropertyConstants.AssetRetirementGlobalDetail.CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_BLANK_CAPITAL_ASSET_NUMBER);
            return false;
        }
        assetRetirementGlobalDetail.refreshReferenceObject(CamsPropertyConstants.AssetLocationGlobalDetail.ASSET);

        if (ObjectUtils.isNull(assetRetirementGlobalDetail.getAsset())) {
            GlobalVariables.getMessageMap().putError(
                    CamsPropertyConstants.AssetRetirementGlobalDetail.CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_INVALID_CAPITAL_ASSET_NUMBER,
                    assetRetirementGlobalDetail.getCapitalAssetNumber().toString());
            return false;
        }

        if (this.getAssetService().isAssetLoaned(assetRetirementGlobalDetail.getAsset())) {
            GlobalVariables.getMessageMap().putError(
                    CamsPropertyConstants.AssetRetirementGlobalDetail.CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_LOANED_ASSET_CANNOT_RETIRED);
            success = false;
        } else if (!getAssetService().isDocumentEnrouting(document)) {
            success &= checkRetirementDetailOneLine(assetRetirementGlobalDetail, assetRetirementGlobal, document);
            success &= checkRetireMultipleAssets(assetRetirementGlobal.getRetirementReasonCode(),
                    assetRetirementGlobal.getAssetRetirementGlobalDetails(), new Integer(0), document);
        }

        // Calculate summary fields in order to show the values even though add new line fails.
        for (AssetRetirementGlobalDetail detail : assetRetirementGlobal.getAssetRetirementGlobalDetails()) {
            getAssetService().setAssetSummaryFields(detail.getAsset());
        }
        return success & super.processCustomAddCollectionLineBusinessRules(document, collectionName, line);
    }

    /**
     * Check if only single asset is allowed to retire.
     *
     * @param retirementReasonCode
     * @param assetRetirementDetails
     * @param maxNumber
     * @param maintenanceDocument
     * @return
     */
    protected boolean checkRetireMultipleAssets(String retirementReasonCode,
            List<AssetRetirementGlobalDetail> assetRetirementDetails, Integer maxNumber,
            MaintenanceDocument maintenanceDocument) {
        boolean success = true;

        if (assetRetirementDetails.size() > maxNumber
                && !getAssetRetirementService().isAllowedRetireMultipleAssets(maintenanceDocument)) {
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.Retirement.ERROR_MULTIPLE_ASSET_RETIRED);
            success = false;
        }

        return success;
    }

    /**
     * This method validates each asset to be retired.
     *
     * @param assetRetirementGlobalDetails
     * @param maintenanceDocument
     * @return
     */
    protected boolean validateRetirementDetails(AssetRetirementGlobal assetRetirementGlobal,
            MaintenanceDocument maintenanceDocument) {
        boolean success = true;

        List<AssetRetirementGlobalDetail> assetRetirementGlobalDetails = assetRetirementGlobal
                .getAssetRetirementGlobalDetails();

        if (assetRetirementGlobalDetails.size() == 0) {
            success = false;
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.Retirement.ERROR_ASSET_RETIREMENT_GLOBAL_NO_ASSET);
        } else {
            // validate each asset retirement detail
            int index = 0;
            for (AssetRetirementGlobalDetail detail : assetRetirementGlobalDetails) {
                String errorPath = MAINTAINABLE_ERROR_PREFIX
                        + CamsPropertyConstants.AssetRetirementGlobal.ASSET_RETIREMENT_GLOBAL_DETAILS + "["
                        + index++ + "]";
                GlobalVariables.getMessageMap().addToErrorPath(errorPath);

                success &= checkRetirementDetailOneLine(detail, assetRetirementGlobal, maintenanceDocument);

                GlobalVariables.getMessageMap().removeFromErrorPath(errorPath);
            }
        }
        return success;
    }

    /**
     * This method validates one asset is a valid asset and no duplicate with target asset when merge.
     *
     * @param assetRetirementGlobalDetail
     * @param assetRetirementGlobal
     * @param maintenanceDocument
     * @return
     */
    protected boolean checkRetirementDetailOneLine(AssetRetirementGlobalDetail assetRetirementGlobalDetail,
            AssetRetirementGlobal assetRetirementGlobal, MaintenanceDocument maintenanceDocument) {
        boolean success = true;

        assetRetirementGlobalDetail.refreshReferenceObject(CamsPropertyConstants.AssetRetirementGlobalDetail.ASSET);

        Asset asset = assetRetirementGlobalDetail.getAsset();

        if (ObjectUtils.isNull(asset)) {
            success = false;
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.Retirement.ERROR_INVALID_CAPITAL_ASSET_NUMBER,
                    assetRetirementGlobalDetail.getCapitalAssetNumber().toString());
        } else {
            success &= validateActiveCapitalAsset(asset);
            success &= validateNonMoveableAsset(asset, maintenanceDocument);

            if (getAssetRetirementService().isAssetRetiredByMerged(assetRetirementGlobal)) {
                success &= validateDuplicateAssetNumber(assetRetirementGlobal.getMergedTargetCapitalAssetNumber(),
                        assetRetirementGlobalDetail.getCapitalAssetNumber());
            }

            // Set asset non persistent fields
            getAssetService().setAssetSummaryFields(asset);
        }

        return success;
    }

    /**
     * Check for Merge Asset, no duplicate capitalAssetNumber between "from" and "to".
     *
     * @param targetAssetNumber
     * @param sourceAssetNumber
     * @return
     */
    protected boolean validateDuplicateAssetNumber(Long targetAssetNumber, Long sourceAssetNumber) {
        boolean success = true;

        if (getAssetService().isCapitalAssetNumberDuplicate(targetAssetNumber, sourceAssetNumber)) {
            GlobalVariables.getMessageMap().putError(
                    CamsPropertyConstants.AssetRetirementGlobalDetail.CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_DUPLICATE_CAPITAL_ASSET_NUMBER_WITH_TARGET,
                    sourceAssetNumber.toString());
            success = false;
        }

        return success;
    }

    /**
     * User must be in work group CM_SUPER_USERS to retire a non-moveable asset.
     *
     * @param asset
     * @param maintenanceDocument
     * @return
     */
    protected boolean validateNonMoveableAsset(Asset asset, MaintenanceDocument maintenanceDocument) {
        boolean success = true;

        FinancialSystemMaintenanceDocumentAuthorizerBase documentAuthorizer = (FinancialSystemMaintenanceDocumentAuthorizerBase) SpringContext
                .getBean(DocumentDictionaryService.class).getDocumentAuthorizer(maintenanceDocument);
        boolean isAuthorized = documentAuthorizer.isAuthorized(maintenanceDocument, CamsConstants.CAM_MODULE_CODE,
                CamsConstants.PermissionNames.RETIRE_NON_MOVABLE_ASSETS,
                GlobalVariables.getUserSession().getPerson().getPrincipalId());

        if (!getAssetService().isAssetMovableCheckByAsset(asset) && !isAuthorized) {
            GlobalVariables.getMessageMap().putError(
                    CamsPropertyConstants.AssetRetirementGlobalDetail.CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_INVALID_USER_GROUP_FOR_NON_MOVEABLE_ASSET,
                    asset.getCapitalAssetNumber().toString());
            success = false;
        }

        return success;
    }

    /**
     * Validate Asset Retirement Global and Details.
     *
     * @param assetRetirementGlobal
     * @param maintenanceDocument
     * @return
     */
    protected boolean assetRetirementValidation(AssetRetirementGlobal assetRetirementGlobal,
            MaintenanceDocument maintenanceDocument) {
        boolean valid = true;

        valid &= validateRequiredGlobalFields(assetRetirementGlobal);
        if (getAssetRetirementService().isAssetRetiredByMerged(assetRetirementGlobal)) {
            valid &= validateMergeTargetAsset(assetRetirementGlobal);
        }

        if (!getAssetService().isDocumentEnrouting(maintenanceDocument)) {
            valid &= validateRetirementDetails(assetRetirementGlobal, maintenanceDocument);
            valid &= checkRetireMultipleAssets(assetRetirementGlobal.getRetirementReasonCode(),
                    assetRetirementGlobal.getAssetRetirementGlobalDetails(), new Integer(1), maintenanceDocument);
        }
        return valid;
    }

    /**
     * Validate mergedTargetCapitalAsset. Only valid and active capital asset is allowed.
     *
     * @param assetRetirementGlobal
     * @return
     */
    protected boolean validateMergeTargetAsset(AssetRetirementGlobal assetRetirementGlobal) {
        boolean valid = true;
        Asset targetAsset = assetRetirementGlobal.getMergedTargetCapitalAsset();
        Long targetAssetNumber = assetRetirementGlobal.getMergedTargetCapitalAssetNumber();

        if (!checkEmptyValue(targetAssetNumber)) {
            putFieldError(CamsPropertyConstants.AssetRetirementGlobal.MERGED_TARGET_CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_BLANK_CAPITAL_ASSET_NUMBER);
            valid = false;
        } else if (ObjectUtils.isNull(targetAsset)) {
            putFieldError(CamsPropertyConstants.AssetRetirementGlobal.MERGED_TARGET_CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_INVALID_MERGED_TARGET_ASSET_NUMBER,
                    targetAssetNumber.toString());
            valid = false;
        } else {
            // Check asset of capital and active
            if (!getAssetService().isCapitalAsset(targetAsset)) {
                putFieldError(CamsPropertyConstants.AssetRetirementGlobal.MERGED_TARGET_CAPITAL_ASSET_NUMBER,
                        CamsKeyConstants.Retirement.ERROR_NON_CAPITAL_ASSET_RETIREMENT,
                        targetAssetNumber.toString());
                valid = false;
            }
            if (getAssetService().isAssetRetired(targetAsset)) {
                putFieldError(CamsPropertyConstants.AssetRetirementGlobal.MERGED_TARGET_CAPITAL_ASSET_NUMBER,
                        CamsKeyConstants.Retirement.ERROR_NON_ACTIVE_ASSET_RETIREMENT,
                        targetAssetNumber.toString());
                valid = false;
            }
        }

        // Validating the mergeAssetDescription is not blank
        if (!checkEmptyValue(assetRetirementGlobal.getMergedTargetCapitalAssetDescription())) {
            String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary()
                    .getBusinessObjectEntry(AssetRetirementGlobal.class.getName())
                    .getAttributeDefinition(
                            CamsPropertyConstants.AssetRetirementGlobal.MERGED_TARGET_CAPITAL_ASSET_DESC)
                    .getLabel();
            putFieldError(CamsPropertyConstants.AssetRetirementGlobal.MERGED_TARGET_CAPITAL_ASSET_DESC,
                    KFSKeyConstants.ERROR_REQUIRED, label);
            valid = false;
        }

        return valid;
    }

    /**
     * Only active capital equipment can be retired using the asset retirement document.
     *
     * @param valid
     * @param detail
     * @return
     */
    protected boolean validateActiveCapitalAsset(Asset asset) {
        boolean valid = true;

        if (!getAssetService().isCapitalAsset(asset)) {
            GlobalVariables.getMessageMap().putError(
                    CamsPropertyConstants.AssetRetirementGlobalDetail.CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_NON_CAPITAL_ASSET_RETIREMENT,
                    asset.getCapitalAssetNumber().toString());
            valid = false;
        } else if (getAssetService().isAssetRetired(asset)) {
            GlobalVariables.getMessageMap().putError(
                    CamsPropertyConstants.AssetRetirementGlobalDetail.CAPITAL_ASSET_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_NON_ACTIVE_ASSET_RETIREMENT,
                    asset.getCapitalAssetNumber().toString());
            valid = false;
        } else if (!this.validateAssetOnLoan(asset)) {
            valid = false;
        }

        return valid;
    }

    /**
     * Validate required fields for given retirement reason code
     *
     * @param assetRetirementGlobal
     * @return
     */
    protected boolean validateRequiredGlobalFields(AssetRetirementGlobal assetRetirementGlobal) {
        boolean valid = true;

        if (getAssetRetirementService().isAssetRetiredBySold(assetRetirementGlobal)) {
            if (StringUtils.isBlank(assetRetirementGlobal.getBuyerDescription())) {
                putFieldError(CamsPropertyConstants.AssetRetirementGlobalDetail.BUYER_DESCRIPTION,
                        CamsKeyConstants.Retirement.ERROR_RETIREMENT_DETAIL_INFO_NULL,
                        new String[] { CamsConstants.RetirementLabel.BUYER_DESCRIPTION,
                                getAssetRetirementService().getAssetRetirementReasonName(assetRetirementGlobal) });
                valid = false;
            }
            if (assetRetirementGlobal.getSalePrice() == null) {
                putFieldError(CamsPropertyConstants.AssetRetirementGlobalDetail.SALE_PRICE,
                        CamsKeyConstants.Retirement.ERROR_RETIREMENT_DETAIL_INFO_NULL,
                        new String[] { CamsConstants.RetirementLabel.SALE_PRICE,
                                getAssetRetirementService().getAssetRetirementReasonName(assetRetirementGlobal) });
                valid = false;
            }
            valid &= validateCashReceiptFinancialDocumentNumber(
                    assetRetirementGlobal.getCashReceiptFinancialDocumentNumber());
        } else if (getAssetRetirementService().isAssetRetiredByAuction(assetRetirementGlobal)) {
            valid = validateCashReceiptFinancialDocumentNumber(
                    assetRetirementGlobal.getCashReceiptFinancialDocumentNumber());
        } else if (getAssetRetirementService().isAssetRetiredByExternalTransferOrGift(assetRetirementGlobal)
                && StringUtils.isBlank(assetRetirementGlobal.getRetirementInstitutionName())) {
            putFieldError(CamsPropertyConstants.AssetRetirementGlobalDetail.RETIREMENT_INSTITUTION_NAME,
                    CamsKeyConstants.Retirement.ERROR_RETIREMENT_DETAIL_INFO_NULL,
                    new String[] { CamsConstants.RetirementLabel.RETIREMENT_INSTITUTION_NAME,
                            getAssetRetirementService().getAssetRetirementReasonName(assetRetirementGlobal) });
            valid = false;
        } else if (getAssetRetirementService().isAssetRetiredByTheft(assetRetirementGlobal)
                && StringUtils.isBlank(assetRetirementGlobal.getPaidCaseNumber())) {
            putFieldError(CamsPropertyConstants.AssetRetirementGlobalDetail.PAID_CASE_NUMBER,
                    CamsKeyConstants.Retirement.ERROR_RETIREMENT_DETAIL_INFO_NULL,
                    new String[] { CamsConstants.RetirementLabel.PAID_CASE_NUMBER,
                            getAssetRetirementService().getAssetRetirementReasonName(assetRetirementGlobal) });
            valid = false;
        }
        return valid;
    }

    /**
     * validates Cash Receipt Financial Document Number
     *
     * @param sharedRetirementInfo
     * @return boolean
     */
    protected boolean validateCashReceiptFinancialDocumentNumber(String documentNumber) {
        boolean valid = true;
        if (StringUtils.isNotBlank(documentNumber)) {
            Map retirementInfoMap = new HashMap();
            retirementInfoMap.put(CamsPropertyConstants.AssetGlobal.DOCUMENT_NUMBER, documentNumber);
            bo = (FinancialSystemDocumentHeader) SpringContext.getBean(BusinessObjectService.class)
                    .findByPrimaryKey(FinancialSystemDocumentHeader.class, retirementInfoMap);
            if (ObjectUtils.isNull(bo)) {
                putFieldError(
                        CamsPropertyConstants.AssetRetirementGlobalDetail.CASH_RECEIPT_FINANCIAL_DOCUMENT_NUMBER,
                        CamsKeyConstants.Retirement.ERROR_INVALID_RETIREMENT_DETAIL_INFO,
                        new String[] { CamsConstants.RetirementLabel.CASH_RECEIPT_FINANCIAL_DOCUMENT_NUMBER,
                                documentNumber });
                valid = false;
            }
        }
        return valid;
    }

    /**
     * Validates whether or not asset is on loan status
     *
     * @param assetRetirementGlobalDetail
     * @return boolean
     */
    protected boolean validateAssetOnLoan(Asset asset) {
        boolean success = true;
        if (this.getAssetService().isAssetLoaned(asset)) {
            GlobalVariables.getMessageMap().putErrorForSectionId(
                    CamsConstants.AssetRetirementGlobal.SECTION_ID_ASSET_DETAIL_INFORMATION,
                    CamsKeyConstants.Retirement.ERROR_LOANED_ASSET_CANNOT_RETIRED);
            success = false;
        }
        return success;
    }

    protected AssetService getAssetService() {
        return SpringContext.getBean(AssetService.class);
    }

    protected AssetRetirementService getAssetRetirementService() {
        return SpringContext.getBean(AssetRetirementService.class);
    }

    protected AssetPaymentService getAssetPaymentService() {
        return SpringContext.getBean(AssetPaymentService.class);
    }

    protected AssetObjectCodeService getAssetObjectCodeService() {
        return SpringContext.getBean(AssetObjectCodeService.class);
    }
}