org.kuali.coeus.propdev.impl.krms.PropDevJavaFunctionKrmsTermServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.coeus.propdev.impl.krms.PropDevJavaFunctionKrmsTermServiceImpl.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.coeus.propdev.impl.krms;

import java.sql.Date;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.kuali.coeus.common.framework.person.attr.PersonAppointment;
import org.kuali.coeus.common.framework.sponsor.hierarchy.SponsorHierarchy;
import org.kuali.coeus.common.framework.unit.Unit;
import org.kuali.coeus.common.framework.unit.UnitService;
import org.kuali.coeus.common.framework.unit.admin.UnitAdministrator;
import org.kuali.coeus.propdev.impl.core.ProposalDevelopmentDocument;
import org.kuali.coeus.propdev.impl.core.ProposalDevelopmentUtils;
import org.kuali.coeus.propdev.impl.core.ProposalTypeService;
import org.kuali.coeus.common.framework.compliance.core.SpecialReviewApprovalType;
import org.kuali.coeus.common.framework.compliance.core.SpecialReviewType;
import org.kuali.coeus.common.budget.framework.core.Budget;
import org.kuali.coeus.common.budget.framework.nonpersonnel.BudgetLineItem;
import org.kuali.coeus.common.budget.framework.period.BudgetPeriod;
import org.kuali.coeus.common.budget.framework.personnel.AppointmentType;
import org.kuali.coeus.sys.framework.gv.GlobalVariableService;
import org.kuali.kra.infrastructure.Constants;
import org.kuali.coeus.common.impl.krms.KcKrmsJavaFunctionTermServiceBase;
import org.kuali.coeus.propdev.impl.core.DevelopmentProposal;
import org.kuali.coeus.propdev.impl.attachment.Narrative;
import org.kuali.coeus.propdev.impl.person.ProposalPerson;
import org.kuali.coeus.propdev.impl.person.attachment.ProposalPersonBiography;
import org.kuali.coeus.propdev.impl.person.ProposalPersonUnit;
import org.kuali.coeus.propdev.impl.budget.subaward.BudgetSubAwards;
import org.kuali.coeus.propdev.impl.person.question.ProposalPersonModuleQuestionnaireBean;
import org.kuali.coeus.propdev.impl.specialreview.ProposalSpecialReview;
import org.kuali.coeus.common.questionnaire.framework.answer.AnswerHeader;
import org.kuali.coeus.common.questionnaire.framework.answer.QuestionnaireAnswerService;
import org.kuali.coeus.propdev.impl.s2s.S2sOppForms;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.kew.api.action.ActionRequest;
import org.kuali.rice.kim.api.identity.Person;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("propDevJavaFunctionKrmsTermService")
public class PropDevJavaFunctionKrmsTermServiceImpl extends KcKrmsJavaFunctionTermServiceBase
        implements PropDevJavaFunctionKrmsTermService {

    private static final int INT_U_S_CITIZEN_OR_NONCITIZEN_NATIONAL = 1;
    private static final int INT_PERMANENT_RESIDENT_OF_U_S = 2;
    private static final int INT_NON_U_S_CITIZEN_WITH_TEMPORARY_VISA = 3;
    private static final int INT_PERMANENT_RESIDENT_OF_U_S_PENDING = 4;
    private static final Log LOG = LogFactory.getLog(PropDevJavaFunctionKrmsTermServiceImpl.class);

    @Autowired
    @Qualifier("dateTimeService")
    private DateTimeService dateTimeService;

    @Autowired
    @Qualifier("questionnaireAnswerService")
    private QuestionnaireAnswerService questionnaireAnswerService;

    @Autowired
    @Qualifier("unitService")
    private UnitService unitService;

    @Autowired
    @Qualifier("globalVariableService")
    private GlobalVariableService globalVariableService;

    @Autowired
    @Qualifier("proposalTypeService")
    private ProposalTypeService proposalTypeService;

    /**
     * 
     * This method checks if the formName is included in the given proposal
     * @return 'true' if true
     */
    @Override
    public Boolean specifiedGGForm(DevelopmentProposal developmentProposal, String formNames) {
        for (String formName : buildArrayFromCommaList(formNames)) {
            for (S2sOppForms s2sOppForm : developmentProposal.getS2sOppForms()) {
                if (s2sOppForm.getInclude() != null && s2sOppForm.getInclude()
                        && s2sOppForm.getFormName().equals(formName.trim())) {
                    return Boolean.TRUE;
                }
            }
        }
        return Boolean.FALSE;
    }

    /**
     * This method checks if the proposal has multiple PIs set.
     * see FN_MULTIPI_RULE.
     * @return 'true' if true
     */
    @Override
    public String multiplePI(DevelopmentProposal developmentProposal) {
        List<ProposalPerson> people = developmentProposal.getProposalPersons();
        for (ProposalPerson person : people) {
            if (person.isMultiplePi()) {
                return TRUE;
            }
        }
        return FALSE;

    }

    /**
     * 
     * This method checks if the passed in forms are included.
     * see FN_S2S_BUDGET_RULE.
     * @param formNames a comma delimited list of s2s forms to check against.
     * @return 'true' if true
     */
    @Override
    public String s2sBudgetRule(DevelopmentProposal developmentProposal, String formNames) {
        /**
         * F.FORM_NAME in ('RR Budget V1-1','RR SubAward Budget V1.2','RR_FedNonFed_SubawardBudget-V1.2',
         * 'RR_FedNonFed_SubawardBudget-V1.1','RR SubAward Budget V1.1','PHS398 Modular Budget V1-1', 'PHS398 Modular Budget V1-2')
         */
        String[] formNamesArray = buildArrayFromCommaList(formNames);
        int li_count_bud = 0;
        for (String formName : formNamesArray) {
            for (S2sOppForms form : developmentProposal.getS2sOppForms()) {
                if (StringUtils.equalsIgnoreCase(formName, form.getFormName()) && form.getInclude()) {
                    li_count_bud++;
                }
            }
        }
        int li_count_s2s = developmentProposal.getS2sOpportunity() != null ? 1 : 0;

        if (li_count_bud != 0 && li_count_s2s <= 0) {
            return TRUE;
        }
        return FALSE;
    }

    /**
     * 
     * This method checks if the proposal is associated with one of monitored sponsored hierarchies. 
     * see FN_COI_MONITORED_SPONSOR_RULE.
     * @param monitoredSponsorHirearchies a comma delimited list of sponsored hirearchies.
     * @return 'true' if true
     */
    @Override
    public String monitoredSponsorRule(DevelopmentProposal developmentProposal,
            String monitoredSponsorHirearchies) {
        String[] sponsoredHierarchyArray = buildArrayFromCommaList(monitoredSponsorHirearchies);
        ArrayList<SponsorHierarchy> hierarchies = new ArrayList<>();
        for (String hierarchyName : sponsoredHierarchyArray) {
            Map<String, String> fieldValues = new HashMap<>();
            fieldValues.put("HIERARCH_NAME", hierarchyName);
            hierarchies.addAll(this.getBusinessObjectService().findMatching(SponsorHierarchy.class, fieldValues));
        }
        for (SponsorHierarchy sh : hierarchies) {
            if (StringUtils.equalsIgnoreCase(sh.getSponsorCode(), developmentProposal.getSponsor().getSponsorCode())
                    || StringUtils.equalsIgnoreCase(sh.getSponsorCode(),
                            developmentProposal.getPrimeSponsor().getSponsorCode())) {
                return TRUE;
            }
        }

        return FALSE;
    }

    /**
     * 
     * This method determines if the proposal has more than the maximum number of attachments of the types provided in the narativeTypes list.
     * see FN_S2S_RESPLAN_RULE.
     * @param narativeTypes a comma delimited list of narrative types.
     * @param maxNumber the maximum number to check.
     * @return 'true' if true
     */
    @Override
    public String s2sResplanRule(DevelopmentProposal developmentProposal, String narativeTypes, String maxNumber) {
        //- max of 10 narrative types PHS_ResearchPlan_Appendix
        String[] narrativeTypesArray = buildArrayFromCommaList(narativeTypes);
        int[] narrativeCounts = new int[narrativeTypesArray.length];
        int maxNumberInt = Integer.parseInt(maxNumber);
        for (Narrative narrative : developmentProposal.getNarratives()) {
            int narrativePosition = 0;
            for (String narrativeType : narrativeTypesArray) {
                if (StringUtils.equalsIgnoreCase(narrativeType, narrative.getNarrativeType().getDescription())) {
                    narrativeCounts[narrativePosition]++;
                    if (narrativeCounts[narrativePosition] > maxNumberInt) {
                        return TRUE;
                    }
                }
                narrativePosition++;
            }
        }
        return FALSE;
    }

    /**
     * 
     * This method checks if the proposal is associated the grants form passed in. 
     * see FN_GG_FORM_RULE.
     * @param formName the grants form to check against.
     * @return 'true' if true
     */
    @Override
    public String grantsFormRule(DevelopmentProposal developmentProposal, String formName) {
        for (S2sOppForms form : developmentProposal.getS2sOppForms()) {
            if (StringUtils.equalsIgnoreCase(formName, form.getFormName())) {
                return TRUE;
            }
        }
        return FALSE;
    }

    /**
     * 
     * This method checks to see if the biosketch file names contain any restricted special characters.
     * See  fn_prop_pers_att_name_rule 
     * @return 'true' if no special characters are found.
     */
    @Override
    public String biosketchFileNameRule(DevelopmentProposal developmentProposal) {
        for (ProposalPersonBiography ppb : developmentProposal.getPropPersonBios()) {
            if (StringUtils.equalsIgnoreCase(ppb.getPropPerDocType().getDescription(), "Biosketch")) {
                if (StringUtils.equals(FALSE, specialCharacterRule(ppb.getName()))) {
                    return FALSE;
                }
            }
        }
        return TRUE;

    }

    /**
     * 
     * This method checks to see if the OSP administrator is also a personal person.
     * See  FN_OSP_ADMIN_IS_PERSON 
     * @return 'true' if the OSP admin is also a proposal person, otherwise 'false'
     */
    @Override
    public String ospAdminPropPersonRule(DevelopmentProposal developmentProposal) {
        List<UnitAdministrator> ospAdmins = developmentProposal.getUnit().getUnitAdministrators();
        if (ospAdmins != null && ospAdmins.size() > 0) {
            for (ProposalPerson person : developmentProposal.getProposalPersons()) {
                for (UnitAdministrator admin : ospAdmins) {
                    if (StringUtils.equals(person.getPersonId(), admin.getPersonId())) {
                        return TRUE;
                    }
                }
            }
        }
        return FALSE;
    }

    /**
     * 
     * This method is used to check if , in any period of the given version of budget, the given cost element has crossed the given limit or not.
     * See  fn_cost_element_ver_per_limit  AND fn_cost_element_limit_in_ver
     * @param versionNumber the version number to be checked
     * @param costElementName the cost element to be checked
     * @param limit the amount limit to be checked
     * @return 'true' - if the total cost of the CE crossed the limit in any one of the period, otherwise 'false'
     */
    @Override
    public String costElementVersionLimit(DevelopmentProposal developmentProposal, String versionNumber,
            String costElementName, String limit) {
        Long versionNumberLong = Long.parseLong(versionNumber);
        float limitLong = Float.parseFloat(limit);
        for (Budget budget : developmentProposal.getBudgets()) {
            if (budget.getVersionNumber().equals(versionNumberLong)) {
                try {
                    if (budget.getVersionNumber().equals(versionNumberLong)) {
                        for (BudgetPeriod period : budget.getBudgetPeriods()) {
                            float costElementTotal = 0;
                            for (BudgetLineItem item : period.getBudgetLineItems()) {
                                if (StringUtils.equalsIgnoreCase(costElementName, item.getCostElementName())) {
                                    costElementTotal = costElementTotal + item.getLineItemCost().floatValue();
                                }
                            }
                            if (costElementTotal > limitLong) {
                                return TRUE;
                            }
                        }
                    }
                } catch (Exception e) {
                    //lets just ignor and return false.
                }
            }
        }
        return FALSE;
    }

    /**
     * 
     * This method is used to CHECK IF a proposal's division code field  is  null
     * See  fn_agency_divcode_is_null_rule 
     * @return 'true' - if the division field is null, otherwise return false.
     */
    @Override
    public String divisionCodeRule(DevelopmentProposal developmentProposal) {
        return StringUtils.isEmpty(developmentProposal.getAgencyDivisionCode()) ? TRUE : FALSE;
    }

    /**
     * 
     * This method is used to CHECK IF THIS PROPOSAL IS FOR A FELLOWSHIP.  Typically 3 or 7 is a fellowship code.
     * See  FN_IS_FELLOWSHIP 
     * @return 'true' - if the division field is a fellowship code, otherwise return false.
     */
    @Override
    public String divisionCodeIsFellowship(DevelopmentProposal developmentProposal, String fellowshipCodes) {
        String[] fellowShipCodeArray = buildArrayFromCommaList(fellowshipCodes);
        for (String code : fellowShipCodeArray) {
            if (StringUtils.equalsIgnoreCase(code, developmentProposal.getActivityTypeCode())) {
                return TRUE;
            }
        }
        return FALSE;
    }

    /**
     * 
     * This method is used to check if a budget sub award organization name contains special characters.  
     * See  fn_sub_awd_org_name_rule  
     * @return 'true' - if it does not contain special characters.  If it does have special characters, otherwise returns 'false'.
     */
    @Override
    public String budgetSubawardOrganizationnameRule(DevelopmentProposal developmentProposal) {
        if (developmentProposal.getFinalBudget() != null) {
            for (BudgetSubAwards bsa : developmentProposal.getFinalBudget().getBudgetSubAwards()) {
                if (StringUtils.equals(FALSE, specialCharacterRule(bsa.getOrganizationName()))) {
                    return FALSE;
                }
            }
        }
        return TRUE;
    }

    /**
     * 
     * This method is used to check if the passed in personId, is among the proposal people.  
     * See FN_CHECK_PROPOSAL_KEY_PERSON   
     * @return 'true' - if the logged in user is a proposal person, otherwise returns 'false'.
     */
    @Override
    public String checkProposalPerson(DevelopmentProposal developmentProposal, String personId) {
        for (ProposalPerson person : developmentProposal.getProposalPersons()) {
            if (StringUtils.equals(person.getPersonId(), personId)) {
                return TRUE;
            }
        }
        return FALSE;
    }

    /**
     * 
     * This method is a rule to CHECK IF a proposal's agency program code field  is  null  
     * See fn_ag_progcode_is_null_rule   
     * @return 'true' - if the agency program code is NULL, otherwise returns 'false'.
     */
    @Override
    public String agencyProgramCodeNullRule(DevelopmentProposal developmentProposal) {
        return StringUtils.isEmpty(developmentProposal.getAgencyProgramCode()) ? TRUE : FALSE;
    }

    /**
     * 
     * This method returns 'true', and is implemented because the original function existed.  
     * See FN_ALL_PROPOSALS_RULE   
     * @return 'true' always
     */
    @Override
    public String allProposalsRule(DevelopmentProposal developmentProposal) {
        return TRUE;
    }

    /**
     * 
     * This method checks to see if the proposal lead unit is in the unit hierarchy of the passed in unit.  
     * See FN_LEAD_UNIT_BELOW   
     * @return 'true' if the lead unit is in the unit hiearchy of the passed in unit, otherwise returns 'false'.
     */
    @Override
    public String proposalLeadUnitInHierarchy(DevelopmentProposal developmentProposal, String unitNumberToCheck) {
        if (StringUtils.equals(developmentProposal.getUnitNumber(), unitNumberToCheck)) {
            return TRUE;
        }
        List<Unit> units = this.getUnitService().getAllSubUnits(unitNumberToCheck);
        if (units != null && units.size() > 0) {
            for (Unit unit : units) {
                if (StringUtils.equals(developmentProposal.getUnitNumber(), unit.getUnitNumber())) {
                    return TRUE;
                }
            }
        }
        return FALSE;
    }

    /**
     * 
     * This method verifies that there is not both a restricted set of RR forms along with PHS forms.  
     * See FN_S2S_SUBAWARD_RULE   
     * @return 'true' if there are RR forms and PHS forms, otherwise returns 'false'.
     */
    @Override
    public String s2sSubawardRule(DevelopmentProposal developmentProposal, String rrFormNames,
            String phsFromNames) {

        /**
         * And     F.FORM_NAME in ('RR SubAward Budget V1.2','RR_FedNonFed_SubawardBudget-V1.2',
         * 'RR_FedNonFed_SubawardBudget-V1.1','RR SubAward Budget V1.1')
         * 
         * And     F.FORM_NAME in ('PHS398 Modular Budget V1-1','PHS398 Modular Budget V1-0', 'PHS398 Modular Budget V1-2')
         */

        boolean foundRRforms = false;
        boolean foundPHSforms = false;
        String[] rrFormNamesArray = buildArrayFromCommaList(rrFormNames);
        String[] phsFromNamesArray = buildArrayFromCommaList(phsFromNames);

        for (S2sOppForms form : developmentProposal.getS2sOppForms()) {
            if (form.getInclude()) {
                for (String formName : rrFormNamesArray) {
                    if (StringUtils.equalsIgnoreCase(formName, form.getFormName())) {
                        foundRRforms = true;
                    }
                }
                for (String formName : phsFromNamesArray) {
                    if (StringUtils.equalsIgnoreCase(formName, form.getFormName())) {
                        foundPHSforms = true;
                    }
                }
            }
        }
        return foundRRforms && foundPHSforms ? TRUE : FALSE;
    }

    /**
     * 
     * This method verifies that there are grans.gov submissions.  
     * See FN_IS_GG_RULE   
     * @return 'true' if there are grants.gov submssion, otherwise returns 'false'.
     */
    @Override
    public String proposalGrantsRule(DevelopmentProposal developmentProposal) {
        return developmentProposal.getS2sOpportunity() != null ? TRUE : FALSE;
    }

    /**
     * 
     * This method verifies that the activity type is specified.  
     * See FN_NARRATIVE_TYPE_RULE   
     * @return 'true' if there an activity type, otherwise returns 'false'.
     */
    @Override
    public String narrativeTypeRule(DevelopmentProposal developmentProposal, String narrativeTypeCode) {
        List<Narrative> attachments = new ArrayList<>();
        attachments.addAll(developmentProposal.getNarratives());
        attachments.addAll(developmentProposal.getInstituteAttachments());
        for (Narrative narrative : attachments) {
            if (narrative.getNarrativeTypeCode().equals(narrativeTypeCode)) {
                return TRUE;
            }
        }
        return FALSE;
    }

    @Override
    public String activityTypeRule(DevelopmentProposal developmentProposal, String activityTypeCode) {
        if (StringUtils.equals(developmentProposal.getActivityTypeCode(), activityTypeCode)) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    @Override
    public String attachmentFileNameRule(DevelopmentProposal developmentProposal) {
        for (Narrative narr : developmentProposal.getNarratives()) {
            for (String character : restrictedElements) {
                if (StringUtils.containsIgnoreCase(narr.getName(), character)) {
                    return FALSE;
                }
            }
        }
        return TRUE;
    }

    @Override
    public String checkProposalCoiRule(DevelopmentProposal developmentProposal, String principalId) {
        for (ProposalPerson person : developmentProposal.getInvestigators()) {
            if (person.isInvestigator() && person.isPrincipalInvestigator()
                    && StringUtils.equals(principalId, person.getPersonId())) {
                return TRUE;
            }
        }
        return FALSE;
    }

    @Override
    public String checkProposalPiRule(DevelopmentProposal developmentProposal, String principalId) {
        for (ProposalPerson person : developmentProposal.getInvestigators()) {
            if (person.isInvestigator() && person.isPrincipalInvestigator()
                    && StringUtils.equals(principalId, person.getPersonId())) {
                return TRUE;
            }
        }
        return FALSE;
    }

    @Override
    public String costElement(DevelopmentProposal developmentProposal, String costElement) {
        for (Budget budgetVersion : developmentProposal.getBudgets()) {
            Map<String, Object> values = new HashMap<String, Object>();
            values.put("costElement", costElement);
            values.put("budgetId", budgetVersion.getBudgetId());
            List<BudgetLineItem> matchingLineItems = (List<BudgetLineItem>) getBusinessObjectService()
                    .findMatching(BudgetLineItem.class, values);
            if (matchingLineItems != null && !matchingLineItems.isEmpty()) {
                return TRUE;
            }
        }
        return FALSE;
    }

    @Override
    public String leadUnitBelowRule(DevelopmentProposal developmentProposal, String unitNumber) {
        if (StringUtils.equals(developmentProposal.getUnitNumber(), unitNumber)) {
            return TRUE;
        } else {
            for (Unit unit : getUnitService().getAllSubUnits(unitNumber)) {
                if (StringUtils.equals(unit.getUnitNumber(), developmentProposal.getUnitNumber())) {
                    return TRUE;
                }
            }
        }
        return FALSE;
    }

    @Override
    public String leadUnitRule(DevelopmentProposal developmentProposal, String unitNumber) {
        if (StringUtils.equals(developmentProposal.getUnitNumber(), unitNumber)) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    @Override
    public String mtdcDeviation(DevelopmentProposal developmentProposal) {
        if (mtdcDeviationInBudget(developmentProposal.getFinalBudget())) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    @Override
    public String mtdcDeviationInVersion(DevelopmentProposal developmentProposal, String versionNumber) {
        if (mtdcDeviationInBudget(getBudgetVersion(developmentProposal, versionNumber))) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    protected Budget getBudgetVersion(DevelopmentProposal developmentProposal, String versionNumber) {
        Integer versionNumberLong = Integer.valueOf(versionNumber);
        for (Budget bdv : developmentProposal.getBudgets()) {
            if (bdv.getBudgetVersionNumber().equals(versionNumberLong)) {
                return bdv;
            }
        }
        return null;
    }

    protected boolean mtdcDeviationInBudget(Budget budget) {
        return budget != null && StringUtils.equals(budget.getOhRateClassCode(), "1");
    }

    @Override
    public String nonFacultyPi(DevelopmentProposal developmentProposal) {
        if (developmentProposal.getPrincipalInvestigator() != null
                && developmentProposal.getPrincipalInvestigator().getFacultyFlag()) {
            return FALSE;
        } else {
            return TRUE;
        }
    }

    @Override
    public String proposalAwardTypeRule(DevelopmentProposal developmentProposal, Integer awardTypeCode) {
        if (awardTypeCode.equals(developmentProposal.getAnticipatedAwardTypeCode())) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    @Override
    public String proposalTypeRule(DevelopmentProposal developmentProposal, String proposalTypeCode) {
        if (StringUtils.equals(developmentProposal.getProposalTypeCode(), proposalTypeCode)) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    @Override
    public String proposalUnitRule(DevelopmentProposal developmentProposal, String unitNumber) {
        for (ProposalPerson person : developmentProposal.getProposalPersons()) {
            for (ProposalPersonUnit unit : person.getUnits()) {
                if (StringUtils.equals(unit.getUnitNumber(), unitNumber)) {
                    return TRUE;
                }
            }
        }
        return FALSE;
    }

    @Override
    public String s2sAttachmentNarrativeRule(DevelopmentProposal developmentProposal) {
        if (developmentProposal.getS2sOpportunity() != null) {
            for (Narrative narrative : developmentProposal.getNarratives()) {
                if (StringUtils.equals(narrative.getNarrativeTypeCode(), "61")
                        && narrative.getModuleTitle() == null) {
                    return FALSE;
                }
            }
        }
        return TRUE;
    }

    @Override
    public String s2sExemptionRule(DevelopmentProposal developmentProposal) {
        boolean irbLinkingEnabled = getParameterService().getParameterValueAsBoolean(
                ProposalDevelopmentDocument.class, Constants.ENABLE_PROTOCOL_TO_DEV_PROPOSAL_LINK);
        if (!irbLinkingEnabled) {
            for (ProposalSpecialReview specialReview : developmentProposal.getPropSpecialReviews()) {
                if (SpecialReviewApprovalType.EXEMPT.equals(specialReview.getApprovalTypeCode())
                        && SpecialReviewType.HUMAN_SUBJECTS.equals(specialReview.getSpecialReviewTypeCode())) {
                    if (specialReview.getComments() == null
                            || !specialReview.getComments().matches("\\w*E[1-6](\\w*,\\w*E[1-6])*[\\w,]*")) {
                        return FALSE;
                    }
                }
            }
        }
        return TRUE;
    }

    @Override
    public String s2sFederalIdRule(DevelopmentProposal developmentProposal) {
        if (developmentProposal.getS2sOpportunity() != null) {
            String renewalType = getProposalTypeService().getRenewProposalTypeCode();
            if (StringUtils.equals(developmentProposal.getProposalTypeCode(), renewalType)
                    || StringUtils.equals(developmentProposal.getProposalTypeCode(), renewalType)
                    || StringUtils.equals(developmentProposal.getProposalTypeCode(), renewalType)
                    || StringUtils.equals(developmentProposal.getProposalTypeCode(), renewalType)) {
                if (StringUtils.isBlank(developmentProposal.getSponsorProposalNumber())
                        || !developmentProposal.getSponsorProposalNumber().matches("[a-zA-Z]{2}\\d{6}")) {
                    return FALSE;
                }
            }
        }
        return TRUE;
    }

    @Override
    public String s2sLeadershipRule(DevelopmentProposal developmentProposal) {
        if (developmentProposal.getS2sOpportunity() != null) {
            int piNumber = 0;
            for (ProposalPerson person : developmentProposal.getProposalPersons()) {
                if (person.isMultiplePi()) {
                    piNumber++;
                }
            }
            if (piNumber > 0) {
                int neededAttachmentCount = 0;
                for (Narrative narrative : developmentProposal.getNarratives()) {
                    if (StringUtils.equals(narrative.getNarrativeTypeCode(),
                            Constants.PHS_RESEARCHPLAN_MULTIPLEPILEADERSHIPPLAN)
                            || StringUtils.equals(narrative.getNarrativeTypeCode(),
                                    Constants.PHS_RESTRAININGPLAN_PILEADERSHIPPLAN_ATTACHMENT)) {
                        neededAttachmentCount++;
                    }
                }
                if (neededAttachmentCount < 1) {
                    return FALSE;
                }
            }
        }
        return TRUE;
    }

    @Override
    public String s2sModularBudgetRule(DevelopmentProposal developmentProposal) {
        List<String> allowedForms = Arrays
                .asList(new String[] { "PHS398 Modular Budget V1-1", "PHS398 Modular Budget V1-2" });
        boolean s2sProp = (developmentProposal.getS2sOpportunity() != null);
        Budget finalBudgetVersion = developmentProposal.getFinalBudget();
        if (s2sProp && finalBudgetVersion != null && finalBudgetVersion.getModularBudgetFlag()) {
            int matchingForms = 0;
            for (S2sOppForms form : developmentProposal.getS2sOppForms()) {
                if (form.getInclude() && allowedForms.contains(form.getFormName())) {
                    matchingForms++;
                }
            }
            if (matchingForms == 0) {
                return FALSE;
            } else {
                return TRUE;
            }
        } else {
            return TRUE;
        }
    }

    @Override
    public String specialReviewRule(DevelopmentProposal developmentProposal, String specialReviewTypeCode) {
        for (ProposalSpecialReview review : developmentProposal.getPropSpecialReviews()) {
            if (StringUtils.equals(review.getSpecialReviewTypeCode(), specialReviewTypeCode)) {
                return TRUE;
            }
        }
        return FALSE;
    }

    @Override
    public String sponsor(DevelopmentProposal developmentProposal, String sponsorCode) {
        if (StringUtils.equals(developmentProposal.getSponsorCode(), sponsorCode)) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    @Override
    public String sponsorGroupRule(DevelopmentProposal developmentProposal, String sponsorGroup) {
        Map<String, Object> values = new HashMap<>();
        values.put("hierarchyName", Constants.SPONSOR_HIERARCHY_ROUTING);
        values.put("sponsorCode", developmentProposal.getSponsorCode());
        List<SponsorHierarchy> hierarchies = (List<SponsorHierarchy>) getBusinessObjectService()
                .findMatching(SponsorHierarchy.class, values);
        if (hierarchies != null && !hierarchies.isEmpty()
                && StringUtils.equals(hierarchies.get(0).getLevel1(), sponsorGroup)) {
            return TRUE;
        }
        values.put("sponsorCode", developmentProposal.getPrimeSponsorCode());
        hierarchies = (List<SponsorHierarchy>) getBusinessObjectService().findMatching(SponsorHierarchy.class,
                values);
        if (hierarchies != null && !hierarchies.isEmpty()
                && StringUtils.equals(hierarchies.get(0).getLevel1(), sponsorGroup)) {
            return TRUE;
        }
        return FALSE;
    }

    /**
     * 
     * This method is used to verify PHS Cover letter narrative(39) is attached, must include s2s cover letter form.
     * See  FN_S2S_398COVER_RULE 
     * @param PHSCoverLetters PHS Cover letter names, comma separated list
     * @param narrativeTypeCode The narrative type code to check.
     * @return 'false' if the passed in narrative type is used, and a PHS cover letter is not attached, otherwise returns 'true'
     */
    @Override
    public String s2s398CoverRule(DevelopmentProposal developmentProposal, String PHSCoverLetters,
            String narrativeTypeCode) {
        if (developmentProposal.getS2sAppSubmission().size() > 0) {
            boolean foundNarrative = false;
            for (Narrative narrative : developmentProposal.getNarratives()) {
                if (StringUtils.equalsIgnoreCase(narrative.getNarrativeTypeCode(), narrativeTypeCode)) {
                    foundNarrative = true;
                }
            }
            if (foundNarrative) {
                String[] coverLetters = this.buildArrayFromCommaList(PHSCoverLetters);
                boolean foundForm = false;
                for (S2sOppForms form : developmentProposal.getS2sOppForms()) {
                    for (String coverLetter : coverLetters) {
                        if (StringUtils.equals(form.getFormName(), coverLetter)) {
                            foundForm = true;
                        }
                    }
                }
                if (!foundForm) {
                    return FALSE;
                }
            }
        }
        return TRUE;
    }

    /**
     * 
     * This method is used to verify no special characters are used.
     * See  fn_narrative_file_name_rule  
     * @return 'false' if there is a special character in the file name, otherwise returns 'true'
     */
    @Override
    public String narrativeFileName(DevelopmentProposal developmentProposal) {
        for (Narrative narrative : developmentProposal.getNarratives()) {
            if (StringUtils.equalsIgnoreCase(narrative.getNarrativeType().getNarrativeTypeGroup(), "P")
                    && StringUtils.equals(FALSE, specialCharacterRule(narrative.getName()))) {
                return FALSE;
            }
            if (StringUtils.equalsIgnoreCase(narrative.getNarrativeTypeCode(), "8")
                    && StringUtils.equals(FALSE, specialCharacterRule(narrative.getModuleTitle()))) {
                return FALSE;
            }

        }
        return TRUE;
    }

    /**
     * 
     * This method is used to verify that a cost element is used in the specified version of the proposal.
     * See  fn_cost_element_in_version  
     * @return 'false' if the cost element is not in the version of the proposal, otherwise returns 'true'
     */
    @Override
    public String costElementInVersion(DevelopmentProposal developmentProposal, String versionNumber,
            String costElement) {
        Long versionNumberLong = Long.parseLong(versionNumber);
        for (Budget budget : developmentProposal.getBudgets()) {
            if (budget.getVersionNumber().equals(versionNumberLong)) {
                for (BudgetPeriod period : budget.getBudgetPeriods()) {
                    if (!period.getBudgetLineItems().isEmpty()) {
                        return TRUE;
                    }
                }
            }
        }
        return FALSE;
    }

    /**
     * 
     * This method is used to verify that each investigator and key person are certified
     * See  FN_IS_EPS_PROP_INVKEY_CERT  
     * @return 'true' if all the investigators and key person have completed their questionaires, otherwise return 'false'
     */
    @Override
    public String investigatorKeyPersonCertificationRule(DevelopmentProposal developmentProposal) {
        for (ProposalPerson person : developmentProposal.getProposalPersons()) {
            ProposalPersonModuleQuestionnaireBean moduleQuestionnaireBean = new ProposalPersonModuleQuestionnaireBean(
                    developmentProposal, person);
            List<AnswerHeader> answerHeaders = getQuestionnaireAnswerService()
                    .getQuestionnaireAnswer(moduleQuestionnaireBean);
            for (AnswerHeader ah : answerHeaders) {
                if (!ah.isCompleted()) {
                    return FALSE;
                }
            }
        }
        return TRUE;
    }

    @Override
    public String sponsorTypeRule(DevelopmentProposal developmentProposal, String sponsorTypeCode) {
        if (StringUtils.equals(developmentProposal.getSponsor().getSponsorTypeCode(), sponsorTypeCode)) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    @Override
    public String completeNarrativeRule(DevelopmentProposal developmentProposal) {
        for (Narrative narrative : developmentProposal.getNarratives()) {
            if (StringUtils.equals(narrative.getModuleStatusCode(), "I")) {
                return FALSE;
            }
        }
        return TRUE;
    }

    /**
     * This method is to CHECK  PI citizenship type
     * Check if the citizenship type of the Principal Investigator equal to the specified value
     * FN_PI_CITIZENSHIP_TYPE_RULE
     */
    public String investigatorCitizenshipTypeRule(DevelopmentProposal developmentProposal,
            String citizenshipTypeToCheck) {
        String RETURN_VALUE = FALSE;
        ProposalPerson principalInvestigator = developmentProposal.getPrincipalInvestigator();
        char citizenType = citizenshipTypeToCheck != null ? citizenshipTypeToCheck.charAt(0) : '0';
        Integer citizenshipTypeCode = principalInvestigator.getCitizenshipTypeCode();
        switch (citizenType) {
        case 'A':
            if (citizenshipTypeCode.equals(INT_NON_U_S_CITIZEN_WITH_TEMPORARY_VISA)) {
                RETURN_VALUE = TRUE;
            }
            break;
        case 'C':
            if (citizenshipTypeCode.equals(INT_U_S_CITIZEN_OR_NONCITIZEN_NATIONAL)) {
                RETURN_VALUE = TRUE;
            }
            break;
        case 'N':
            if (citizenshipTypeCode.equals(INT_PERMANENT_RESIDENT_OF_U_S)) {
                RETURN_VALUE = TRUE;
            }
            break;
        case 'P':
            if (citizenshipTypeCode.equals(INT_PERMANENT_RESIDENT_OF_U_S_PENDING)) {
                RETURN_VALUE = TRUE;
            }
            break;
        default:
            Collection<String> citizenshipTypeParams = getParameterService().getParameterValuesAsString(
                    ProposalDevelopmentDocument.class, ProposalDevelopmentUtils.PROPOSAL_PI_CITIZENSHIP_TYPE_PARM);
            if (citizenshipTypeParams != null && citizenshipTypeParams.contains(citizenshipTypeToCheck)) {
                RETURN_VALUE = TRUE;
            }
            break;
        }
        return RETURN_VALUE;
    }

    /**
     * This method is to check if the PI or any multi-PI has PI status
     * FN_PI_APPOINTMENT_TYPE_RULE
     */
    public String piAppointmentTypeRule(DevelopmentProposal developmentProposal) {
        List<ProposalPerson> people = developmentProposal.getProposalPersons();
        List<AppointmentType> appointmentTypes = (List<AppointmentType>) getBusinessObjectService()
                .findAll(AppointmentType.class);
        for (ProposalPerson person : people) {
            if ((person.isInvestigator() && person.isPrincipalInvestigator()) || (person.isMultiplePi())
                    && person.getPerson() != null && person.getPerson().getExtendedAttributes() != null) {
                List<PersonAppointment> appointments = person.getPerson().getExtendedAttributes()
                        .getPersonAppointments();
                for (PersonAppointment personAppointment : appointments) {
                    if (isAppointmentTypeEqualsJobTitle(appointmentTypes, personAppointment.getJobTitle())) {
                        return TRUE;
                    }
                }
            }
        }
        return FALSE;
    }

    private boolean isAppointmentTypeEqualsJobTitle(List<AppointmentType> appointmentTypes, String jobTitle) {
        for (AppointmentType appointmentType : appointmentTypes) {
            if (appointmentType.getDescription().equalsIgnoreCase(jobTitle)) {
                return true;
            }
        }
        return false;
    }

    /**
     * This method is to check campus
     * Check if the lead unit of the Proposal belong to campus
     * FN_PROPOSAL_CAMPUS_RULE
     */
    public String proposalCampusRule(DevelopmentProposal developmentProposal, String a2SCampusCode) {
        for (ProposalPerson person : developmentProposal.getProposalPersons()) {
            for (ProposalPersonUnit unit : person.getUnits()) {
                if (unit.isLeadUnit() && StringUtils.equals(unit.getUnitNumber().substring(1, 3), a2SCampusCode)) {
                    return TRUE;
                }
            }
        }
        return FALSE;
    }

    /**
     * This method is to check document in routing
     * Check if the proposal has been approved or rejected by OSP
     * FN_ROUTED_TO_OSP_RULE
     */
    public String routedToOSPRule(DevelopmentProposal developmentProposal) {
        if (developmentProposal.getProposalDocument().getDocumentHeader().getWorkflowDocument().isApproved()
                || developmentProposal.getProposalDocument().getDocumentHeader().getWorkflowDocument()
                        .isDisapproved()) {
            return TRUE;
        }
        return FALSE;
    }

    /**
     * This method to check submit user
     * Check if the submit/given user is the PI of the proposal
     */
    public String isUserProposalPI(DevelopmentProposal developmentProposal) {
        Person loggedInUser = globalVariableService.getUserSession().getPerson();
        String principalId = loggedInUser.getPrincipalId();
        return checkProposalPiRule(developmentProposal, principalId);
    }

    /**
     * This method is to check units
     * Check if any proposal unit is below a specified unit in the hierarchy
     * FN_PROPOSAL_UNIT_BELOW
     */
    public String proposalUnitBelow(DevelopmentProposal developmentProposal, String unitNumberToCheck) {
        List<Unit> units = this.getUnitService().getAllSubUnits(unitNumberToCheck);
        if (units != null && units.size() > 0) {
            for (Unit unit : units) {
                for (ProposalPerson person : developmentProposal.getProposalPersons()) {
                    for (ProposalPersonUnit proposalUnit : person.getUnits()) {
                        if (StringUtils.equals(proposalUnit.getUnitNumber(), unit.getUnitNumber())) {
                            return TRUE;
                        }
                    }
                }
            }
        }
        return FALSE;
    }

    /**
     * This method is to check rolodex person
     * Check if the proposal involves a specific rolodex id
     * FN_USES_ROLODEX
     */
    public String usesRolodex(DevelopmentProposal developmentProposal, Integer rolodexId) {
        for (ProposalPerson person : developmentProposal.getProposalPersons()) {
            if (person.getRolodexId() != null && person.getRolodexId().equals(rolodexId)) {
                return TRUE;
            }
        }
        return FALSE;
    }

    /**
     * This method is to check s2s competition id
     * FN_COMPETITION_ID_RULE
     */
    public String competitionIdRule(DevelopmentProposal developmentProposal, String competitionId) {
        if (developmentProposal.getS2sOpportunity().getCompetetionId().equals(competitionId)) {
            return TRUE;
        }
        return FALSE;
    }

    /**
     * This method is to check if proposal Animal or Human Special review approval date 
     * is in the future
     * FN_SPECIAL_REV_DATE_RULE
     */
    public String specialReviewDateRule(DevelopmentProposal developmentProposal) {
        Date currentDate = getDateTimeService().getCurrentSqlDateMidnight();
        for (ProposalSpecialReview proposalSpecialReview : developmentProposal.getPropSpecialReviews()) {
            if (proposalSpecialReview.getSpecialReviewTypeCode().equals(SpecialReviewType.HUMAN_SUBJECTS)
                    || proposalSpecialReview.getSpecialReviewTypeCode().equals(SpecialReviewType.ANIMAL_USAGE)) {
                if (proposalSpecialReview.getApplicationDate().after(currentDate)) {
                    return TRUE;
                }
            }
        }
        return FALSE;
    }

    /**
     * This method is to check if the proposal's deadline date is before a specified date.
     * @param developmentProposal
     * FN_DEADLINE_DATE
     */
    public String deadlineDateRule(DevelopmentProposal developmentProposal, String deadlineDate) {
        try {
            Date checkDeadLineDate = getDateTimeService().convertToSqlDate(deadlineDate);
            if (developmentProposal.getDeadlineDate().before(checkDeadLineDate)) {
                return TRUE;
            }
        } catch (Exception ex) {
            LOG.error(ex.getMessage());
        }
        return FALSE;
    }

    /**
     * This method is to check if the proposal is being routed for the first time.
     * FN_ROUTING_SEQ_RULE
     */
    public String routingSequenceRule(DevelopmentProposal developmentProposal) {
        List<ActionRequest> actionRequests = developmentProposal.getProposalDocument().getDocumentHeader()
                .getWorkflowDocument().getDocumentDetail().getActionRequests();
        int submitCount = 0;
        for (ActionRequest actionRequest : actionRequests) {
            if (actionRequest.getNodeName().equals(Constants.PD_INITIATED_ROUTE_NODE_NAME)) {
                submitCount++;
            }
            if (submitCount > 1) {
                return FALSE;
            }
        }
        return TRUE;
    }

    public DateTimeService getDateTimeService() {
        return dateTimeService;
    }

    public void setDateTimeService(DateTimeService dateTimeService) {
        this.dateTimeService = dateTimeService;
    }

    public QuestionnaireAnswerService getQuestionnaireAnswerService() {
        return questionnaireAnswerService;
    }

    public void setQuestionnaireAnswerService(QuestionnaireAnswerService questionnaireAnswerService) {
        this.questionnaireAnswerService = questionnaireAnswerService;
    }

    public UnitService getUnitService() {
        return unitService;
    }

    public void setUnitService(UnitService unitService) {
        this.unitService = unitService;
    }

    public GlobalVariableService getGlobalVariableService() {
        return globalVariableService;
    }

    public void setGlobalVariableService(GlobalVariableService globalVariableService) {
        this.globalVariableService = globalVariableService;
    }

    public ProposalTypeService getProposalTypeService() {
        return proposalTypeService;
    }

    public void setProposalTypeService(ProposalTypeService proposalTypeService) {
        this.proposalTypeService = proposalTypeService;
    }

}