Here’s a plugin code skeleton you can adapt for enforcing conditional approval on Quote creation in Dynamics 365:
Plugin Skeleton
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
namespace OpportunityApprovalPlugin
{
public class QuoteCreateValidation : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Obtain execution context
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// Ensure target is Quote entity
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity quote = (Entity)context.InputParameters["Target"];
// Get related Opportunity
if (quote.Contains("opportunityid"))
{
EntityReference oppRef = (EntityReference)quote["opportunityid"];
Guid oppId = oppRef.Id;
// Retrieve Opportunity Product Lines
QueryExpression query = new QueryExpression("opportunityproduct");
query.ColumnSet = new ColumnSet("extendedamount");
query.Criteria.AddCondition("opportunityid", ConditionOperator.Equal, oppId);
EntityCollection oppProducts = service.RetrieveMultiple(query);
// Calculate total
decimal totalAmount = 0;
foreach (Entity product in oppProducts.Entities)
{
if (product.Contains("extendedamount"))
{
Money amount = (Money)product["extendedamount"];
totalAmount += amount.Value;
}
}
// Retrieve approval status from Opportunity
Entity opportunity = service.Retrieve("opportunity", oppId, new ColumnSet("new_approvalstatus"));
string approvalStatus = opportunity.Contains("new_approvalstatus") ? opportunity["new_approvalstatus"].ToString() : "Pending";
// Check condition
decimal threshold = 50000; // Example threshold
if (totalAmount >= threshold && approvalStatus != "Approved")
{
throw new InvalidPluginExecutionException("Quote creation blocked. Approval required for Opportunity total exceeding threshold.");
}
}
}
}
}
}
Key Points
- Trigger: Register this plugin on Pre-Create of Quote.
- Logic:
- Retrieve Opportunity Product Lines.
- Sum the
extendedamount.
- Compare against threshold.
- Check custom field
new_approvalstatus on Opportunity.
- Block: If threshold exceeded and not approved → throw exception.
- Approval Integration:
- Approval status can be updated via Power Automate flow or another plugin when approver responds.
- Store approver details in custom fields (
ApprovedBy, ApprovalDate).
This skeleton enforces server-side validation, ensuring no Quote can be created until approval is granted. Combine it with the Power Automate flow for email-based approvals to complete the solution.