protected void cancelOnlineReviewDocument(
      ProtocolOnlineReviewDocumentBase protocolOnlineReviewDocument,
      ProtocolSubmissionBase submission,
      String annotation) {
    try {

      final String principalId =
          identityManagementService
              .getPrincipalByPrincipalName(KRADConstants.SYSTEM_USER)
              .getPrincipalId();
      WorkflowDocument workflowDocument =
          WorkflowDocumentFactory.loadDocument(
              principalId, protocolOnlineReviewDocument.getDocumentNumber());

      if (workflowDocument.isEnroute()
          || workflowDocument.isInitiated()
          || workflowDocument.isSaved()) {
        workflowDocument.superUserCancel(
            String.format(
                "Review Cancelled from assign reviewers action by %s",
                GlobalVariables.getUserSession().getPrincipalId()));
      }
    } catch (Exception e) {
      String errorMessage =
          String.format(
              "Exception generated while executing superUserCancel on document %s in removeOnlineReviewDocument. Message: %s",
              protocolOnlineReviewDocument.getDocumentNumber(), e.getMessage());
      LOG.error(errorMessage);
      throw new RuntimeException(errorMessage, e);
    }
  }
 /**
  * Adding the role qualifications for the processing chart and organization
  *
  * @see
  *     org.kuali.rice.kns.document.authorization.DocumentAuthorizerBase#addRoleQualification(org.kuali.rice.kns.bo.BusinessObject,
  *     java.util.Map)
  */
 @Override
 protected void addRoleQualification(Object businessObject, Map<String, String> attributes) {
   super.addRoleQualification(businessObject, attributes);
   if (businessObject != null && businessObject instanceof PaymentApplicationDocument) {
     final PaymentApplicationDocument document = (PaymentApplicationDocument) businessObject;
     final WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
     if (workflowDocument.isInitiated()
         || workflowDocument.isSaved()
         || workflowDocument
             .isCompletionRequested()) { // only add processing chart and org if we're PreRoute
       final AccountsReceivableDocumentHeader arDocumentHeader =
           document.getAccountsReceivableDocumentHeader();
       if (!ObjectUtils.isNull(arDocumentHeader)) {
         if (!StringUtils.isBlank(arDocumentHeader.getProcessingChartOfAccCodeAndOrgCode())) {
           attributes.put(
               KfsKimAttributes.CHART_OF_ACCOUNTS_CODE,
               arDocumentHeader.getProcessingChartOfAccountCode());
         }
         if (!StringUtils.isBlank(arDocumentHeader.getProcessingOrganizationCode())) {
           attributes.put(
               KfsKimAttributes.ORGANIZATION_CODE,
               arDocumentHeader.getProcessingOrganizationCode());
         }
       }
     }
   }
 }
  /**
   * Test the approval of a protocol. The protocol status and its corresponding action should be set
   * to approved.
   */
  @Test
  public void runApprovedTest() throws Exception {
    ProtocolDocument protocolDocument = ProtocolFactory.createProtocolDocument();

    protocolSubmitActionService.submitToIrbForReview(
        protocolDocument.getProtocol(), getMockSubmitAction());

    documentService.routeDocument(protocolDocument, null, null);
    documentService.blanketApproveDocument(protocolDocument, null, null);
    WorkflowDocument workflowDoc = getWorkflowDocument(protocolDocument);
    WorkflowDocumentActionsService info =
        GlobalResourceLoader.getService("rice.kew.workflowDocumentActionsService");
    RoutingReportCriteria.Builder reportCriteriaBuilder =
        RoutingReportCriteria.Builder.createByDocumentId(workflowDoc.getDocumentId());
    DocumentDetail results1 = info.executeSimulation(reportCriteriaBuilder.build());

    assertTrue(workflowDoc.isFinal());

    // the status update is not happening within doRouteStatusChange anymore
    // assertEquals(protocolDocument.getProtocol().getProtocolStatusCode(),
    // ProtocolStatus.ACTIVE_OPEN_TO_ENROLLMENT);
    assertTrue(protocolDocument.getProtocol().isActive());
    // verifyProtocolAction(protocolDocument.getProtocol().getProtocolId(),
    // ProtocolActionType.APPROVED);
  }
  /**
   * @see
   *     org.kuali.kfs.module.ar.document.service.InvoiceRecurrenceService#isInvoiceApproved(String)
   */
  @Override
  public boolean isInvoiceApproved(String invoiceNumber) {
    boolean success = true;

    if (ObjectUtils.isNull(invoiceNumber)) {
      return success;
    }

    CustomerInvoiceDocument customerInvoiceDocument = null;
    try {
      customerInvoiceDocument =
          (CustomerInvoiceDocument)
              SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(invoiceNumber);
    } catch (WorkflowException e) {

    }
    if (ObjectUtils.isNotNull(customerInvoiceDocument)) {
      WorkflowDocument workflowDocument =
          customerInvoiceDocument.getDocumentHeader().getWorkflowDocument();
      if (!(workflowDocument.isApproved())) {
        success = false;
      }
    } else {
      success = false;
    }
    return success;
  }
  @Override
  public List<String> buildListForFYI(AwardDocument awardDocument) throws WorkflowException {

    WorkflowDocument document = awardDocument.getDocumentHeader().getWorkflowDocument();
    RoutingReportCriteria reportCriteria =
        RoutingReportCriteria.Builder.createByDocumentId(document.getDocumentId()).build();
    // gather the IDs for action requests that predate the simulation
    DocumentRouteHeaderValue routeHeader =
        KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
    Set<String> preexistingActionRequestIds = getActionRequestIds(routeHeader);

    // run the simulation via WorkflowUtility
    DocumentDetail documentDetail = workflowUtility.executeSimulation(reportCriteria);

    // fabricate our ActionRequestValueS from the results
    List<ActionRequestValue> actionRequests =
        reconstituteActionRequestValues(documentDetail, preexistingActionRequestIds);

    List<String> actionIds = new ArrayList<String>();
    for (ActionRequestValue request : actionRequests) {
      if (request.isGroupRequest()) {
        actionIds.addAll(
            KimApiServiceLocator.getGroupService().getMemberPrincipalIds(request.getGroupId()));
      }
      if (request.isUserRequest()) {
        actionIds.add(request.getPrincipalId());
      }
    }
    return actionIds;
  }
  /**
   * @see
   *     org.kuali.rice.krad.service.DocumentService#getByDocumentHeaderIdSessionless(java.lang.String)
   */
  @Override
  public Document getByDocumentHeaderIdSessionless(String documentHeaderId)
      throws WorkflowException {
    if (documentHeaderId == null) {
      throw new IllegalArgumentException("invalid (null) documentHeaderId");
    }

    WorkflowDocument workflowDocument = null;

    if (LOG.isDebugEnabled()) {
      LOG.debug("Retrieving doc id: " + documentHeaderId + " from workflow service.");
    }

    Person person = getPersonService().getPersonByPrincipalName(KRADConstants.SYSTEM_USER);
    workflowDocument = workflowDocumentService.loadWorkflowDocument(documentHeaderId, person);

    Class<? extends Document> documentClass =
        getDocumentClassByTypeName(workflowDocument.getDocumentTypeName());

    // retrieve the Document
    Document document =
        getLegacyDataAdapter().findByDocumentHeaderId(documentClass, documentHeaderId);

    return postProcessDocument(documentHeaderId, workflowDocument, document);
  }
  /**
   * Overridden to guarantee that form of copied document is set to whatever the entry mode of the
   * document is
   *
   * @see org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase#copy
   *     (org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm,
   *     javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
   */
  @Override
  public ActionForward copy(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
    ActionForward forward = null;
    String docID = "docId";
    if (request.getParameter(docID) == null) {
      forward = super.copy(mapping, form, request, response);
    } else {
      // this is copy document from Procurement Gateway:
      // use this url to call:
      // http://localhost:8080/kfs-dev/purapRequisition.do?methodToCall=copy&docId=xxxx
      String docId = request.getParameter(docID);
      KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;

      CuRequisitionDocument document = null;
      document = (CuRequisitionDocument) getDocumentService().getByDocumentHeaderId(docId);
      document.toCopyFromGateway();

      kualiDocumentFormBase.setDocument(document);
      WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
      kualiDocumentFormBase.setDocTypeName(workflowDocument.getDocumentTypeName());
      SpringContext.getBean(SessionDocumentService.class)
          .addDocumentToUserSession(GlobalVariables.getUserSession(), workflowDocument);

      forward = mapping.findForward(RiceConstants.MAPPING_BASIC);
    }
    return forward;
  }
 /**
  * @see
  *     org.kuali.rice.ken.service.NotificationWorkflowDocumentService#terminateWorkflowDocument(org.kuali.rice.kew.api.WorkflowDocument)
  */
 public void terminateWorkflowDocument(WorkflowDocument document) {
   document.superUserCancel(
       "terminating document: documentId="
           + document.getDocumentId()
           + ", appDocId="
           + document.getApplicationDocumentId());
 }
  public ProtocolOnlineReviewDocumentBase createProtocolOnlineReviewDocument(
      ProtocolSubmissionBase protocolSubmission,
      ProtocolReviewer protocolReviewer,
      String documentDescription,
      String documentExplanation,
      String documentOrganizationDocumentNumber,
      Date dateRequested,
      Date dateDue,
      String principalId)
      throws WorkflowException {

    IacucProtocolOnlineReviewDocument protocolReviewDocument;

    Person person = personService.getPerson(principalId);
    WorkflowDocument workflowDocument =
        workflowDocumentService.createWorkflowDocument(
            IACUC_PROTOCOL_ONLINE_REVIEW_DOCUMENT_TYPE, person);

    DocumentHeader docHeader = new DocumentHeader();
    docHeader.setWorkflowDocument(workflowDocument);
    docHeader.setDocumentNumber(workflowDocument.getDocumentId().toString());
    protocolReviewDocument = new IacucProtocolOnlineReviewDocument();
    protocolReviewDocument.setDocumentNumber(docHeader.getDocumentNumber());
    protocolReviewDocument.setDocumentHeader(docHeader);

    protocolReviewDocument.getProtocolOnlineReview().setProtocol(protocolSubmission.getProtocol());

    protocolReviewDocument
        .getProtocolOnlineReview()
        .setProtocolId(protocolSubmission.getProtocolId());

    protocolReviewDocument.getProtocolOnlineReview().setProtocolSubmission(protocolSubmission);
    protocolReviewDocument
        .getProtocolOnlineReview()
        .setSubmissionIdFk(protocolSubmission.getSubmissionId());
    protocolReviewDocument
        .getProtocolOnlineReview()
        .setProtocolOnlineReviewStatusCode(IacucProtocolOnlineReviewStatus.SAVED_STATUS_CD);
    protocolReviewDocument
        .getProtocolOnlineReview()
        .setDateRequested(
            dateRequested == null ? new Date((new java.util.Date()).getTime()) : dateRequested);
    protocolReviewDocument.getProtocolOnlineReview().setDateDue(dateDue);

    protocolReviewDocument
        .getProtocolOnlineReview()
        .setProtocolReviewerId(protocolReviewer.getProtocolReviewerId());
    protocolReviewDocument.getProtocolOnlineReview().setProtocolReviewer(protocolReviewer);

    docHeader.setDocumentDescription(documentDescription);
    docHeader.setOrganizationDocumentNumber(documentOrganizationDocumentNumber);
    docHeader.setExplanation(documentExplanation);

    documentService.saveDocument(protocolReviewDocument);
    return protocolReviewDocument;
  }
  /**
   * Creates a new ProtocolReviewDocument.
   *
   * <p>Handles creating the workflow document, and the underlying ProtocolReview BO linking the
   * protocol, submission, and reviewer.
   *
   * @param protocolSubmission The protocol submission
   * @param protocolReviewerBean The bean that holds
   * @param documentDescription the description for the created document
   * @param documentExplanation the explanation for the created document
   * @param documentOrganizationNumber the organizationNumber for the created document
   * @param principalId The principalId to use when creating the workflow document. Usually this
   *     should be the principal of the user creating the review.
   * @return
   * @throws WorkflowException
   */
  protected ProtocolOnlineReviewDocumentBase createProtocolOnlineReviewDocument(
      ProtocolSubmissionBase protocolSubmission,
      ProtocolReviewer protocolReviewer,
      String documentDescription,
      String documentExplanation,
      String documentOrganizationDocumentNumber,
      Date dateRequested,
      Date dateDue,
      String principalId)
      throws WorkflowException {

    ProtocolOnlineReviewDocumentBase protocolReviewDocument;

    Person person = personService.getPerson(principalId);
    WorkflowDocument workflowDocument =
        workflowDocumentService.createWorkflowDocument(getProtocolOLRDocumentTypeHook(), person);

    DocumentHeader docHeader = new DocumentHeader();
    docHeader.setWorkflowDocument(workflowDocument);
    docHeader.setDocumentNumber(workflowDocument.getDocumentId().toString());
    protocolReviewDocument = getNewProtocolOnlineReviewDocumentInstanceHook();
    protocolReviewDocument.setDocumentNumber(docHeader.getDocumentNumber());
    protocolReviewDocument.setDocumentHeader(docHeader);

    protocolReviewDocument.getProtocolOnlineReview().setProtocol(protocolSubmission.getProtocol());

    protocolReviewDocument
        .getProtocolOnlineReview()
        .setProtocolId(protocolSubmission.getProtocolId());

    protocolReviewDocument.getProtocolOnlineReview().setProtocolSubmission(protocolSubmission);
    protocolReviewDocument
        .getProtocolOnlineReview()
        .setSubmissionIdFk(protocolSubmission.getSubmissionId());
    protocolReviewDocument
        .getProtocolOnlineReview()
        .setProtocolOnlineReviewStatusCode(getProtocolOLRSavedStatusCodeHook());
    protocolReviewDocument
        .getProtocolOnlineReview()
        .setDateRequested(
            dateRequested == null ? new Date((new java.util.Date()).getTime()) : dateRequested);
    protocolReviewDocument.getProtocolOnlineReview().setDateDue(dateDue);

    protocolReviewDocument
        .getProtocolOnlineReview()
        .setProtocolReviewerId(protocolReviewer.getProtocolReviewerId());
    protocolReviewDocument.getProtocolOnlineReview().setProtocolReviewer(protocolReviewer);

    docHeader.setDocumentDescription(documentDescription);
    docHeader.setOrganizationDocumentNumber(documentOrganizationDocumentNumber);
    docHeader.setExplanation(documentExplanation);

    documentService.saveDocument(protocolReviewDocument);
    return protocolReviewDocument;
  }
  @Override
  public boolean canEditDocumentOverview(Document document) {
    WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
    Set<String> nodeNames = workflowDocument.getCurrentNodeNames();

    return workflowDocument.isEnroute()
        && CollectionUtils.isNotEmpty(nodeNames)
        && nodeNames.contains(KFSConstants.RouteLevelNames.ACCOUNT_REVIEW_FULL_EDIT)
        && workflowDocument.isApprovalRequested()
        && !workflowDocument.isAcknowledgeRequested();
  }
 protected void performDisapprove(ProtocolBase protocol) throws Exception {
   if (protocol.getProtocolDocument() != null) {
     WorkflowDocument currentWorkflowDocument =
         protocol.getProtocolDocument().getDocumentHeader().getWorkflowDocument();
     if (currentWorkflowDocument != null) {
       currentWorkflowDocument.disapprove(
           "Protocol document disapproved after committee decision");
     }
   }
   getProtocolOnlineReviewService()
       .cancelOnlineReviews(
           protocol.getProtocolSubmission(),
           "Protocol Review cancelled - protocol has been disapproved.");
 }
  /**
   * Tests that an exception is not thrown if you try to execute a "route" command on a document you
   * did not initiate.
   */
  @Test
  public void testRouteDocumentAsNonInitiatorUser() throws Exception {
    WorkflowDocument firstDocument =
        WorkflowDocumentFactory.createDocument(
            getPrincipalIdForName("user1"), DOCUMENT_TYPE_POLICY_TEST_NAME);
    WorkflowDocument document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("user2"), firstDocument.getDocumentId());
    try {
      document.route("");
    } catch (Exception e) {
      e.printStackTrace();
      fail(
          "Exception thrown but should not have have been... Exception was of type "
              + e.getClass().getName()
              + " and message was "
              + e.getMessage());
    }
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("user1"), firstDocument.getDocumentId());
    assertEquals(
        "Document should be in Enroute status.", DocumentStatus.ENROUTE, document.getStatus());

    // verify that there is 1 action taken
    Collection<ActionTakenValue> actionTakens =
        KEWServiceLocator.getActionTakenService().findByDocumentId(document.getDocumentId());
    assertEquals("There should be 1 action taken.", 1, actionTakens.size());
  }
  /**
   * Tests that an exception is thrown if you try to execute a "route" command on an already routed
   * document.
   */
  @Test
  public void testRouteAlreadyRoutedDocument() throws Exception {
    WorkflowDocument document =
        WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), DOCUMENT_TYPE_NAME);
    document.route("");

    assertTrue("Document should be ENROUTE.", document.isEnroute());
    assertFalse("There should not be a request to ewestfal.", document.isApprovalRequested());

    // verify that only 1 action taken has been performed
    Collection<ActionTakenValue> actionTakens =
        KEWServiceLocator.getActionTakenService().findByDocumentId(document.getDocumentId());
    assertEquals("There should be only 1 action taken.", 1, actionTakens.size());

    // now try and route the document again, an exception should be thrown
    try {
      document.route("");
      fail("A WorkflowException should have been thrown.");
    } catch (InvalidActionTakenException e) {
      e.printStackTrace();
    }

    // verify that there is still only 1 action taken (the transaction above should have rolled
    // back)
    actionTakens =
        KEWServiceLocator.getActionTakenService().findByDocumentId(document.getDocumentId());
    assertEquals("There should still be only 1 action taken.", 1, actionTakens.size());
  }
 private WorkflowAttributeDefinition.Builder getWorkflowAttributeDefinitionVO(
     String attributeName, WorkflowDocument document) {
   for (WorkflowAttributeDefinition attributeDefinition : document.getAttributeDefinitions()) {
     if (attributeDefinition.getAttributeName().equals(attributeName)) {
       return WorkflowAttributeDefinition.Builder.create(attributeDefinition);
     }
   }
   return WorkflowAttributeDefinition.Builder.create(attributeName);
 }
 /**
  * Check if workflow is at the specific node
  *
  * @param workflowDocument
  * @param nodeName
  * @return
  */
 protected boolean isAtTravelNode(WorkflowDocument workflowDocument) {
   Set<String> nodeNames = workflowDocument.getNodeNames();
   for (String nodeNamesNode : nodeNames) {
     if (TemWorkflowConstants.RouteNodeNames.AP_TRAVEL.equals(nodeNamesNode)) {
       return true;
     }
   }
   return false;
 }
 /**
  * @see
  *     org.kuali.rice.ken.service.NotificationWorkflowDocumentService#clearAllFyisAndAcknowledgeNotificationWorkflowDocument(java.lang.String,
  *     org.kuali.rice.ken.document.kew.NotificationWorkflowDocument, java.lang.String)
  */
 public void clearAllFyisAndAcknowledgeNotificationWorkflowDocument(
     String initiatorUserId, WorkflowDocument workflowDocument, String annotation) {
   List<ActionRequest> reqs = workflowDocument.getRootActionRequests();
   for (int i = 0; i < reqs.size(); i++) {
     LOG.info("Action Request[" + i + "] = " + reqs.get(i).getActionRequested());
     if (reqs.get(i).getActionRequested().equals(ActionRequestType.ACKNOWLEDGE)) {
       workflowDocument.acknowledge(annotation);
     } else if (reqs.get(i).getActionRequested().equals(ActionRequestType.FYI)) {
       workflowDocument.logAnnotation(annotation);
       workflowDocument.fyi();
     } else {
       throw new WorkflowRuntimeException(
           "Invalid notification action request in workflow document ("
               + workflowDocument.getDocumentId()
               + ") was encountered.  Should be either an acknowledge or fyi and was not.");
     }
   }
 }
