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?
| Property | Value |
|---|---|
| Entity | Document Approval (tt_documentapproval) |
| Message | Create |
| Stage | Post-Operation (runs after the record is created) |
| Execution Mode | Synchronous |
| Conditions | Runs 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_documentsignerrecord 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:
- Verify the Service Line field has a value when the record is created
- Check that contacts exist with the correct Data Approver Connection Role for that Service Line
- 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:
- Verify the approver contacts have the appropriate "Data Approver" Connection Roles
- Check the Plugin Trace Log to see which Service Line label was used
- 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:
- Review which contacts have the Data Approver Connection Role for this Service Line
- Check the Plugin Trace Log to see how many signers were created
- Verify the logic in
Utils.UpdateSignersForDocumentApproval()is filtering correctly
Related Documentation
- DocumentApprovalDocumentSignersPostOperationUpdate - Companion plugin that updates signers when Service Line is changed
- Utils.UpdateSignersForDocumentApproval() [To Be Completed] - Utility method that contains the core logic for managing Document Signers
- Service Line Configuration Guide [To Be Completed] - How to configure Service Line to Approver mappings
- Connection Roles Overview [To Be Completed] - Understanding Data Approver roles and permissions
Configuration Requirements
This plugin depends on the following configuration:
- Service Line Option Set - The
tt_servicelinefield must have valid option set values - Data Approver Connection Roles - Contacts must be assigned to appropriate Data Approver Connection Roles
- Plugin Registration - Registered on Create of
tt_documentapprovalin 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