org.kuali.kra.award.timeandmoney.AwardDirectFandADistributionRuleImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.kra.award.timeandmoney.AwardDirectFandADistributionRuleImpl.java

Source

/*
 * Kuali Coeus, a comprehensive research administration system for higher education.
 * 
 * Copyright 2005-2015 Kuali, Inc.
 * 
 * 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.kra.award.timeandmoney;

import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.kuali.coeus.sys.framework.rule.KcTransactionalDocumentRuleBase;
import org.kuali.coeus.sys.framework.service.KcServiceLocator;
import org.kuali.kra.award.AwardAmountInfoService;
import org.kuali.kra.infrastructure.KeyConstants;
import org.kuali.kra.timeandmoney.service.AwardFnaDistributionService;
import org.kuali.coeus.sys.api.model.ScaleTwoDecimal;
import org.kuali.rice.kns.util.KNSGlobalVariables;

import java.sql.Date;
import java.util.List;

/**
 * This class contains all rule methods for actions on Award Direct F and A Distribution tab.
 */
public class AwardDirectFandADistributionRuleImpl extends KcTransactionalDocumentRuleBase
        implements AwardDirectFandADistributionRule {

    private static final String NEW_AWARD_DIRECT_FNA_DISTRIBUTION = "newAwardDirectFandADistribution";
    private static final String START_DATE_REQUIRED = ".startDateRequired";
    private static final String END_DATE_REQUIRED = ".endDateRequired";
    private static final String DIRECT_COST_REQUIRED = ".directCostRequired";
    private static final String DIRECT_COST_POSITIVE = ".directCostPositive";
    private static final String INDIRECT_COST_REQUIRED = ".indirectCostRequired";
    private static final String INDIRECT_COST_POSITIVE = ".indirectCostPositive";
    private static final String INVALID_DATES = ".invalidDates";
    private static final String OVERLAPPING_DATE_RANGES = ".overlappingDateRanges";
    private static final String INVALID_TARGET_START_DATE = ".invalidStartDate";
    private static final String INVALID_TARGET_END_DATE = ".invalidEndDate";
    private static final String WARNING_AWARD_DIRECT_FNA_DISTRIBUTION_ANTICIPATED_MISMATCH = ".mismatchAnticipated";
    private static final String WARNING_BREAK_DATE_RANGE = ".breakDateRanges";
    AwardDirectFandADistribution awardDirectFandADistribution;
    List<AwardDirectFandADistribution> awardDirectFandADistributions;
    transient AwardAmountInfoService awardAmountInfoService;
    private transient AwardFnaDistributionService awardFnaDistributionService;

    public boolean processAwardDirectFandADistributionBusinessRules(
            AwardDirectFandADistributionRuleEvent awardDirectFandADistributionRuleEvent) {
        this.awardDirectFandADistributions = awardDirectFandADistributionRuleEvent
                .getAwardDirectFandADistributionsForValidation();
        boolean validExistingDateRanges = existingDirectFandADistributionsDatesDontOverlap(
                awardDirectFandADistributions);
        boolean validStartDate = true;
        boolean validEndDate = true;
        boolean validAmounts = existingAmountsAreValid(awardDirectFandADistributions);
        boolean hasTimeAndMoneyBeenSaved = StringUtils
                .isNotBlank(awardDirectFandADistributionRuleEvent.getTimeAndMoneyDocument().getObjectId());
        boolean validTotalAnticipated = doTotalAnticipatedAmountValidOnExistingDistribution(
                awardDirectFandADistributions, hasTimeAndMoneyBeenSaved);
        boolean validConsecutiveDateRange = existingDirectFandADistributionsDatesNoBreak(
                awardDirectFandADistributions);
        if (awardDirectFandADistributions.size() > 0) {
            this.awardDirectFandADistribution = awardDirectFandADistributions.get(0);
            validStartDate = isTargetStartAfterProjectStartDate(awardDirectFandADistributionRuleEvent);
            this.awardDirectFandADistribution = awardDirectFandADistributions
                    .get(awardDirectFandADistributions.size() - 1);
            validEndDate = isTargetEndDatePriorToProjectEndDate(awardDirectFandADistributionRuleEvent);
        }
        return validExistingDateRanges && validStartDate && validEndDate;
    }

    public boolean processAddAwardDirectFandADistributionBusinessRules(
            AwardDirectFandADistributionRuleEvent awardDirectFandADistributionRuleEvent) {
        this.awardDirectFandADistribution = awardDirectFandADistributionRuleEvent
                .getAwardDirectFandADistributionForValidation();
        List<AwardDirectFandADistribution> thisAwardDirectFandADistributions = awardDirectFandADistributionRuleEvent
                .getTimeAndMoneyDocument().getAward().getAwardDirectFandADistributions();

        boolean isValid = true;

        if (!isStartDateEntered())
            isValid = false;
        if (!isEndDateEntered())
            isValid = false;

        // if start or end date is null, skip the remaining date checks
        if (isValid && !isStartDatePriorToEndDate())
            isValid = false;

        if (isValid) {
            boolean validDatePeriod = doTargetDatesFallWithinOpenPeriod(thisAwardDirectFandADistributions)
                    && isTargetStartAfterProjectStartDate(awardDirectFandADistributionRuleEvent)
                    && isTargetEndDatePriorToProjectEndDate(awardDirectFandADistributionRuleEvent);
            if (!validDatePeriod) {
                isValid = false;
            }
        }

        // check cost fields
        if (!isDirectCostValid())
            isValid = false;
        if (!isIndirectCostValid())
            isValid = false;

        return isValid;
    }

    /**
     * This method tests for overlapping dates in existing AwardDirectFandADistribution list on the Award.
     */
    boolean existingDirectFandADistributionsDatesDontOverlap(
            List<AwardDirectFandADistribution> thisAwardDirectFandADistributions) {
        boolean valid = true;
        int currentIndex = 0;
        for (AwardDirectFandADistribution thisAwardDirectFandADistribution : thisAwardDirectFandADistributions) {
            if (thisAwardDirectFandADistribution.getStartDate()
                    .after(thisAwardDirectFandADistribution.getEndDate())) {
                valid = false;
                reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INVALID_DATES,
                        KeyConstants.ERROR_AWARD_FANDA_DISTRIB_START_BEFORE_END_DATE);
                break;
            } else if (targetOverlapsWithExistingPeriods(thisAwardDirectFandADistribution,
                    thisAwardDirectFandADistributions, currentIndex)) {
                valid = false;
                reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INVALID_DATES,
                        KeyConstants.ERROR_OVERLAPPING_EXISTING_DATES);
                break;
            }
            currentIndex++;
        }
        return valid;
    }

    /**
     * This method tests for break in date ranges of existing AwardDirectFandADistribution list on the Award.
     */
    boolean existingDirectFandADistributionsDatesNoBreak(
            List<AwardDirectFandADistribution> thisAwardDirectFandADistributions) {
        boolean valid = true;
        int currentIndex = 0;
        for (AwardDirectFandADistribution thisAwardDirectFandADistribution : thisAwardDirectFandADistributions) {
            if (currentIndex < thisAwardDirectFandADistributions.size() - 1) {
                AwardDirectFandADistribution nextAwardDirectFandADistribution = thisAwardDirectFandADistributions
                        .get(++currentIndex);
                if (DateUtils.addDays(thisAwardDirectFandADistribution.getEndDate(), 1)
                        .before(nextAwardDirectFandADistribution.getStartDate())) {
                    reportWarning(WARNING_BREAK_DATE_RANGE, KeyConstants.WARNING_AWARD_FANDA_DISTRIB_BREAKS);
                    KNSGlobalVariables.getMessageList().add(KeyConstants.WARNING_AWARD_FANDA_DISTRIB_EXISTS, "");
                    valid = false;
                }
            }
        }
        return valid;
    }

    /**
     * This is a helper method for doExistingFandADistributionDatesOverlap.
     */
    boolean targetOverlapsWithExistingPeriods(AwardDirectFandADistribution thisAwardDirectFandADistribution,
            List<AwardDirectFandADistribution> thisAwardDirectFandADistributions, int currentIndex) {
        boolean invalid = false;
        Date testStartDate;
        Date testEndDate;
        Date startDate = thisAwardDirectFandADistribution.getStartDate();
        Date endDate = thisAwardDirectFandADistribution.getEndDate();
        int newCurrentIndex = 0;
        for (AwardDirectFandADistribution testAwardDirectFandADistribution : thisAwardDirectFandADistributions) {
            testStartDate = testAwardDirectFandADistribution.getStartDate();
            testEndDate = testAwardDirectFandADistribution.getEndDate();
            if (newCurrentIndex != currentIndex) {
                if (startDate.before(testEndDate) && startDate.after(testStartDate)
                        || endDate.after(testStartDate) && endDate.before(testEndDate)
                        || startDate.equals(testEndDate) || endDate.equals(testStartDate)) {
                    invalid = true;
                    break;
                }
            }
            newCurrentIndex++;
        }
        return invalid;
    }

    /**
     * This method checks whether the user provided a start date
     */
    private boolean isStartDateEntered() {
        boolean valid = true;
        if (awardDirectFandADistribution.getStartDate() == null) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + START_DATE_REQUIRED,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_START_DATE_REQUIRED);
        }
        return valid;
    }

    /**
     * This method checks whether the user provided a end date
     */
    private boolean isEndDateEntered() {
        boolean valid = true;
        if (awardDirectFandADistribution.getEndDate() == null) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + END_DATE_REQUIRED,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_END_DATE_REQUIRED);
        }
        return valid;
    }

    private boolean existingAmountsAreValid(List<AwardDirectFandADistribution> thisAwardDirectFandADistributions) {
        boolean valid = true;
        for (AwardDirectFandADistribution awardDirectFandADistribution : thisAwardDirectFandADistributions) {
            if (!isDirectCostValidOnExistingDistribution(awardDirectFandADistribution)) {
                valid = false;
            }
            if (!isIndirectCostValidOnExistingDistribution(awardDirectFandADistribution)) {
                valid = false;
            }
        }
        return valid;
    }

    /**
     * This method checks whether the user provided a valid Direct Cost amount
     */
    private boolean isDirectCostValidOnExistingDistribution(
            AwardDirectFandADistribution thisAwardDirectFandADistribution) {
        boolean valid = true;
        ScaleTwoDecimal directCost = thisAwardDirectFandADistribution.getDirectCost();
        if (directCost == null) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + DIRECT_COST_REQUIRED,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_DIRECT_COST_REQUIRED);
        } else if (directCost.isNegative()) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + DIRECT_COST_POSITIVE,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_DIRECT_COST_NEGATIVE);
        }
        return valid;
    }

    private boolean doTotalAnticipatedAmountValidOnExistingDistribution(
            List<AwardDirectFandADistribution> thisAwardDirectFandADistributions,
            boolean hasTimeAndMoneyBeenSaved) {
        if (getAwardFnaDistributionService().disableFAndADistributionEqualityValidation()) {
            return true;
        }
        boolean valid = false;
        ScaleTwoDecimal awardAnticipatedTotal = ScaleTwoDecimal.ZERO;
        ScaleTwoDecimal calculatedFNAAmount = ScaleTwoDecimal.ZERO;
        ScaleTwoDecimal calculatedDirAmount = ScaleTwoDecimal.ZERO;
        if (awardDirectFandADistributions.size() > 0) {
            awardAnticipatedTotal = awardDirectFandADistributions.get(0).getAward().getAnticipatedTotal();
            for (AwardDirectFandADistribution awardDirectFandADistribution : thisAwardDirectFandADistributions) {
                calculatedFNAAmount = calculatedFNAAmount.add(awardDirectFandADistribution.getDirectCost());
                calculatedDirAmount = calculatedDirAmount.add(awardDirectFandADistribution.getIndirectCost());
            }
            if (awardAnticipatedTotal.equals(calculatedFNAAmount.add(calculatedDirAmount))) {
                valid = true;
            } else {
                if (getAwardFnaDistributionService().displayAwardFAndADistributionEqualityValidationAsError()) {
                    if (hasTimeAndMoneyBeenSaved) {
                        reportError(WARNING_AWARD_DIRECT_FNA_DISTRIBUTION_ANTICIPATED_MISMATCH,
                                KeyConstants.WARNING_AWARD_FANDA_DISTRIB_LIMITNOTEQUAL_ANTICIPATED,
                                new String[] { awardDirectFandADistributions.get(0).getAward().getAwardNumber() });
                        KNSGlobalVariables.getMessageList().add(KeyConstants.WARNING_AWARD_FANDA_DISTRIB_EXISTS,
                                "");
                    }
                } else if (getAwardFnaDistributionService()
                        .displayAwardFAndADistributionEqualityValidationAsWarning()) {
                    reportWarning(WARNING_AWARD_DIRECT_FNA_DISTRIBUTION_ANTICIPATED_MISMATCH,
                            KeyConstants.WARNING_AWARD_FANDA_DISTRIB_LIMITNOTEQUAL_ANTICIPATED,
                            new String[] { awardDirectFandADistributions.get(0).getAward().getAwardNumber() });
                    KNSGlobalVariables.getMessageList().add(KeyConstants.WARNING_AWARD_FANDA_DISTRIB_EXISTS, "");
                } else {
                    //no validation warning
                    valid = true;
                }
            }
        }
        return valid;
    }

    protected AwardFnaDistributionService getAwardFnaDistributionService() {
        if (awardFnaDistributionService == null) {
            awardFnaDistributionService = KcServiceLocator.getService(AwardFnaDistributionService.class);
        }
        return awardFnaDistributionService;
    }

    /**
     * This method checks whether the user provided a valid Indirect Cost amount
     */
    private boolean isIndirectCostValidOnExistingDistribution(
            AwardDirectFandADistribution thisAwardDirectFandADistribution) {
        boolean valid = true;
        ScaleTwoDecimal indirectCost = thisAwardDirectFandADistribution.getIndirectCost();
        if (indirectCost == null) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INDIRECT_COST_REQUIRED,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_INDIRECT_COST_REQUIRED);
        } else if (indirectCost.isNegative()) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INDIRECT_COST_POSITIVE,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_INDIRECT_COST_POSITIVE);
        }
        return valid;
    }

    /**
     * This method checks whether the user provided a valid Direct Cost amount
     */
    private boolean isDirectCostValid() {
        boolean valid = true;
        ScaleTwoDecimal directCost = awardDirectFandADistribution.getDirectCost();
        if (directCost == null) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + DIRECT_COST_REQUIRED,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_DIRECT_COST_REQUIRED);
        } else if (!directCost.isPositive()) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + DIRECT_COST_POSITIVE,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_DIRECT_COST_POSITIVE);
        }
        return valid;
    }

    /**
     * This method checks whether the user provided a valid Indirect Cost amount
     */
    private boolean isIndirectCostValid() {
        boolean valid = true;
        ScaleTwoDecimal indirectCost = awardDirectFandADistribution.getIndirectCost();
        if (indirectCost == null) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INDIRECT_COST_REQUIRED,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_INDIRECT_COST_REQUIRED);
        } else if (indirectCost.isNegative()) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INDIRECT_COST_POSITIVE,
                    KeyConstants.ERROR_AWARD_FANDA_DISTRIB_INDIRECT_COST_POSITIVE);
        }
        return valid;
    }

    /**
     * This method tests that the period start date is prior to the period end date.
     */
    boolean isStartDatePriorToEndDate() {
        boolean valid = true;
        if (awardDirectFandADistribution.getStartDate()
                .compareTo(awardDirectFandADistribution.getEndDate()) != -1) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INVALID_DATES,
                    KeyConstants.ERROR_START_DATE_PRECEDES_END_DATE);
        }
        return valid;
    }

    /**
     * This method tests that the target date range falls into an open date range.
     */
    boolean doTargetDatesFallWithinOpenPeriod(
            List<AwardDirectFandADistribution> thisAwardDirectFandADistributions) {
        boolean valid = true;
        for (AwardDirectFandADistribution testAwardDirectFandADistribution : thisAwardDirectFandADistributions) {
            if (doDateRangesOverlap(testAwardDirectFandADistribution, awardDirectFandADistribution)) {
                valid = false;
                reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + OVERLAPPING_DATE_RANGES,
                        KeyConstants.ERROR_OVERLAPPING_DATE_RANGES);
            }
        }
        return valid;
    }

    /**
     * This is a helper method for doTargetDatesFallWithinOpenPeriod.
     */
    boolean doDateRangesOverlap(AwardDirectFandADistribution testAwardDirectFandADistribution,
            AwardDirectFandADistribution thisAwardDirectFandADistribution) {
        Date testStartDate = testAwardDirectFandADistribution.getStartDate();
        Date testEndDate = testAwardDirectFandADistribution.getEndDate();
        Date startDate = thisAwardDirectFandADistribution.getStartDate();
        Date endDate = thisAwardDirectFandADistribution.getEndDate();
        return startDate.before(testEndDate) && startDate.after(testStartDate)
                || endDate.after(testStartDate) && endDate.before(testEndDate);
    }

    /**
     * This method tests if target start date falls after project start date.
     */
    boolean isTargetStartAfterProjectStartDate(
            AwardDirectFandADistributionRuleEvent awardDirectFandADistributionRuleEvent) {
        Date targetStartDate = awardDirectFandADistribution.getStartDate();
        Date projectStartDate = awardDirectFandADistributionRuleEvent.getTimeAndMoneyDocument().getAward()
                .getAwardEffectiveDate();
        boolean valid = true;
        if (!(projectStartDate == null)) {
            if (projectStartDate.after(targetStartDate)) {
                valid = false;
                reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INVALID_TARGET_START_DATE,
                        KeyConstants.ERROR_TARGET_START_DATE);
            }
        }
        return valid;
    }

    /**
     * This method tests if target end date falls before project end date.
     */
    boolean isTargetEndDatePriorToProjectEndDate(
            AwardDirectFandADistributionRuleEvent awardDirectFandADistributionRuleEvent) {
        Date targetEndDate = awardDirectFandADistribution.getEndDate();
        //Date projectEndDate = awardDirectFandADistributionRuleEvent.getTimeAndMoneyDocument().getAward().getProjectEndDate();
        Date projectEndDate = getAwardAmountInfoService().fetchAwardAmountInfoWithHighestTransactionId(
                awardDirectFandADistributionRuleEvent.getTimeAndMoneyDocument().getAward().getAwardAmountInfos())
                .getFinalExpirationDate();
        boolean valid = true;
        if (projectEndDate.before(targetEndDate)) {
            valid = false;
            reportError(NEW_AWARD_DIRECT_FNA_DISTRIBUTION + INVALID_TARGET_END_DATE,
                    KeyConstants.ERROR_TARGET_END_DATE);

        }
        return valid;
    }

    public AwardAmountInfoService getAwardAmountInfoService() {
        awardAmountInfoService = KcServiceLocator.getService(AwardAmountInfoService.class);
        return awardAmountInfoService;
    }

    /**
     * Gets the awardDirectFandADistribution attribute. 
     * @return Returns the awardDirectFandADistribution.
     */
    public AwardDirectFandADistribution getAwardDirectFandADistribution() {
        return awardDirectFandADistribution;
    }

    /**
     * Sets the awardDirectFandADistribution attribute value.
     * @param awardDirectFandADistribution The awardDirectFandADistribution to set.
     */
    public void setAwardDirectFandADistribution(AwardDirectFandADistribution awardDirectFandADistribution) {
        this.awardDirectFandADistribution = awardDirectFandADistribution;
    }

    /**
     * Gets the awardDirectFandADistributions attribute. 
     * @return Returns the awardDirectFandADistributions.
     */
    public List<AwardDirectFandADistribution> getAwardDirectFandADistributions() {
        return awardDirectFandADistributions;
    }

    /**
     * Sets the awardDirectFandADistributions attribute value.
     * @param awardDirectFandADistributions The awardDirectFandADistributions to set.
     */
    public void setAwardDirectFandADistributions(List<AwardDirectFandADistribution> awardDirectFandADistributions) {
        this.awardDirectFandADistributions = awardDirectFandADistributions;
    }

}