Example #18
0
  /**
   * Cancel that calls superUserCancel if the document is in route and the current user is the
   * routed by user of the document.
   *
   * @see
   *     org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#cancel(org.apache.struts.action.ActionMapping,
   *     org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest,
   *     javax.servlet.http.HttpServletResponse)
   */
  @Override
  public ActionForward cancel(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {

    AwardBudgetDocument awardBudgetDocument = ((AwardBudgetForm) form).getAwardBudgetDocument();
    WorkflowDocument workflowDoc = awardBudgetDocument.getDocumentHeader().getWorkflowDocument();
    if (workflowDoc.isEnroute()
        && StringUtils.equals(
            GlobalVariables.getUserSession().getPrincipalId(),
            workflowDoc.getRoutedByPrincipalId())) {
      workflowDoc.superUserCancel("Cancelled by Routed By User");
      return mapping.findForward(Constants.MAPPING_BASIC);
    } else {
      return super.cancel(mapping, form, request, response);
    }
  }
  public boolean isValidRemovalRequest(
      ProtocolOnlineReviewDocument document, ProtocolReviewerBean reviewer, int reviewerIndex) {
    boolean isValid = true;
    WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
    String propertyName =
        Constants.PROTOCOL_ASSIGN_REVIEWERS_PROPERTY_KEY
            + ".reviewer["
            + reviewerIndex
            + "].reviewerTypeCode";
    String documentRouteStatus = workflowDocument.getStatus().getCode();
    // 1. check to see the workflow status
    if (StringUtils.equals(KewApiConstants.ROUTE_HEADER_FINAL_CD, documentRouteStatus)) {
      // we just report the warning, the request is still valid - the action should prompt for
      // confirmation.
      reportWarning(
          propertyName,
          KeyConstants.ERROR_PROTOCOL_REVIEWER_CANNOT_REMOVE_REVIEW_FINAL,
          reviewer.getFullName());
    }

    if (document.getProtocolOnlineReview().getCommitteeScheduleMinutes().size() > 0) {
      // there are review comments that will be deleted by this operation
      // just report the warning.
      reportWarning(
          propertyName,
          KeyConstants.ERROR_PROTOCOL_REVIEWER_CANNOT_REMOVE_REVIEW_EXISTING_COMMENTS,
          reviewer.getFullName(),
          "" + document.getProtocolOnlineReview().getCommitteeScheduleMinutes().size());
    }

    if (StringUtils.equals(
        document.getProtocolOnlineReview().getProtocolOnlineReviewStatusCode(),
        ProtocolOnlineReviewStatus.FINAL_STATUS_CD)) {
      reportWarning(
          propertyName,
          KeyConstants.ERROR_PROTOCOL_REVIEWER_CANNOT_REMOVE_FINAL_REVIEW,
          reviewer.getFullName());
    }

    return isValid;
  }
  protected void finalizeOnlineReviewDocument(
      ProtocolOnlineReviewDocumentBase protocolOnlineReviewDocument,
      ProtocolSubmissionBase submission,
      String annotation) {

    try {

      final String principalId =
          identityManagementService
              .getPrincipalByPrincipalName(KRADConstants.SYSTEM_USER)
              .getPrincipalId();
      WorkflowDocument workflowDocument =
          WorkflowDocumentFactory.loadDocument(
              principalId, protocolOnlineReviewDocument.getDocumentNumber());
      ProtocolOnlineReviewBase review = protocolOnlineReviewDocument.getProtocolOnlineReview();
      review.addActionPerformed(
          "Finalize:"
              + workflowDocument.getStatus().getCode()
              + ":"
              + review.getProtocolOnlineReviewStatusCode());

      if (workflowDocument.isEnroute()
          || workflowDocument.isInitiated()
          || workflowDocument.isSaved()) {
        workflowDocument.superUserBlanketApprove(annotation);
      }
    } catch (Exception e) {
      String errorMessage =
          String.format(
              "Workflow exception generated while executing superUserApprove on document %s in finalizeOnlineReviewDocument. Message:%s",
              protocolOnlineReviewDocument.getDocumentNumber(), e.getMessage());
      LOG.error(errorMessage);
      throw new RuntimeException(errorMessage, e);
    }
  }
  /**
   * This is temporary until workflow 2.0 and reads from a table to get documents whose status has
   * changed to A (approved - no outstanding approval actions requested)
   *
   * @param documentHeaderId
   * @return Document
   * @throws WorkflowException
   */
  @Override
  public Document getByDocumentHeaderId(String documentHeaderId) throws WorkflowException {
    if (documentHeaderId == null) {
      throw new IllegalArgumentException("invalid (null) documentHeaderId");
    }
    boolean internalUserSession = false;
    try {
      // KFSMI-2543 - allowed method to run without a user session so it can be used
      // by workflow processes
      if (GlobalVariables.getUserSession() == null) {
        internalUserSession = true;
        GlobalVariables.setUserSession(new UserSession(KRADConstants.SYSTEM_USER));
        GlobalVariables.clear();
      }

      WorkflowDocument workflowDocument = null;

      if (LOG.isDebugEnabled()) {
        LOG.debug("Retrieving doc id: " + documentHeaderId + " from workflow service.");
      }
      workflowDocument =
          getWorkflowDocumentService()
              .loadWorkflowDocument(documentHeaderId, GlobalVariables.getUserSession().getPerson());
      UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument);

      Class<? extends Document> documentClass =
          getDocumentClassByTypeName(workflowDocument.getDocumentTypeName());

      // retrieve the Document
      Document document =
          getLegacyDataAdapter().findByDocumentHeaderId(documentClass, documentHeaderId);
      return postProcessDocument(documentHeaderId, workflowDocument, document);
    } finally {
      // if a user session was established for this call, clear it out
      if (internalUserSession) {
        GlobalVariables.clear();
        GlobalVariables.setUserSession(null);
      }
    }
  }
 /**
  * Tests that an exception is not thrown if you try to execute a "route" command on a document you
  * did not initiate.
  */
 @Test
 public void testRouteDefaultDocumentAsNonInitiatorUser() throws Exception {
   WorkflowDocument firstDocument =
       WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), DOCUMENT_TYPE_NAME);
   WorkflowDocument document =
       WorkflowDocumentFactory.loadDocument(
           getPrincipalIdForName("user2"), firstDocument.getDocumentId());
   try {
     document.route("");
     fail("Exception should have been thrown.");
   } catch (Exception e) {
     e.printStackTrace();
   }
   assertFalse("Document should not be ENROUTE.", document.isEnroute());
   //        assertFalse("There should not be a request to user2.",
   // document.isApprovalRequested());
   //
   //        // verify that there are no actions taken
   //        Collection actionTakens =
   // KEWServiceLocator.getActionTakenService().findByDocumentId(document.getDocumentId());
   //        assertEquals("There should be 0 actions taken.", 0, actionTakens.size());
 }
  protected boolean isAuthorizedToHierarchyChildAckWorkflowAction(Document document, Person user) {
    boolean authorized = true;
    final ProposalDevelopmentDocument pdDocument = ((ProposalDevelopmentDocument) document);

    if (pdDocument.getDevelopmentProposal().isChild()) {
      try {
        WorkflowDocument parentWDoc =
            getProposalHierarchyService().getParentWorkflowDocument(pdDocument);
        if ((!parentWDoc.isAcknowledgeRequested()) || parentWDoc.isInitiated()) {
          authorized = false;
        }
      } catch (ProposalHierarchyException e) {
        LOG.error(
            String.format(
                "Could not find parent workflow document for proposal document number:%s, which claims to be a child. Returning false.",
                pdDocument.getDocumentHeader().getDocumentNumber()),
            e);
        authorized = false;
      }
    }

    return authorized;
  }
  @Override
  public Document recallDocument(Document document, String annotation, boolean cancel)
      throws WorkflowException {
    checkForNulls(document);
    WorkflowDocument workflowDocument =
        KRADServiceLocatorWeb.getDocumentService()
            .getByDocumentHeaderId(document.getDocumentNumber())
            .getDocumentHeader()
            .getWorkflowDocument();

    if (!workflowDocument.isFinal() && !workflowDocument.isProcessed()) {
      Note note = createNoteFromDocument(document, annotation);
      document.addNote(note);
      getNoteService().save(note);
    }

    prepareWorkflowDocument(document);
    getWorkflowDocumentService()
        .recall(document.getDocumentHeader().getWorkflowDocument(), annotation, cancel);
    UserSessionUtils.addWorkflowDocument(
        GlobalVariables.getUserSession(), document.getDocumentHeader().getWorkflowDocument());
    removeAdHocPersonsAndWorkgroups(document);
    return document;
  }
 protected boolean hasBeenRoutedOrCanceled(ProposalDevelopmentDocument document) {
   WorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
   return !workflowDoc.isInitiated() && !workflowDoc.isSaved();
 }
