protected boolean getModifyNarrativePermission(
      ProposalDevelopmentDocument document, Person user) {
    DocumentRequestAuthorizationCache documentRequestAuthorizationCache =
        getDocumentRequestAuthorizationCache(document);

    boolean hasModifyNarrativePermission;

    String modifyNarrativeCacheKey =
        "ModifyNarrative|" + document.getDocumentNumber() + "|" + user.getPrincipalId();
    if (documentRequestAuthorizationCache.hasPermissionResult(modifyNarrativeCacheKey)) {
      hasModifyNarrativePermission =
          documentRequestAuthorizationCache.getPermissionResult(modifyNarrativeCacheKey);
    } else {
      hasModifyNarrativePermission =
          getKcAuthorizationService()
              .hasPermission(user.getPrincipalId(), document, PermissionConstants.MODIFY_NARRATIVE);
      documentRequestAuthorizationCache.addPermissionResult(
          modifyNarrativeCacheKey, hasModifyNarrativePermission);
    }
    if (!hasModifyNarrativePermission) {
      hasModifyNarrativePermission =
          !document.getDevelopmentProposal().getSubmitFlag()
              && document.getDocumentHeader().getWorkflowDocument().isEnroute()
              && getKcAuthorizationService()
                  .hasPermission(
                      user.getPrincipalId(), document, PermissionConstants.ALTER_PROPOSAL_DATA);
      documentRequestAuthorizationCache.addPermissionResult(
          modifyNarrativeCacheKey, hasModifyNarrativePermission);
    }

    return hasModifyNarrativePermission;
  }
  protected boolean hasModifyS2sEnroutePermission(Document document, Person user) {
    DocumentRequestAuthorizationCache documentRequestAuthorizationCache =
        getDocumentRequestAuthorizationCache(document);
    final String cacheKey =
        buildPermissionCacheKey(document, user, PermissionConstants.MODIFY_S2S_ENROUTE);
    Boolean cachedResult = getCachedPermissionResult(document, cacheKey);
    boolean hasS2sPermission;

    if (cachedResult != null) {
      hasS2sPermission = cachedResult;
    } else {
      ProposalDevelopmentDocument pdDocument = (ProposalDevelopmentDocument) document;
      hasS2sPermission =
          getKcAuthorizationService()
              .hasPermission(
                  user.getPrincipalId(), pdDocument, PermissionConstants.MODIFY_S2S_ENROUTE);
    }

    final ProposalDevelopmentDocument pdDocument = ((ProposalDevelopmentDocument) document);
    final DevelopmentProposal proposal = pdDocument.getDevelopmentProposal();

    if (proposal.isChild() && hasS2sPermission) {
      final Document parent = proposal.getParent().getDocument();
      final String parentResultCacheKey =
          buildPermissionCacheKey(parent, user, PermissionConstants.MODIFY_S2S_ENROUTE);
      documentRequestAuthorizationCache.getPermissionResultCache().remove(parentResultCacheKey);
      hasS2sPermission = isAuthorizedToModifyBudget(parent, user);
    }

    addCachedPermissionResult(document, cacheKey, hasS2sPermission);

    return hasS2sPermission;
  }
 Boolean getCachedPermissionResult(Document document, String permissionCacheKey) {
   DocumentRequestAuthorizationCache documentRequestAuthorizationCache =
       getDocumentRequestAuthorizationCache(document);
   if (documentRequestAuthorizationCache.hasPermissionResult(permissionCacheKey)) {
     return documentRequestAuthorizationCache.getPermissionResult(permissionCacheKey);
   } else {
     return null;
   }
 }
  protected boolean isAuthorizedToModify(Document document, Person user) {
    DocumentRequestAuthorizationCache documentRequestAuthorizationCache =
        getDocumentRequestAuthorizationCache(document);

    final String resultCacheKey = buildPermissionCacheKey(document, user, IS_AUTHORIZED_TO_MODIFY);
    if (documentRequestAuthorizationCache.hasPermissionResult(resultCacheKey)) {
      return documentRequestAuthorizationCache.getPermissionResult(resultCacheKey);
    }

    final ProposalDevelopmentDocument pdDocument = ((ProposalDevelopmentDocument) document);
    final DevelopmentProposal proposal = pdDocument.getDevelopmentProposal();

    if (!isEditableState(proposal.getProposalStateTypeCode())) {
      return false;
    }

    final String proposalNbr = proposal.getProposalNumber();

    boolean hasPermission;
    if (proposalNbr == null) {
      hasPermission = hasPermissionByOwnedByUnit(document, user);
    } else {
      /*
       * After the initial save, the proposal can only be modified if it is not in workflow
       * and the user has the require permission.
       */

      final boolean hasBeenRejected =
          ProposalState.REVISIONS_REQUESTED.equals(proposal.getProposalStateTypeCode());

      hasPermission =
          !pdDocument.isViewOnly()
              && getKcAuthorizationService()
                  .hasPermission(
                      user.getPrincipalId(), pdDocument, PermissionConstants.MODIFY_PROPOSAL)
              && (!getKcWorkflowService().isInWorkflow(document) || hasBeenRejected)
              && !proposal.getSubmitFlag();
    }

    if (proposal.isChild() && hasPermission) {
      final Document parent = proposal.getParent().getDocument();
      final String parentResultCacheKey =
          buildPermissionCacheKey(parent, user, IS_AUTHORIZED_TO_MODIFY);
      documentRequestAuthorizationCache.getPermissionResultCache().remove(parentResultCacheKey);
      hasPermission = isAuthorizedToModify(parent, user);
    }

    documentRequestAuthorizationCache.addPermissionResult(resultCacheKey, hasPermission);

    return hasPermission;
  }
  protected boolean canSaveCertification(ProposalDevelopmentDocument document, Person user) {
    final DevelopmentProposal proposal = document.getDevelopmentProposal();

    DocumentRequestAuthorizationCache documentRequestAuthorizationCache =
        getDocumentRequestAuthorizationCache(document);

    boolean hasSaveCertificationPermission;

    final String saveCertificationCacheKey =
        buildPermissionCacheKey(document, user, SAVE_CERTIFICATION);
    if (documentRequestAuthorizationCache.hasPermissionResult(saveCertificationCacheKey)) {
      hasSaveCertificationPermission =
          documentRequestAuthorizationCache.getPermissionResult(saveCertificationCacheKey);
    } else {
      hasSaveCertificationPermission =
          isProposalStateEditableForCertification(document.getDevelopmentProposal())
              && document
                  .getDevelopmentProposal()
                  .getProposalPersons()
                  .stream()
                  .filter(
                      person ->
                          getProposalDevelopmentPermissionsService()
                              .hasCertificationPermissions(document, user, person))
                  .anyMatch(person -> true);
    }

    if (proposal.isChild() && hasSaveCertificationPermission) {
      final Document parent = proposal.getParent().getDocument();
      final String parentResultCacheKey = buildPermissionCacheKey(parent, user, SAVE_CERTIFICATION);
      documentRequestAuthorizationCache.getPermissionResultCache().remove(parentResultCacheKey);
      hasSaveCertificationPermission =
          canSaveCertification((ProposalDevelopmentDocument) parent, user);
    }

    documentRequestAuthorizationCache.addPermissionResult(
        saveCertificationCacheKey, hasSaveCertificationPermission);

    return hasSaveCertificationPermission;
  }
  protected boolean isAuthorizedToModifyBudget(Document document, Person user) {
    final ProposalDevelopmentDocument pdDocument = ((ProposalDevelopmentDocument) document);
    final DevelopmentProposal proposal = pdDocument.getDevelopmentProposal();

    DocumentRequestAuthorizationCache documentRequestAuthorizationCache =
        getDocumentRequestAuthorizationCache(pdDocument);

    boolean hasModifyBudgetPermission;

    final String modifyBudgetCacheKey = buildPermissionCacheKey(pdDocument, user, MODIFY_BUDGET);
    if (documentRequestAuthorizationCache.hasPermissionResult(modifyBudgetCacheKey)) {
      hasModifyBudgetPermission =
          documentRequestAuthorizationCache.getPermissionResult(modifyBudgetCacheKey);
    } else {
      hasModifyBudgetPermission =
          getKcAuthorizationService()
              .hasPermission(user.getPrincipalId(), pdDocument, PermissionConstants.MODIFY_BUDGET);
    }

    boolean rejectedDocument =
        getKcDocumentRejectionService()
            .isDocumentOnInitialNode(pdDocument.getDocumentHeader().getWorkflowDocument());
    hasModifyBudgetPermission =
        ((!getKcWorkflowService().isInWorkflow(pdDocument) || rejectedDocument)
            && hasModifyBudgetPermission);

    if (proposal.isChild() && hasModifyBudgetPermission) {
      final Document parent = proposal.getParent().getDocument();
      final String parentResultCacheKey = buildPermissionCacheKey(parent, user, MODIFY_BUDGET);
      documentRequestAuthorizationCache.getPermissionResultCache().remove(parentResultCacheKey);
      hasModifyBudgetPermission = isAuthorizedToModifyBudget(parent, user);
    }

    documentRequestAuthorizationCache.addPermissionResult(
        modifyBudgetCacheKey, hasModifyBudgetPermission);

    return hasModifyBudgetPermission;
  }
  protected boolean isAuthorizedToMaintainProposalHierarchy(Document document, Person user) {
    final ProposalDevelopmentDocument pdDocument = ((ProposalDevelopmentDocument) document);
    final DevelopmentProposal proposal = pdDocument.getDevelopmentProposal();

    DocumentRequestAuthorizationCache documentRequestAuthorizationCache =
        getDocumentRequestAuthorizationCache(pdDocument);

    boolean hasMaintainProposalHierarchyPermission;

    final String cacheKey =
        buildPermissionCacheKey(pdDocument, user, PermissionConstants.MAINTAIN_PROPOSAL_HIERARCHY);
    if (documentRequestAuthorizationCache.hasPermissionResult(cacheKey)) {
      hasMaintainProposalHierarchyPermission =
          documentRequestAuthorizationCache.getPermissionResult(cacheKey);
    } else {
      hasMaintainProposalHierarchyPermission =
          getKcAuthorizationService()
              .hasPermission(
                  user.getPrincipalId(),
                  pdDocument,
                  PermissionConstants.MAINTAIN_PROPOSAL_HIERARCHY);
    }

    if (proposal.isChild() && hasMaintainProposalHierarchyPermission) {
      final Document parent = proposal.getParent().getDocument();
      final String parentResultCacheKey =
          buildPermissionCacheKey(parent, user, PermissionConstants.MAINTAIN_PROPOSAL_HIERARCHY);
      documentRequestAuthorizationCache.getPermissionResultCache().remove(parentResultCacheKey);
      hasMaintainProposalHierarchyPermission = isAuthorizedToModifyBudget(parent, user);
    }

    documentRequestAuthorizationCache.addPermissionResult(
        cacheKey, hasMaintainProposalHierarchyPermission);

    return hasMaintainProposalHierarchyPermission;
  }
 void addCachedPermissionResult(Document document, String permissionCacheKey, boolean result) {
   DocumentRequestAuthorizationCache documentRequestAuthorizationCache =
       getDocumentRequestAuthorizationCache(document);
   documentRequestAuthorizationCache.addPermissionResult(permissionCacheKey, result);
 }