org.kuali.coeus.propdev.impl.core.ProposalDevelopmentSubmitController.java Source code

Java tutorial

Introduction

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

import java.sql.Timestamp;
import java.util.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.kuali.coeus.common.framework.krms.KrmsRulesExecutionService;
import org.kuali.coeus.common.view.wizard.framework.WizardControllerService;
import org.kuali.coeus.common.budget.framework.core.Budget;
import org.kuali.coeus.common.framework.ruleengine.KcBusinessRulesEngine;
import org.kuali.coeus.common.notification.impl.bo.KcNotification;
import org.kuali.coeus.common.notification.impl.bo.NotificationTypeRecipient;
import org.kuali.coeus.common.notification.impl.rule.event.SendNotificationEvent;
import org.kuali.coeus.common.notification.impl.service.KcNotificationService;
import org.kuali.coeus.propdev.impl.action.ProposalDevelopmentRejectionBean;
import org.kuali.coeus.propdev.impl.action.ProposalDevelopmentRejectionRule;
import org.kuali.coeus.propdev.impl.hierarchy.ProposalHierarchyService;
import org.kuali.coeus.propdev.impl.notification.ProposalDevelopmentNotificationContext;
import org.kuali.coeus.propdev.impl.notification.ProposalDevelopmentNotificationRenderer;
import org.kuali.coeus.propdev.impl.s2s.S2sSubmissionService;
import org.kuali.coeus.propdev.impl.specialreview.ProposalSpecialReview;
import org.kuali.coeus.propdev.impl.state.ProposalState;
import org.kuali.coeus.propdev.impl.state.ProposalStateService;
import org.kuali.coeus.s2sgen.api.core.S2SException;
import org.kuali.coeus.sys.framework.gv.GlobalVariableService;
import org.kuali.coeus.s2sgen.api.generate.FormGeneratorService;
import org.kuali.coeus.common.framework.compliance.core.SaveSpecialReviewLinkEvent;
import org.kuali.coeus.common.framework.compliance.core.SpecialReviewService;
import org.kuali.coeus.common.framework.compliance.core.SpecialReviewType;
import org.kuali.coeus.sys.framework.validation.AuditHelper;
import org.kuali.coeus.sys.framework.workflow.KcWorkflowService;
import org.kuali.kra.bo.FundingSourceType;
import org.kuali.kra.infrastructure.Constants;
import org.kuali.kra.infrastructure.KeyConstants;
import org.kuali.kra.institutionalproposal.home.InstitutionalProposal;
import org.kuali.kra.institutionalproposal.proposaladmindetails.ProposalAdminDetails;
import org.kuali.kra.institutionalproposal.service.InstitutionalProposalService;
import org.kuali.kra.institutionalproposal.specialreview.InstitutionalProposalSpecialReview;
import org.kuali.rice.core.api.config.property.ConfigurationService;
import org.kuali.rice.core.api.util.RiceKeyConstants;
import org.kuali.rice.coreservice.framework.parameter.ParameterConstants;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kew.api.KewApiConstants;
import org.kuali.rice.kew.api.WorkflowDocument;
import org.kuali.rice.kew.api.action.ActionRequest;
import org.kuali.rice.kew.api.action.RoutingReportCriteria;
import org.kuali.rice.kew.api.action.WorkflowDocumentActionsService;
import org.kuali.rice.kew.api.document.DocumentDetail;
import org.kuali.rice.kim.api.group.GroupService;
import org.kuali.rice.krad.document.Document;
import org.kuali.rice.krad.service.KualiRuleService;
import org.kuali.rice.krad.service.LegacyDataAdapter;
import org.kuali.rice.krad.uif.UifConstants;
import org.kuali.rice.krad.uif.UifParameters;
import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
import org.kuali.rice.krad.util.KRADConstants;
import org.kuali.rice.krad.web.form.DialogResponse;
import org.kuali.rice.krad.web.form.DocumentFormBase;
import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class ProposalDevelopmentSubmitController extends ProposalDevelopmentControllerBase {

    @Autowired
    @Qualifier("kcNotificationService")
    private KcNotificationService kcNotificationService;

    @Autowired
    @Qualifier("kualiRuleService")
    private KualiRuleService kualiRuleService;

    @Autowired
    @Qualifier("wizardControllerService")
    private WizardControllerService wizardControllerService;

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

    @Autowired
    @Qualifier("kualiConfigurationService")
    private ConfigurationService configurationService;

    @Autowired
    @Qualifier("s2sSubmissionService")
    private S2sSubmissionService s2sSubmissionService;

    @Autowired
    @Qualifier("institutionalProposalService")
    private InstitutionalProposalService institutionalProposalService;

    @Autowired
    @Qualifier("kradWorkflowDocumentService")
    private WorkflowDocumentService kradWorkflowDocumentService;

    @Autowired
    @Qualifier("workflowDocumentActionsService")
    protected WorkflowDocumentActionsService workflowDocumentActionsService;

    @Autowired
    @Qualifier("groupService")
    private GroupService groupService;

    @Autowired
    @Qualifier("proposalDevelopmentNotificationRenderer")
    private ProposalDevelopmentNotificationRenderer renderer;

    @Autowired
    @Qualifier("kcBusinessRulesEngine")
    private KcBusinessRulesEngine kcBusinessRulesEngine;

    @Autowired
    @Qualifier("krmsRulesExecutionService")
    private KrmsRulesExecutionService krmsRulesExecutionService;

    @Autowired
    @Qualifier("parameterService")
    private ParameterService parameterService;

    @Autowired
    @Qualifier("formGeneratorService")
    private FormGeneratorService formGeneratorService;

    @Autowired
    @Qualifier("proposalStateService")
    private ProposalStateService proposalStateService;

    @Autowired
    @Qualifier("specialReviewService")
    private SpecialReviewService specialReviewService;

    @Autowired
    @Qualifier("proposalHierarchyService")
    private ProposalHierarchyService proposalHierarchyService;

    @Autowired
    @Qualifier("legacyDataAdapter")
    private LegacyDataAdapter legacyDataAdapter;

    @Autowired
    @Qualifier("kcWorkflowService")
    private KcWorkflowService kcWorkflowService;

    private final Logger LOGGER = Logger.getLogger(ProposalDevelopmentSubmitController.class);

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=populateAdHocs")
    public ModelAndView populateAdHocs(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        populateAdHocRecipients(form.getProposalDevelopmentDocument());
        return getModelAndViewService().showDialog("PropDev-DocumentAdHocRecipientsSection", true, form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=saveAdHocChanges")
    public ModelAndView saveAdHocChanges(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        return super.save(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=deleteProposal")
    public ModelAndView deleteProposal(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {

        if (form.getProposalDevelopmentDocument().getDevelopmentProposal().isInHierarchy()) {
            getGlobalVariableService().getMessageMap().putError(KRADConstants.GLOBAL_ERRORS,
                    KeyConstants.ERROR_DELETE_PROPOSAL_IN_HIERARCHY);
            return getModelAndViewService().getModelAndView(form);
        } else {
            getProposalDevelopmentService().deleteProposal(form.getProposalDevelopmentDocument());
            return getNavigationControllerService().returnToHub(form);
        }
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=submitForReview")
    public ModelAndView submitForReview(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        populateAdHocRecipients(form.getProposalDevelopmentDocument());
        AuditHelper.ValidationState severityLevel = getValidationState(form);
        if (severityLevel.equals(AuditHelper.ValidationState.ERROR)) {
            return getModelAndViewService()
                    .showDialog(ProposalDevelopmentConstants.KradConstants.DATA_VALIDATION_DIALOG_ID, true, form);
        } else if (severityLevel.equals(AuditHelper.ValidationState.WARNING)) {
            return getModelAndViewService().showDialog(
                    ProposalDevelopmentConstants.KradConstants.DATA_VALIDATION_SECTION_WITH_SUBMIT, true, form);
        } else {
            return internalSubmit(form);
        }
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=internalSubmit")
    public ModelAndView internalSubmit(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        WorkflowDocument workflowDoc = form.getProposalDevelopmentDocument().getDocumentHeader()
                .getWorkflowDocument();
        if (canGenerateRequestsInFuture(workflowDoc,
                getGlobalVariableService().getUserSession().getPrincipalId())) {
            DialogResponse dialogResponse = form.getDialogResponse("PropDev-SubmitPage-ReceiveFutureRequests");
            if (dialogResponse == null) {
                return getModelAndViewService().showDialog("PropDev-SubmitPage-ReceiveFutureRequests", false, form);
            } else if (dialogResponse.getResponseAsBoolean()) {
                form.getWorkflowDocument().setReceiveFutureRequests();
            } else {
                form.getWorkflowDocument().setDoNotReceiveFutureRequests();
            }
        }
        form.setCanEditView(null);
        form.setEvaluateFlagsAndModes(true);
        getTransactionalDocumentControllerService().route(form);
        getPessimisticLockService().releaseWorkflowPessimisticLocking(form.getProposalDevelopmentDocument());
        return updateProposalState(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=cancelProposal")
    public ModelAndView cancelProposal(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        form.setCanEditView(null);
        form.setEvaluateFlagsAndModes(true);
        form.getDevelopmentProposal().setProposalStateTypeCode(ProposalState.CANCELED);
        return getTransactionalDocumentControllerService().cancel(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = { "methodToCall=navigate",
            "actionParameters[navigateToPageId]=PropDev-SubmitPage" })
    public ModelAndView navigateToSubmit(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form,
            BindingResult result, HttpServletRequest request, HttpServletResponse response) throws Exception {
        ((ProposalDevelopmentViewHelperServiceImpl) form.getViewHelperService()).prepareSummaryPage(form);
        return super.navigate(form, result, request, response);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=blanketApprove")
    public ModelAndView blanketApprove(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        if (!getValidationState(form).equals(AuditHelper.ValidationState.ERROR)) {
            form.setCanEditView(null);
            form.setEvaluateFlagsAndModes(true);
            return getTransactionalDocumentControllerService().blanketApprove(form);
        }
        return getModelAndViewService()
                .showDialog(ProposalDevelopmentConstants.KradConstants.DATA_VALIDATION_DIALOG_ID, true, form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=recall")
    public ModelAndView recall(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form) throws Exception {
        String successMessageKey = null;
        Document document = form.getDocument();
        if (getDocumentService().documentExists(document.getDocumentNumber())) {
            String recallExplanation = form.getDialogExplanations()
                    .get(KRADConstants.QUESTION_ACTION_RECALL_REASON);
            getDocumentService().recallDocument(document, recallExplanation, false);
            successMessageKey = RiceKeyConstants.MESSAGE_ROUTE_RECALLED;
        }
        if (successMessageKey != null) {
            getGlobalVariableService().getMessageMap().putInfo(KRADConstants.GLOBAL_MESSAGES, successMessageKey);
        }
        form.setCanEditView(null);
        form.setEvaluateFlagsAndModes(true);
        return getModelAndViewService().getModelAndView(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=disapproveProposal")
    public ModelAndView disapproveProposal(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        String applicationUrl = getConfigurationService()
                .getPropertyValueAsString(KRADConstants.APPLICATION_URL_KEY);
        form.setReturnLocation(applicationUrl);
        form.setCanEditView(null);
        form.setEvaluateFlagsAndModes(true);
        return getTransactionalDocumentControllerService().disapprove(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=prepareNotificationWizard")
    public ModelAndView prepareNotificationWizard(
            @ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form) {
        final String step = form.getNotificationHelper().getNotificationRecipients().isEmpty() ? "0" : "2";
        form.getActionParameters().put("Kc-SendNotification-Wizard.step", step);
        return getRefreshControllerService().refresh(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=addRecipients")
    public ModelAndView addRecipients(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form) {
        form.getNotificationHelper().getNotificationRecipients()
                .addAll(getKcNotificationService().addRecipient(form.getAddRecipientHelper().getResults()));
        return getRefreshControllerService().refresh(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=performRecipientSearch")
    public ModelAndView performRecipientSearch(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        form.getAddRecipientHelper().getResults().clear();
        form.getAddRecipientHelper().setResults(getWizardControllerService().performWizardSearch(
                form.getAddRecipientHelper().getLookupFieldValues(), form.getAddRecipientHelper().getLineType()));
        return getRefreshControllerService().refresh(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=sendNotifications")
    public ModelAndView sendNotifications(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form) {
        ProposalDevelopmentDocument document = form.getProposalDevelopmentDocument();
        KcNotification notification = form.getNotificationHelper().getNotification();
        List<NotificationTypeRecipient> notificationRecipients = form.getNotificationHelper()
                .getNotificationRecipients();

        if (getKualiRuleService()
                .applyRules(new SendNotificationEvent(document, notification, notificationRecipients))) {
            form.getNotificationHelper().sendNotification();
        }

        ProposalDevelopmentNotificationRenderer renderer = new ProposalDevelopmentNotificationRenderer(
                form.getDevelopmentProposal());
        ProposalDevelopmentNotificationContext context = new ProposalDevelopmentNotificationContext(
                form.getDevelopmentProposal(), null, "Ad-Hoc Notification", renderer);

        form.getNotificationHelper().initializeDefaultValues(context);
        form.getAddRecipientHelper().reset();
        populateDeferredMessages(form);
        return getRefreshControllerService().refresh(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=cancelNotifications")
    public ModelAndView cancelNotifications(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form) {
        populateDeferredMessages(form);
        return getRefreshControllerService().refresh(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=submitToS2s")
    public ModelAndView submitToS2s(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        form.setGrantsGovSubmitFlag(true);
        form.setShowSubmissionDetails(true);
        form.setDirtyForm(false);

        if (!requiresResubmissionPrompt(form)) {
            if (validToSubmitToSponsor(form)) {
                //Generate IP in case auto generate IP and no IP hasn't been generated yet (in other words no submit to sponsor button clicked)
                if (autogenerateInstitutionalProposal() && !hasInstitutionalProposal(
                        form.getProposalDevelopmentDocument().getDevelopmentProposal().getProposalNumber())) {
                    submitApplication(form);
                }
                handleSubmissionToS2S(form);
                return getModelAndViewService().getModelAndView(form, "PropDev-OpportunityPage");
            } else {
                return getModelAndViewService().showDialog(
                        ProposalDevelopmentConstants.KradConstants.DATA_VALIDATION_DIALOG_ID, true, form);
            }
        } else {
            return getModelAndViewService().showDialog("PropDev-Resumbit-OptionsSection", true, form);
        }
    }

    protected void handleSubmissionToS2S(ProposalDevelopmentDocumentForm form) throws Exception {
        ProposalDevelopmentDocument proposalDevelopmentDocument = form.getProposalDevelopmentDocument();
        try {
            submitS2sApplication(proposalDevelopmentDocument);
        } catch (S2SException ex) {
            LOGGER.error(ex.getStackTrace(), ex);
            getGlobalVariableService().getMessageMap().putError(Constants.NO_FIELD,
                    KeyConstants.ERROR_ON_GRANTS_GOV_SUBMISSION, ex.getErrorMessage());
        }
    }

    protected boolean hasInstitutionalProposal(String proposalNumber) {
        return getProposalDevelopmentService().getInstitutionalProposal(proposalNumber) != null;
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=submitToSponsor")
    public ModelAndView submitToSponsor(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {

        if (!requiresResubmissionPrompt(form)) {
            if (validToSubmitToSponsor(form)) {
                submitApplication(form);
                handleSubmissionNotification(form);
                form.setDeferredMessages(getGlobalVariableService().getMessageMap());
                return sendSubmitToSponsorNotification(form);
            } else {
                form.setDataValidationItems(((ProposalDevelopmentViewHelperServiceImpl) form.getViewHelperService())
                        .populateDataValidation());
                return getModelAndViewService().showDialog(
                        ProposalDevelopmentConstants.KradConstants.DATA_VALIDATION_DIALOG_ID, true, form);
            }
        } else {
            return getModelAndViewService().showDialog("PropDev-Resumbit-OptionsSection", true, form);
        }
    }

    protected ModelAndView sendSubmitToSponsorNotification(
            ProposalDevelopmentDocumentForm proposalDevelopmentDocumentForm) {
        ProposalDevelopmentDocument proposalDevelopmentDocument = proposalDevelopmentDocumentForm
                .getProposalDevelopmentDocument();
        ProposalDevelopmentNotificationContext context = new ProposalDevelopmentNotificationContext(
                proposalDevelopmentDocument.getDevelopmentProposal(), "101", "Proposal Submitted");
        ((ProposalDevelopmentNotificationRenderer) context.getRenderer())
                .setDevelopmentProposal(proposalDevelopmentDocumentForm.getDevelopmentProposal());
        if (proposalDevelopmentDocumentForm.getNotificationHelper().getPromptUserForNotificationEditor(context)) {
            proposalDevelopmentDocumentForm.getNotificationHelper().initializeDefaultValues(context);
            return getModelAndViewService().showDialog("Kc-SendNotification-Wizard", true,
                    proposalDevelopmentDocumentForm);
        } else {
            getKcNotificationService().sendNotification(context);
        }
        return getModelAndViewService().getModelAndView(proposalDevelopmentDocumentForm);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=deleteLineNotificationRecipient")
    public ModelAndView deleteLine(@ModelAttribute("KualiForm") DocumentFormBase form,
            @RequestParam("actionParameters[" + UifParameters.SELECTED_COLLECTION_PATH
                    + "]") String selectedCollectionPath) {
        getCollectionControllerService().deleteLine(form);

        final Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(form, selectedCollectionPath);
        form.getActionParameters().put("Kc-SendNotification-Wizard.step",
                collection.isEmpty() ? ProposalDevelopmentConstants.NotificationConstants.NOTIFICATION_STEP_0
                        : ProposalDevelopmentConstants.NotificationConstants.NOTIFICATION_STEP_2);
        return getModelAndViewService().showDialog("Kc-SendNotification-Wizard", true, form);
    }

    protected void handleSubmissionNotification(ProposalDevelopmentDocumentForm form) {
        getRenderer().setDevelopmentProposal(form.getDevelopmentProposal());
        ProposalDevelopmentDocument proposalDevelopmentDocument = form.getProposalDevelopmentDocument();
        ProposalDevelopmentNotificationContext notificationContext = new ProposalDevelopmentNotificationContext(
                proposalDevelopmentDocument.getDevelopmentProposal(),
                ProposalDevelopmentConstants.NotificationConstants.NOTIFICATION_S2S_SUBMIT_ACTION_CODE,
                ProposalDevelopmentConstants.NotificationConstants.NOTIFICATION_S2S_SUBMIT_CONTEXT_NAME,
                getRenderer());
        form.getNotificationHelper().setNotificationContext(notificationContext);
        form.getNotificationHelper().initializeDefaultValues(notificationContext);
        final String step = form.getNotificationHelper().getNotificationRecipients().isEmpty()
                ? ProposalDevelopmentConstants.NotificationConstants.NOTIFICATION_STEP_0
                : ProposalDevelopmentConstants.NotificationConstants.NOTIFICATION_STEP_2;
        form.getActionParameters().put("Kc-SendNotification-Wizard.step", step);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=proceed")
    public ModelAndView proceed(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        return form.isGrantsGovSubmitFlag() ? submitToS2s(form) : submitToSponsor(form);
    }

    protected boolean validToSubmitToSponsor(ProposalDevelopmentDocumentForm form) {
        boolean isValid = !getValidationState(form).equals(AuditHelper.ValidationState.ERROR);
        isValid &= getKcBusinessRulesEngine()
                .applyRules(new SubmitToSponsorEvent(form.getProposalDevelopmentDocument()));
        return isValid;
    }

    public void submitApplication(ProposalDevelopmentDocumentForm proposalDevelopmentForm) throws Exception {
        ProposalDevelopmentDocument proposalDevelopmentDocument = proposalDevelopmentForm
                .getProposalDevelopmentDocument();

        boolean isIPProtocolLinkingEnabled = getParameterService().getParameterValueAsBoolean(
                Constants.MODULE_NAMESPACE_PROTOCOL, ParameterConstants.DOCUMENT_COMPONENT,
                Constants.ENABLE_PROTOCOL_TO_PROPOSAL_LINK);

        List<ProposalSpecialReview> specialReviews = proposalDevelopmentDocument.getDevelopmentProposal()
                .getPropSpecialReviews();

        if (!isIPProtocolLinkingEnabled
                || getKcBusinessRulesEngine().applyRules(new SaveSpecialReviewLinkEvent<ProposalSpecialReview>(
                        proposalDevelopmentDocument, specialReviews))) {

            final boolean generateIp = !(autogenerateInstitutionalProposal()
                    && ProposalDevelopmentConstants.ResubmissionOptions.DO_NOT_GENERATE_NEW_IP
                            .equals(proposalDevelopmentForm.getResubmissionOption()));

            if (generateIp) {
                proposalDevelopmentDocument.getDevelopmentProposal().setSubmitFlag(true);
            }
            setProposalStateType(generateIp, proposalDevelopmentDocument);

            String pCode = proposalDevelopmentDocument.getDevelopmentProposal().getProposalStateTypeCode();
            proposalDevelopmentForm.setCanEditView(null);
            proposalDevelopmentForm.setEvaluateFlagsAndModes(true);
            getTransactionalDocumentControllerService().save(proposalDevelopmentForm);
            if (!StringUtils.equals(pCode,
                    proposalDevelopmentDocument.getDevelopmentProposal().getProposalStateTypeCode())) {
                proposalDevelopmentDocument.getDevelopmentProposal().setProposalStateTypeCode(pCode);
                proposalDevelopmentDocument.getDevelopmentProposal().refresh();
                getDataObjectService().save(proposalDevelopmentDocument.getDevelopmentProposal());
            }

            if (autogenerateInstitutionalProposal()) {
                generateInstitutionalProposal(proposalDevelopmentForm, isIPProtocolLinkingEnabled);
            }
        }

    }

    protected void setProposalStateType(boolean generateIp,
            ProposalDevelopmentDocument proposalDevelopmentDocument) {
        if (generateIp) {
            if (ProposalState.APPROVED
                    .equals(proposalDevelopmentDocument.getDevelopmentProposal().getProposalStateTypeCode())) {
                proposalDevelopmentDocument.getDevelopmentProposal()
                        .setProposalStateTypeCode(ProposalState.APPROVED_AND_SUBMITTED);
            } else {
                proposalDevelopmentDocument.getDevelopmentProposal().setProposalStateTypeCode(
                        proposalStateService.getProposalStateTypeCode(proposalDevelopmentDocument, false));
            }
        } else {
            if (proposalDevelopmentDocument.getDocumentHeader().getWorkflowDocument().isFinal()) {
                proposalDevelopmentDocument.getDevelopmentProposal()
                        .setProposalStateTypeCode(ProposalState.APPROVED);
            } else {
                proposalDevelopmentDocument.getDevelopmentProposal()
                        .setProposalStateTypeCode(ProposalState.APPROVAL_PENDING);
            }
        }
    }

    private void generateInstitutionalProposal(ProposalDevelopmentDocumentForm proposalDevelopmentForm,
            boolean isIPProtocolLinkingEnabled) {

        if (ProposalDevelopmentConstants.ResubmissionOptions.DO_NOT_GENERATE_NEW_IP
                .equals(proposalDevelopmentForm.getResubmissionOption())) {
            doNotGenerateIp(proposalDevelopmentForm);
        } else if (ProposalDevelopmentConstants.ResubmissionOptions.GENERATE_NEW_VERSION_OF_ORIGINAL_IP
                .equals(proposalDevelopmentForm.getResubmissionOption())) {
            generateNewVersionOfOrigIp(proposalDevelopmentForm, isIPProtocolLinkingEnabled);
        } else if (ProposalDevelopmentConstants.ResubmissionOptions.GENERATE_NEW_VERSION_OF_IP
                .equals(proposalDevelopmentForm.getResubmissionOption())) {
            generateNewVersionIp(proposalDevelopmentForm, isIPProtocolLinkingEnabled);
        } else if (null == proposalDevelopmentForm.getResubmissionOption()
                || ProposalDevelopmentConstants.ResubmissionOptions.GENERATE_NEW_IP
                        .equals(proposalDevelopmentForm.getResubmissionOption())) {
            generateNewIp(proposalDevelopmentForm, isIPProtocolLinkingEnabled);
        } else {
            LOGGER.warn("Invalid resubmission option " + proposalDevelopmentForm.getResubmissionOption());
        }
    }

    protected void doNotGenerateIp(ProposalDevelopmentDocumentForm proposalDevelopmentForm) {
        ProposalDevelopmentDocument proposalDevelopmentDocument = proposalDevelopmentForm
                .getProposalDevelopmentDocument();

        if (proposalDevelopmentDocument.getDocumentHeader().getWorkflowDocument().isFinal()) {
            getGlobalVariableService().getMessageMap().putInfo(Constants.NO_FIELD,
                    KeyConstants.MESSAGE_INSTITUTIONAL_PROPOSAL_NOT_CREATED);
        } else {
            getGlobalVariableService().getMessageMap().putInfo(Constants.NO_FIELD,
                    KeyConstants.MESSAGE_INSTITUTIONAL_PROPOSAL_NOT_CREATED_INROUTE);
        }
    }

    protected void generateNewVersionOfOrigIp(ProposalDevelopmentDocumentForm proposalDevelopmentForm,
            boolean isIPProtocolLinkingEnabled) {
        ProposalDevelopmentDocument proposalDevelopmentDocument = proposalDevelopmentForm
                .getProposalDevelopmentDocument();
        proposalDevelopmentForm.setInstitutionalProposalToVersion(
                proposalDevelopmentDocument.getDevelopmentProposal().getContinuedFrom());
        generateNewVersionIp(proposalDevelopmentForm, isIPProtocolLinkingEnabled);
    }

    protected void generateNewVersionIp(ProposalDevelopmentDocumentForm proposalDevelopmentForm,
            boolean isIPProtocolLinkingEnabled) {
        ProposalDevelopmentDocument proposalDevelopmentDocument = proposalDevelopmentForm
                .getProposalDevelopmentDocument();
        String versionNumber = createInstitutionalProposalVersion(
                proposalDevelopmentForm.getInstitutionalProposalToVersion(),
                proposalDevelopmentDocument.getDevelopmentProposal(),
                proposalDevelopmentDocument.getDevelopmentProposal().getFinalBudget());

        getGlobalVariableService().getMessageMap().putInfo(KeyConstants.MESSAGE_INSTITUTIONAL_PROPOSAL_VERSIONED,
                versionNumber, proposalDevelopmentForm.getInstitutionalProposalToVersion());

        Long institutionalProposalId = getActiveProposalId(
                proposalDevelopmentForm.getInstitutionalProposalToVersion());
        persistProposalAdminDetails(proposalDevelopmentDocument.getDevelopmentProposal().getProposalNumber(),
                institutionalProposalId);
        persistSpecialReviewProtocolFundingSourceLink(institutionalProposalId, isIPProtocolLinkingEnabled);
    }

    protected void generateNewIp(ProposalDevelopmentDocumentForm proposalDevelopmentForm,
            boolean isIPProtocolLinkingEnabled) {
        ProposalDevelopmentDocument proposalDevelopmentDocument = proposalDevelopmentForm
                .getProposalDevelopmentDocument();
        String proposalNumber = createInstitutionalProposal(proposalDevelopmentDocument.getDevelopmentProposal(),
                proposalDevelopmentDocument.getDevelopmentProposal().getFinalBudget());
        getGlobalVariableService().getMessageMap().putInfo(Constants.NO_FIELD,
                KeyConstants.MESSAGE_INSTITUTIONAL_PROPOSAL_CREATED, proposalNumber);

        Long institutionalProposalId = getActiveProposalId(proposalNumber);
        persistProposalAdminDetails(proposalDevelopmentDocument.getDevelopmentProposal().getProposalNumber(),
                institutionalProposalId);
        persistSpecialReviewProtocolFundingSourceLink(institutionalProposalId, isIPProtocolLinkingEnabled);
    }

    protected void persistSpecialReviewProtocolFundingSourceLink(Long institutionalProposalId,
            boolean isIPProtocolLinkingEnabled) {
        if (isIPProtocolLinkingEnabled) {
            InstitutionalProposal institutionalProposal = getLegacyDataAdapter()
                    .findBySinglePrimaryKey(InstitutionalProposal.class, institutionalProposalId);
            for (InstitutionalProposalSpecialReview specialReview : institutionalProposal.getSpecialReviews()) {
                if (SpecialReviewType.HUMAN_SUBJECTS.equals(specialReview.getSpecialReviewTypeCode())) {
                    String protocolNumber = specialReview.getProtocolNumber();
                    String fundingSourceNumber = institutionalProposal.getProposalNumber();
                    String fundingSourceTypeCode = FundingSourceType.INSTITUTIONAL_PROPOSAL;

                    if (!getSpecialReviewService().isLinkedToProtocolFundingSource(protocolNumber,
                            fundingSourceNumber, fundingSourceTypeCode)) {
                        String fundingSourceName = institutionalProposal.getSponsorName();
                        String fundingSourceTitle = institutionalProposal.getTitle();
                        getSpecialReviewService().addProtocolFundingSourceForSpecialReview(protocolNumber,
                                fundingSourceNumber, fundingSourceTypeCode, fundingSourceName, fundingSourceTitle);
                    }
                }
            }
        }
    }

    protected boolean requiresResubmissionPrompt(ProposalDevelopmentDocumentForm proposalDevelopmentForm) {
        return ((ProposalDevelopmentViewHelperService) proposalDevelopmentForm.getViewHelperService())
                .requiresResubmissionPrompt(proposalDevelopmentForm.getDevelopmentProposal(),
                        proposalDevelopmentForm.getResubmissionOption());
    }

    protected boolean autogenerateInstitutionalProposal() {
        return getProposalDevelopmentService().autogenerateInstitutionalProposal();
    }

    private String createInstitutionalProposalVersion(String proposalNumber,
            DevelopmentProposal developmentProposal, Budget budget) {
        return getInstitutionalProposalService().createInstitutionalProposalVersion(proposalNumber,
                developmentProposal, budget);
    }

    protected String createInstitutionalProposal(DevelopmentProposal developmentProposal, Budget budget) {
        String proposalNumber = getInstitutionalProposalService().createInstitutionalProposal(developmentProposal,
                budget);
        Long institutionalProposalId = getActiveProposalId(proposalNumber);
        persistProposalAdminDetails(developmentProposal.getProposalNumber(), institutionalProposalId);
        return proposalNumber;
    }

    private Long getActiveProposalId(String proposalNumber) {
        Collection<InstitutionalProposal> ips = getLegacyDataAdapter().findMatching(InstitutionalProposal.class,
                Collections.singletonMap("proposalNumber", proposalNumber));
        return ((InstitutionalProposal) ips.toArray()[0]).getProposalId();
    }

    protected void persistProposalAdminDetails(String devProposalNumber, Long instProposalId) {
        ProposalAdminDetails proposalAdminDetails = new ProposalAdminDetails();
        addCreateDetails(proposalAdminDetails);
        proposalAdminDetails.setDevProposalNumber(devProposalNumber);
        proposalAdminDetails.setInstProposalId(instProposalId);
        String loggedInUser = getGlobalVariableService().getUserSession().getPrincipalName();
        proposalAdminDetails.setSignedBy(loggedInUser);
        getLegacyDataAdapter().save(proposalAdminDetails);
    }

    private void addCreateDetails(ProposalAdminDetails proposalAdminDetails) {
        proposalAdminDetails.setCreateTimestamp(new Timestamp(System.currentTimeMillis()));
        proposalAdminDetails
                .setCreateUser(getGlobalVariableService().getUserSession().getLoggedInUserPrincipalName());
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=approve")
    public ModelAndView approve(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        form.setAuditActivated(true);

        if (getValidationState(form).equals(AuditHelper.ValidationState.ERROR)) {
            getGlobalVariableService().getMessageMap().putError("datavalidation",
                    KeyConstants.ERROR_WORKFLOW_SUBMISSION);
            return getModelAndViewService().getModelAndView(form);
        }

        WorkflowDocument workflowDoc = form.getProposalDevelopmentDocument().getDocumentHeader()
                .getWorkflowDocument();
        if (canGenerateRequestsInFuture(workflowDoc,
                getGlobalVariableService().getUserSession().getPrincipalId())) {
            DialogResponse dialogResponse = form.getDialogResponse("PropDev-SubmitPage-ReceiveFutureRequests");
            if (dialogResponse == null) {
                return getModelAndViewService().showDialog("PropDev-SubmitPage-ReceiveFutureRequests", false, form);
            } else if (dialogResponse.getResponseAsBoolean()) {
                form.getWorkflowDocument().setReceiveFutureRequests();
            } else {
                form.getWorkflowDocument().setDoNotReceiveFutureRequests();
            }
        }

        getTransactionalDocumentControllerService().performWorkflowAction(form,
                UifConstants.WorkflowAction.APPROVE);
        getPessimisticLockService().releaseWorkflowPessimisticLocking(form.getProposalDevelopmentDocument());
        if (form.getActionFlags().containsKey("submitToSponsor")
                && getParameterService().getParameterValueAsBoolean(ProposalDevelopmentDocument.class,
                        "autoSubmitToSponsorOnFinalApproval")
                && getKcWorkflowService().isFinalApproval(workflowDoc)) {
            return submitToSponsor(form);
        }
        form.setCanEditView(null);
        form.setEvaluateFlagsAndModes(true);
        return updateProposalState(form);
    }

    private boolean canGenerateRequestsInFuture(WorkflowDocument workflowDoc, String principalId) throws Exception {
        RoutingReportCriteria.Builder reportCriteriaBuilder = RoutingReportCriteria.Builder
                .createByDocumentId(workflowDoc.getDocumentId());
        reportCriteriaBuilder.setTargetPrincipalIds(Collections.singletonList(principalId));

        String currentRouteNodeNames = getKradWorkflowDocumentService().getCurrentRouteNodeNames(workflowDoc);

        return (hasAskedToNotReceiveFutureRequests(workflowDoc, principalId) && canGenerateMultipleApprovalRequests(
                reportCriteriaBuilder.build(), principalId, currentRouteNodeNames));
    }

    private boolean hasAskedToNotReceiveFutureRequests(WorkflowDocument workflowDoc, String principalId) {
        boolean receiveFutureRequests = false;
        boolean doNotReceiveFutureRequests = false;

        Map<String, String> variables = workflowDoc.getVariables();

        for (Map.Entry<String, String> entry : variables.entrySet()) {
            String variableKey = entry.getKey();
            String variableValue = entry.getValue();
            if (variableKey.startsWith(KewApiConstants.RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_KEY)
                    && variableValue.toUpperCase()
                            .equals(KewApiConstants.RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_VALUE)
                    && variableKey.contains(principalId)) {
                receiveFutureRequests = true;
                break;
            } else if (variableKey.startsWith(KewApiConstants.RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_KEY)
                    && variableValue.toUpperCase()
                            .equals(KewApiConstants.DONT_RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_VALUE)
                    && variableKey.contains(principalId)) {
                doNotReceiveFutureRequests = true;
                break;
            }
        }

        return (!receiveFutureRequests && !doNotReceiveFutureRequests);
    }

    protected boolean canGenerateMultipleApprovalRequests(RoutingReportCriteria reportCriteria,
            String loggedInPrincipalId, String currentRouteNodeNames) throws Exception {
        int approvalRequestsCount = 0;

        DocumentDetail results1 = getWorkflowDocumentActionsService().executeSimulation(reportCriteria);
        for (ActionRequest actionRequest : results1.getActionRequests()) {
            if (actionRequest.isPending()
                    && actionRequest.getActionRequested().getCode()
                            .equalsIgnoreCase(KewApiConstants.ACTION_REQUEST_APPROVE_REQ)
                    && recipientMatchesUser(actionRequest, loggedInPrincipalId)
                    && !StringUtils.contains(currentRouteNodeNames, actionRequest.getNodeName())) {
                approvalRequestsCount += 1;
            }
        }

        return (approvalRequestsCount > 0);
    }

    protected boolean recipientMatchesUser(ActionRequest actionRequest, String loggedInPrincipalId) {
        if (actionRequest != null && loggedInPrincipalId != null) {
            List<ActionRequest> actionRequests = Collections.singletonList(actionRequest);
            if (actionRequest.isRoleRequest()) {
                actionRequests = actionRequest.getChildRequests();
            }
            for (ActionRequest cActionRequest : actionRequests) {
                String recipientUser = cActionRequest.getPrincipalId();
                if ((recipientUser != null && recipientUser.equals(loggedInPrincipalId))
                        || (StringUtils.isNotBlank(cActionRequest.getGroupId()) && getGroupService()
                                .isMemberOfGroup(loggedInPrincipalId, cActionRequest.getGroupId()))) {
                    return true;
                }
            }
        }

        return false;
    }

    protected ModelAndView updateProposalState(ProposalDevelopmentDocumentForm form) throws Exception {
        if (getKcWorkflowService().isFinalApproval(form.getWorkflowDocument())) {
            form.getDevelopmentProposal().setProposalStateTypeCode(ProposalState.APPROVAL_GRANTED);
            getGlobalVariableService().getMessageMap().getInfoMessages().clear();
            getGlobalVariableService().getMessageMap().putInfoForSectionId(
                    ProposalDevelopmentConstants.KradConstants.SUBMIT_PAGE, KeyConstants.APPROVAL_CYCLE_COMPLETE);
        } else {
            form.getDevelopmentProposal().setProposalStateTypeCode(getProposalStateService()
                    .getProposalStateTypeCode(form.getProposalDevelopmentDocument(), false));
        }
        getDataObjectService().wrap(form.getDevelopmentProposal()).fetchRelationship("proposalState");
        return getModelAndViewService().getModelAndView(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=reject")
    public ModelAndView reject(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form) throws Exception {

        ProposalDevelopmentRejectionBean bean = form.getProposalDevelopmentRejectionBean();
        if (new ProposalDevelopmentRejectionRule().proccessProposalDevelopmentRejection(bean)) {
            getProposalHierarchyService().rejectProposalDevelopmentDocument(
                    form.getDevelopmentProposal().getProposalNumber(), bean.getRejectReason(),
                    getGlobalVariableService().getUserSession().getPrincipalId(), bean.getRejectFile());
        }

        form.setCanEditView(null);
        form.setEvaluateFlagsAndModes(true);
        return getTransactionalDocumentControllerService().reload(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=cancelReject")
    public ModelAndView cancelReject(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form)
            throws Exception {
        form.setProposalDevelopmentRejectionBean(new ProposalDevelopmentRejectionBean());
        return getModelAndViewService().getModelAndView(form);
    }

    @Transactional
    @RequestMapping(value = "/proposalDevelopment", params = "methodToCall=sendAdHocRequests")
    public ModelAndView sendAdHocRequests(@ModelAttribute("KualiForm") ProposalDevelopmentDocumentForm form) {
        form.setCanEditView(null);
        form.setEvaluateFlagsAndModes(true);
        return getTransactionalDocumentControllerService().sendAdHocRequests(form);
    }

    public GlobalVariableService getGlobalVariableService() {
        return globalVariableService;
    }

    private void submitS2sApplication(ProposalDevelopmentDocument proposalDevelopmentDocument) throws Exception {
        getS2sSubmissionService().submitApplication(proposalDevelopmentDocument);
    }

    public S2sSubmissionService getS2sSubmissionService() {
        return s2sSubmissionService;
    }

    public void setS2sSubmissionService(S2sSubmissionService s2sSubmissionService) {
        this.s2sSubmissionService = s2sSubmissionService;
    }

    public InstitutionalProposalService getInstitutionalProposalService() {
        return institutionalProposalService;
    }

    public void setInstitutionalProposalService(InstitutionalProposalService institutionalProposalService) {
        this.institutionalProposalService = institutionalProposalService;
    }

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

    public ConfigurationService getConfigurationService() {
        return configurationService;
    }

    public void setConfigurationService(ConfigurationService configurationService) {
        this.configurationService = configurationService;
    }

    public KcNotificationService getKcNotificationService() {
        return kcNotificationService;
    }

    public void setKcNotificationService(KcNotificationService kcNotificationService) {
        this.kcNotificationService = kcNotificationService;
    }

    public KualiRuleService getKualiRuleService() {
        return kualiRuleService;
    }

    public void setKualiRuleService(KualiRuleService kualiRuleService) {
        this.kualiRuleService = kualiRuleService;
    }

    public WizardControllerService getWizardControllerService() {
        return wizardControllerService;
    }

    public void setWizardControllerService(WizardControllerService wizardControllerService) {
        this.wizardControllerService = wizardControllerService;
    }

    public WorkflowDocumentService getKradWorkflowDocumentService() {
        return kradWorkflowDocumentService;
    }

    public void setKradWorkflowDocumentService(WorkflowDocumentService kradWorkflowDocumentService) {
        this.kradWorkflowDocumentService = kradWorkflowDocumentService;
    }

    public WorkflowDocumentActionsService getWorkflowDocumentActionsService() {
        return workflowDocumentActionsService;
    }

    public void setWorkflowDocumentActionsService(WorkflowDocumentActionsService workflowDocumentActionsService) {
        this.workflowDocumentActionsService = workflowDocumentActionsService;
    }

    public GroupService getGroupService() {
        return groupService;
    }

    public void setGroupService(GroupService groupService) {
        this.groupService = groupService;
    }

    public ProposalHierarchyService getProposalHierarchyService() {
        return proposalHierarchyService;
    }

    public void setProposalHierarchyService(ProposalHierarchyService proposalHierarchyService) {
        this.proposalHierarchyService = proposalHierarchyService;
    }

    public ProposalDevelopmentNotificationRenderer getRenderer() {
        return renderer;
    }

    public void setRenderer(ProposalDevelopmentNotificationRenderer renderer) {
        this.renderer = renderer;
    }

    public KcBusinessRulesEngine getKcBusinessRulesEngine() {
        return kcBusinessRulesEngine;
    }

    public void setKcBusinessRulesEngine(KcBusinessRulesEngine kcBusinessRulesEngine) {
        this.kcBusinessRulesEngine = kcBusinessRulesEngine;
    }

    public KrmsRulesExecutionService getKrmsRulesExecutionService() {
        return krmsRulesExecutionService;
    }

    public void setKrmsRulesExecutionService(KrmsRulesExecutionService krmsRulesExecutionService) {
        this.krmsRulesExecutionService = krmsRulesExecutionService;
    }

    public ParameterService getParameterService() {
        return parameterService;
    }

    public void setParameterService(ParameterService parameterService) {
        this.parameterService = parameterService;
    }

    public ProposalStateService getProposalStateService() {
        return proposalStateService;
    }

    public void setProposalStateService(ProposalStateService proposalStateService) {
        this.proposalStateService = proposalStateService;
    }

    public SpecialReviewService getSpecialReviewService() {
        return specialReviewService;
    }

    public void setSpecialReviewService(SpecialReviewService specialReviewService) {
        this.specialReviewService = specialReviewService;
    }

    public LegacyDataAdapter getLegacyDataAdapter() {
        return legacyDataAdapter;
    }

    public KcWorkflowService getKcWorkflowService() {
        return kcWorkflowService;
    }

    public void setKcWorkflowService(KcWorkflowService kcWorkflowService) {
        this.kcWorkflowService = kcWorkflowService;
    }
}