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;
  }
  /**
   * @see
   *     org.kuali.rice.kns.maintenance.KualiMaintainableImpl#doRouteStatusChange(org.kuali.rice.kns.bo.DocumentHeader)
   */
  @Override
  public void doRouteStatusChange(DocumentHeader documentHeader) {
    if (documentHeader.getWorkflowDocument().isProcessed()) {
      AgencyStagingData agencyStaging = (AgencyStagingData) getBusinessObject();

      updateCreditCardAgency(agencyStaging);

      // All validations have passed at this point. Set error code to 'OK'.
      agencyStaging.setErrorCode(AgencyStagingDataErrorCodes.AGENCY_NO_ERROR);

      // after fixing the agency audit record, attempt to move agency data to historical table
      List<ErrorMessage> errors =
          getAgencyDataImportService()
              .processAgencyStagingExpense(
                  agencyStaging, getGeneralLedgerPendingEntrySequenceHelper());
      LOG.info(
          "Agency Data Id: "
              + agencyStaging.getId()
              + (errors.isEmpty() ? " was" : " was not")
              + " processed.");

      // add a Note if there were errors reconciling or distributing the record
      if (!errors.isEmpty()) {
        try {
          MaintenanceDocument document =
              (MaintenanceDocument)
                  getDocumentService().getByDocumentHeaderId(documentHeader.getDocumentNumber());
          addNoteAfterProcessingAgencyStagingExpense(document, errors);
        } catch (WorkflowException exception) {
          LOG.error(
              "Unable to add Note to Document Id: " + documentHeader.getDocumentNumber(),
              exception);
          LOG.error(getMessageAsString(errors));
        }
      }

      // nota bene: agency staging data object does NOT need to be saved here as the maint doc will
      // save it itself once processing completes

    }
    super.doRouteStatusChange(documentHeader);
  }
  /**
   * 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;
  }