Example #26
0
 /**
  * This method specifies if this document may be edited; i.e. it's only initiated or saved
  *
  * @return boolean
  */
 public boolean isEditable() {
   WorkflowDocument workflowDoc = getDocumentHeader().getWorkflowDocument();
   return workflowDoc.isInitiated() || workflowDoc.isSaved();
 }
  public void updateDOM(Document dom, Element configElement, EDLContext edlContext) {
    // String action =
    // edlContext.getRequestParser().getPropertyValueAsString(WorkflowDocumentActions.USER_ACTION_REQUEST_KEY);
    // we don't want to clear the attribute content if they are just opening up the document to view
    // it!
    if (!edlContext.getUserAction().isLoadAction()) {
      RequestParser requestParser = edlContext.getRequestParser();
      try {
        WorkflowDocument document =
            (WorkflowDocument)
                requestParser.getAttribute(RequestParser.WORKFLOW_DOCUMENT_SESSION_KEY);
        //			 clear attribute content so that duplicate attribute values are not added during
        // submission of a new EDL form values version
        document.clearAttributeContent();
        Document edlDef =
            EdlServiceLocator.getEDocLiteService()
                .getDefinitionXml(edlContext.getEdocLiteAssociation());
        XPath xpath = XPathHelper.newXPath(edlDef);
        NodeList attributeNodes =
            (NodeList) xpath.evaluate("/edl/attributes/attribute", edlDef, XPathConstants.NODESET);
        for (int index = 0; index < attributeNodes.getLength(); index++) {
          Element attributeElem = (Element) attributeNodes.item(index);
          String attributeName = attributeElem.getAttribute("name");

          WorkflowAttributeDefinition.Builder attributeDefBuilder =
              getWorkflowAttributeDefinitionVO(attributeName, document);

          NodeList fieldNodes =
              (NodeList) xpath.evaluate("./field", attributeElem, XPathConstants.NODESET);
          for (int fIndex = 0; fIndex < fieldNodes.getLength(); fIndex++) {
            Element fieldElem = (Element) fieldNodes.item(fIndex);
            String edlField = fieldElem.getAttribute("edlField");
            String attributeField = fieldElem.getAttribute("attributeField");
            PropertyDefinition property = attributeDefBuilder.getPropertyDefinition(attributeField);
            String value = requestParser.getParameterValue(edlField);
            if (property == null) {
              property = PropertyDefinition.create(attributeField, value);
            } else {
              // modify the current property
              attributeDefBuilder.getPropertyDefinitions().remove(property);
              property = PropertyDefinition.create(property.getName(), value);
            }
            attributeDefBuilder.addPropertyDefinition(property);
          }

          // validate if they are taking an action on the document (i.e. it's annotatable)
          boolean curAttrValid = true;
          if (edlContext.getUserAction().isValidatableAction()) {
            List<? extends RemotableAttributeErrorContract> errors =
                document.validateAttributeDefinition(attributeDefBuilder.build());
            if (!errors.isEmpty()) {
              edlContext.setInError(true);
              curAttrValid = false;
            }
            Map<String, String> fieldErrors =
                (Map<String, String>)
                    edlContext
                        .getRequestParser()
                        .getAttribute(RequestParser.GLOBAL_FIELD_ERRORS_KEY);
            for (RemotableAttributeErrorContract error : errors) {
              fieldErrors.put(error.getAttributeName(), error.getMessage());
            }
          }

          if (curAttrValid) {
            if (edlContext.getUserAction().isValidatableAction()) {
              for (int fIndex = 0; fIndex < fieldNodes.getLength(); fIndex++) {
                Element fieldElem = (Element) fieldNodes.item(fIndex);
                String edlField = fieldElem.getAttribute("edlField");
                String attributeField = fieldElem.getAttribute("attributeField");
                PropertyDefinition property =
                    attributeDefBuilder.getPropertyDefinition(attributeField);
                String value = requestParser.getParameterValue(edlField);
                if (property == null) {
                  property = PropertyDefinition.create(attributeField, value);
                } else {
                  // modify the current property
                  attributeDefBuilder.getPropertyDefinitions().remove(property);
                  property = PropertyDefinition.create(property.getName(), value);
                }
                attributeDefBuilder.addPropertyDefinition(property);
              }
              WorkflowAttributeDefinition attributeDef = attributeDefBuilder.build();
              document.addAttributeDefinition(attributeDef);
            }
          }
        }
      } catch (Exception e) {
        if (e instanceof RuntimeException) {
          throw (RuntimeException) e;
        }
        throw new WorkflowRuntimeException("Failed to process attribute.", e);
      }
    }
  }
  /**
   * Creates a new document by document type name. The principal name passed in will be used as the
   * document initiator. If the initiatorPrincipalNm is null or blank, the current user will be
   * used.
   *
   * @see org.kuali.rice.krad.service.DocumentService#getNewDocument(String, String)
   */
  @Override
  public Document getNewDocument(String documentTypeName, String initiatorPrincipalNm)
      throws WorkflowException {

    // argument validation
    String watchName = "DocumentServiceImpl.getNewDocument";
    StopWatch watch = new StopWatch();
    watch.start();
    if (LOG.isDebugEnabled()) {
      LOG.debug(watchName + ": started");
    }
    if (StringUtils.isBlank(documentTypeName)) {
      throw new IllegalArgumentException("invalid (blank) documentTypeName");
    }
    if (GlobalVariables.getUserSession() == null) {
      throw new IllegalStateException(
          "GlobalVariables must be populated with a valid UserSession before a new document can be created");
    }

    // get the class for this docTypeName
    Class<? extends Document> documentClass = getDocumentClassByTypeName(documentTypeName);

    // get the initiator
    Person initiator = null;
    if (StringUtils.isBlank(initiatorPrincipalNm)) {
      initiator = GlobalVariables.getUserSession().getPerson();
    } else {
      initiator =
          KimApiServiceLocator.getPersonService().getPersonByPrincipalName(initiatorPrincipalNm);
      if (initiator == null) {
        initiator = GlobalVariables.getUserSession().getPerson();
      }
    }

    // get the authorization
    DocumentAuthorizer documentAuthorizer =
        getDocumentDictionaryService().getDocumentAuthorizer(documentTypeName);
    DocumentPresentationController documentPresentationController =
        getDocumentDictionaryService().getDocumentPresentationController(documentTypeName);
    // make sure this person is authorized to initiate
    if (LOG.isDebugEnabled()) {
      LOG.debug(
          "calling canInitiate from getNewDocument("
              + documentTypeName
              + ","
              + initiatorPrincipalNm
              + ")");
    }
    if (!documentPresentationController.canInitiate(documentTypeName)
        || !documentAuthorizer.canInitiate(documentTypeName, initiator)) {
      throw new DocumentAuthorizationException(
          initiator.getPrincipalName(), "initiate", documentTypeName);
    }

    // initiate new workflow entry, get the workflow doc
    WorkflowDocument workflowDocument =
        getWorkflowDocumentService().createWorkflowDocument(documentTypeName, initiator);
    UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument);

    // create a new document header object
    DocumentHeader documentHeader = new DocumentHeader();
    documentHeader.setWorkflowDocument(workflowDocument);
    documentHeader.setDocumentNumber(workflowDocument.getDocumentId());

    // build Document of specified type
    Document document = null;
    try {
      // all maintenance documents have same class
      if (MaintenanceDocumentBase.class.isAssignableFrom(documentClass)) {
        Class<?>[] defaultConstructor = new Class[] {String.class};
        Constructor<? extends Document> cons = documentClass.getConstructor(defaultConstructor);
        if (cons == null) {
          throw new ConfigurationException(
              "Could not find constructor with document type name parameter needed for Maintenance Document Base class");
        }
        document = cons.newInstance(documentTypeName);
      } else {
        // non-maintenance document
        document = documentClass.newInstance();
      }
    } catch (IllegalAccessException e) {
      throw new RuntimeException("Error instantiating Document", e);
    } catch (InstantiationException e) {
      throw new RuntimeException("Error instantiating Document", e);
    } catch (SecurityException e) {
      throw new RuntimeException("Error instantiating Maintenance Document", e);
    } catch (NoSuchMethodException e) {
      throw new RuntimeException(
          "Error instantiating Maintenance Document: No constructor with String parameter found",
          e);
    } catch (IllegalArgumentException e) {
      throw new RuntimeException("Error instantiating Maintenance Document", e);
    } catch (InvocationTargetException e) {
      throw new RuntimeException("Error instantiating Maintenance Document", e);
    }

    document.setDocumentHeader(documentHeader);
    document.setDocumentNumber(documentHeader.getDocumentNumber());

    watch.stop();
    if (LOG.isDebugEnabled()) {
      LOG.debug(watchName + ": " + watch.toString());
    }

    return document;
  }
  @Test
  public void testParallelRoute() throws Exception {
    WorkflowDocument document =
        WorkflowDocumentFactory.createDocument(
            getPrincipalIdForName("ewestfal"), DOCUMENT_TYPE_NAME);
    document.saveDocumentData();
    assertTrue("Document should be initiated", document.isInitiated());
    assertEquals("Should be no action requests.", 0, document.getRootActionRequests().size());
    Collection<RouteNodeInstance> nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
    document.route("Routing for parallel");

    // should have generated a request to "bmcgough"
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("bmcgough"), document.getDocumentId());
    assertTrue("Document should be enroute", document.isEnroute());
    List<ActionRequestValue> actionRequests =
        KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
    assertEquals("Incorrect pending action requests.", 1, actionRequests.size());
    ActionRequestValue bRequest = actionRequests.get(0);
    assertNotNull("Should have been routed through node instance.", bRequest.getNodeInstance());
    assertTrue(document.isApprovalRequested());

    document.approve("Approving test");

    // document should split at this point and generate an ack to temay and approves to rkirkend and
    // pmckown
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("rkirkend"), document.getDocumentId());
    assertTrue("Document should be enroute", document.isEnroute());
    actionRequests =
        KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
    assertEquals("Incorrect pending action requests.", 3, actionRequests.size());
    boolean isToTemay = false;
    boolean isToPmckown = false;
    boolean isToRkirkend = false;
    for (Iterator iterator = actionRequests.iterator(); iterator.hasNext(); ) {
      ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
      if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("temay"))) {
        isToTemay = true;
        assertEquals(
            "Request should be activated.",
            ActionRequestStatus.ACTIVATED.getCode(),
            actionRequest.getStatus());
        assertEquals(
            "Wrong action requested.",
            KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ,
            actionRequest.getActionRequested());
        assertNotNull(
            "Should have been routed through node instance.", actionRequest.getNodeInstance());
        assertEquals(
            "Invalid node.",
            ACKNOWLEDGE_1_NODE,
            actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
      }
      if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("rkirkend"))) {
        isToRkirkend = true;
        assertEquals(
            "Request should be activated.",
            ActionRequestStatus.ACTIVATED.getCode(),
            actionRequest.getStatus());
        assertEquals(
            "Wrong action requested.",
            KewApiConstants.ACTION_REQUEST_APPROVE_REQ,
            actionRequest.getActionRequested());
        assertNotNull(
            "Should have been routed through node instance.", actionRequest.getNodeInstance());
        assertEquals(
            "Invalid node.",
            WORKFLOW_DOCUMENT_2_NODE,
            actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
      }
      if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("pmckown"))) {
        isToPmckown = true;
        assertEquals(
            "Request should be activated.",
            ActionRequestStatus.ACTIVATED.getCode(),
            actionRequest.getStatus());
        assertEquals(
            "Wrong action requested.",
            KewApiConstants.ACTION_REQUEST_APPROVE_REQ,
            actionRequest.getActionRequested());
        assertNotNull(
            "Should have been routed through node instance.", actionRequest.getNodeInstance());
        assertEquals(
            "Invalid node.",
            WORKFLOW_DOCUMENT_3_NODE,
            actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
      }
    }
    assertTrue("No request to temay.", isToTemay);
    assertTrue("No request to pmckown.", isToPmckown);
    assertTrue("No request to rkirkend.", isToRkirkend);

    // check that we are at both nodes, one in each branch
    Set<String> nodeNames = document.getNodeNames();
    assertEquals("Wrong number of node names.", 2, nodeNames.size());
    boolean isNode2 = false;
    boolean isNode3 = false;
    for (String name : nodeNames) {
      if (name.equals(WORKFLOW_DOCUMENT_2_NODE)) {
        isNode2 = true;
      }
      if (name.equals(WORKFLOW_DOCUMENT_3_NODE)) {
        isNode3 = true;
      }
    }
    assertTrue("Not at node2.", isNode2);
    assertTrue("Not at node3.", isNode3);
    nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 2, nodeInstances.size());
    Iterator<RouteNodeInstance> iterator = nodeInstances.iterator();
    RouteNodeInstance instance1 = (RouteNodeInstance) iterator.next();
    RouteNodeInstance instance2 = (RouteNodeInstance) iterator.next();
    assertNotNull("Node should be in branch.", instance1.getBranch());
    assertNotNull("Node should be in branch.", instance2.getBranch());
    assertTrue(
        "Branches should be different.",
        !instance1.getBranch().getBranchId().equals(instance2.getBranch().getBranchId()));

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("rkirkend"), document.getDocumentId());
    assertTrue("Should have request.", document.isApprovalRequested());
    document.approve("Git-r-dun");

    nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 2, nodeInstances.size());
    boolean isAtJoin = false;
    boolean isAtWD3 = false;
    for (RouteNodeInstance nodeInstance : nodeInstances) {
      if (nodeInstance.getRouteNode().getRouteNodeName().equals(JOIN_NODE)) {
        assertEquals(
            "Join branch should be split branch.",
            instance1.getBranch().getParentBranch().getBranchId(),
            nodeInstance.getBranch().getBranchId());
        isAtJoin = true;
      }
      if (nodeInstance.getRouteNode().getRouteNodeName().equals(WORKFLOW_DOCUMENT_3_NODE)) {
        isAtWD3 = true;
      }
    }
    assertTrue("Not at join", isAtJoin);
    assertTrue("Not at WD3", isAtWD3);

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("pmckown"), document.getDocumentId());
    assertTrue("Should have request.", document.isApprovalRequested());
    document.approve("Do it.");

    nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
    boolean isAtWDF = false;
    for (RouteNodeInstance nodeInstance : nodeInstances) {
      if (nodeInstance.getRouteNode().getRouteNodeName().equals(WORKFLOW_DOCUMENT_FINAL_NODE)) {
        isAtWDF = true;
      }
    }
    assertTrue("Not at WDF", isAtWDF);

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("xqi"), document.getDocumentId());
    assertTrue("Should still be enroute.", document.isEnroute());
    assertTrue("Should have request.", document.isApprovalRequested());
    document.approve("I'm the last approver");

    assertTrue("Document should be processed.", document.isProcessed());
    nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals(
        "The doc is processed so no node instances should be active", 0, nodeInstances.size());

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("temay"), document.getDocumentId());
    assertTrue("Should have request.", document.isAcknowledgeRequested());
    document.acknowledge("");
    assertTrue(document.isFinal());
  }
  @Test
  public void testAdhocApproversJoinScenario() throws Exception {
    WorkflowDocument document =
        WorkflowDocumentFactory.createDocument(
            getPrincipalIdForName("ewestfal"), "AdHocApproversDocType");
    document.route("");

    // should send an approve to bmcgough
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("bmcgough"), document.getDocumentId());
    assertTrue("Bmcgough should have approve request.", document.isApprovalRequested());
    document.approve("");

    // at this point the document should pass the split, and end up at the WorkflowDocument2 node
    // and the AdHocApproversJoin node
    // after bypassing the AdHocJoinPoint
    Set<String> nodeNames = document.getNodeNames();
    assertEquals("There should be two node names.", 2, nodeNames.size());
    assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("WorkflowDocument2"));
    assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("AdHocApproversJoin"));

    // pmckown has the request at the adhoc approvers node, if we approve as him then the document
    // should _not_ transition out
    // of it's current nodes
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("pmckown"), document.getDocumentId());
    assertTrue("Pmckown should have approve request.", document.isApprovalRequested());
    document.approve("");

    // the document should still be at the same nodes
    nodeNames = document.getNodeNames();
    assertEquals("There should be two node names.", 2, nodeNames.size());
    assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("WorkflowDocument2"));
    assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("AdHocApproversJoin"));

    // at WorkflowDocument2, rkirkend is the approver, if we approve as him we should end up at the
    // WorkflowDocumentFinal node
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("rkirkend"), document.getDocumentId());
    assertTrue("Rkirkend should have approve request.", document.isApprovalRequested());
    document.approve("");

    // the document should now be at WorkflowDocumentFinal with a request to xqi
    nodeNames = document.getNodeNames();
    assertEquals("There should be one node name.", 1, nodeNames.size());
    assertTrue(
        "Should be at WorkflowDocumentFinal node.", nodeNames.contains("WorkflowDocumentFinal"));

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("xqi"), document.getDocumentId());
    assertTrue("Document should still be enroute.", document.isEnroute());
    document.approve("");
    assertTrue("Document should now be final.", document.isFinal());
  }