Skip to main content

Document Approval Document Signers - Post Operation Create

This plugin automatically creates Document Signer records when a new Document Approval is created.


What Does This Do?

When someone creates a new Document Approval, this plugin automatically generates the list of people who need to sign off on it based on the selected Service Line (department).

For example, if a document is created with the Service Line set to "UK Tax", this plugin will:

  • Find all contacts with the "Data Approver" role for UK Tax
  • Create a Document Signer record for each approver
  • Link them to the new Document Approval

This ensures that the right people are immediately notified and assigned to review the document.


When Does This Run?

PropertyValue
EntityDocument Approval (tt_documentapproval)
MessageCreate
StagePost-Operation (runs after the record is created)
Execution ModeSynchronous
ConditionsRuns every time a new Document Approval is created

How It Works

Step 1: Validate the Document Approval was created

The plugin retrieves the newly created Document Approval record from the execution context and validates that it's the correct entity type and message.

What happens: Confirms this is a Create operation on a Document Approval entity

Step 2: Retrieve the full Document Approval record

Gets the complete Document Approval record from the database to access all its field values, including the Service Line and Contact information.

What happens: Fetches the full entity record with all attributes

Step 3: Validate Service Line exists

Ensures that the Document Approval has a valid Service Line value set. This is critical because we need the Service Line to determine which approvers should be assigned.

Exit condition: Throws InvalidPluginExecutionException if Service Line is missing or invalid

Step 4: Get Contact ID

Retrieves the Contact ID from the Document Approval record. This identifies the person who submitted the document for approval and is needed to determine the appropriate signers.

What happens: Extracts the Contact lookup field from the Document Approval

Step 5: Get Service Line label

Fetches the display name (label) of the Service Line option set value (e.g., "Audit", "Business Advisory", "UK Tax"). This label is used to match approvers with the correct department.

What happens: Converts the numeric Service Line value to its readable text equivalent

Step 6: Create Document Signers

Creates Document Signer records based on the selected Service Line. The plugin queries for contacts who have the appropriate "Data Approver" Connection Role for the selected Service Line and generates a Document Signer record for each one.

What happens:

  • Finds contacts with matching Data Approver roles
  • Creates a tt_documentsigner record for each approver
  • Links each signer to the new Document Approval
Step 7: Log completion

Records the number of signers that were successfully created in the Plugin Trace Log. This helps with debugging and verifying the plugin executed correctly.

What happens: Writes a trace message showing how many signer records were created


Why This Matters

When a Document Approval is created, the appropriate approvers need to be immediately assigned based on the department (Service Line) that will handle the review. This plugin automates that process, ensuring:

  • No manual assignment of approvers is needed
  • The correct people are always assigned based on their Connection Roles
  • The approval workflow can start immediately after creation
  • Human error in assigning approvers is eliminated

Code

Dependencies

using System;
using Microsoft.Xrm.Sdk;

Full Plugin Code

namespace PracticeGateway.Plugin
{
public class DocumentApprovalDocumentSignersPostOperationCreate : PluginBase
{
// Entity and message names
private const string ENTITY_DOCUMENT_APPROVAL = "tt_documentapproval";
private const string MESSAGE_CREATE = "Create";
private const int MAX_PLUGIN_DEPTH = 10;

public DocumentApprovalDocumentSignersPostOperationCreate(string unsecure, string secure)
: base(typeof(DocumentApprovalDocumentSignersPostOperationCreate))
{
}

protected override void ExecuteCdsPlugin(ILocalPluginContext localContext)
{
var tracing = localContext.TracingService;
var context = localContext.PluginExecutionContext;
var service = localContext.CurrentUserService;

tracing.Trace($"[Plugin Start] {context.MessageName}, Stage: {context.Stage}, Depth: {context.Depth}");

try
{
// Helper class for common operations
Utils.Utils utils = new Utils.Utils(service, tracing);

// Get the Document Approval record that was just created
Entity target = utils.ValidateAndGetTarget(context, ENTITY_DOCUMENT_APPROVAL, MESSAGE_CREATE, MAX_PLUGIN_DEPTH);
Guid documentApprovalId = target.Id;

tracing.Trace($"[Processing] Document Approval ID: {documentApprovalId}");

// Retrieve the full Document Approval record
Entity documentApproval = utils.RetrieveDocumentApproval(documentApprovalId);

// Make sure a Service Line is set (required to find the right approvers)
if (!utils.ValidateServiceLine(documentApproval))
{
throw new InvalidPluginExecutionException(
$"Document Approval {documentApprovalId} does not have a valid service line value.");
}

// Get the Contact who needs approval
Guid contactId = utils.GetContactIdFromDocumentApproval(documentApproval);
tracing.Trace($"[Processing] Contact ID: {contactId}");

// Get the Service Line name (e.g., "Audit", "UK Tax")
string serviceLineLabel = utils.GetServiceLineLabel(documentApproval);
tracing.Trace($"[Processing] Service Line: {serviceLineLabel}");

// Create Document Signer records for all appropriate approvers
int signersCreated = utils.UpdateSignersForDocumentApproval(
documentApprovalId,
contactId,
serviceLineLabel,
deleteExisting: false); // Don't delete anything - this is a new record

tracing.Trace($"[Plugin Complete] Successfully created {signersCreated} signer record(s)");
}
catch (InvalidPluginExecutionException)
{
// Let plugin exceptions pass through without modification
throw;
}
catch (Exception ex)
{
// Log unexpected errors and wrap them
tracing.Trace($"[Error] {ex.GetType().Name}: {ex.Message}");
if (ex.InnerException != null)
{
tracing.Trace($"[Error] Inner exception: {ex.InnerException.Message}");
}
throw new InvalidPluginExecutionException(
$"An unexpected error occurred in DocumentApprovalDocumentSignersPostOperationCreate: {ex.Message}", ex);
}
}
}
}

Common Issues & Troubleshooting

Problem: No signers are created when a Document Approval is created

Possible Causes:

  • The Service Line field is not populated on the new Document Approval
  • No contacts have the required Data Approver Connection Role for the selected Service Line
  • The plugin registration might be missing or disabled

How to Check:

  1. Verify the Service Line field has a value when the record is created
  2. Check that contacts exist with the correct Data Approver Connection Role for that Service Line
  3. Review the Plugin Trace Log for detailed execution information

Problem: Plugin throws "does not have a valid service line value"

Cause: The Service Line field is empty or null when the Document Approval is created

Solution: Ensure the Service Line is populated before creating the Document Approval record. Consider adding client-side validation to make Service Line a required field or set a default value.


Problem: Wrong approvers are being assigned

Possible Causes:

  • The approver contacts don't have the correct Connection Roles assigned
  • The Service Line mapping to Connection Roles is incorrect

How to Check:

  1. Verify the approver contacts have the appropriate "Data Approver" Connection Roles
  2. Check the Plugin Trace Log to see which Service Line label was used
  3. Confirm the Connection Role names match the Service Line labels exactly

Problem: Plugin is creating too many or too few signers

Possible Causes:

  • Multiple contacts have the same Data Approver Connection Role (creating duplicates)
  • The Contact filter in the utility method is too restrictive or too permissive

How to Check:

  1. Review which contacts have the Data Approver Connection Role for this Service Line
  2. Check the Plugin Trace Log to see how many signers were created
  3. Verify the logic in Utils.UpdateSignersForDocumentApproval() is filtering correctly


Configuration Requirements

This plugin depends on the following configuration:

  1. Service Line Option Set - The tt_serviceline field must have valid option set values
  2. Data Approver Connection Roles - Contacts must be assigned to appropriate Data Approver Connection Roles
  3. Plugin Registration - Registered on Create of tt_documentapproval in Post-Operation stage

Testing Checklist

When testing this plugin, verify:

  • Creating a Document Approval with a valid Service Line creates the correct signers
  • Creating a Document Approval without a Service Line throws an appropriate error
  • The correct number of signers are created based on available Data Approver contacts
  • Signers are linked correctly to the new Document Approval record
  • Plugin handles missing approver contacts gracefully
  • Error messages are logged clearly in Plugin Trace Log
  • Plugin doesn't create duplicate signer records