I've implemented a plugin to block creation of sales order if the same quote number exist but its not firing no trace, think there is a different message i have to use. below salesorder entity create message and preoperation
--
{
public class OrderDuplicateQuoteValidation : IPlugin
{
private const int STATE_CANCELED = 3;
public void Execute(IServiceProvider serviceProvider)
{
// Services
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.InitiatingUserId); // Not UserId unless impersonating
// Only run on Create of Sales Order
if (!"create".Equals(context.MessageName, StringComparison.OrdinalIgnoreCase))
return;
// Prevent plugin recursion
if (context.Depth > 1)
return;
// Validate target
if (!context.InputParameters.TryGetValue("Target", out object target) || !(target is Entity))
return;
Entity salesOrder = (Entity)target;
if (salesOrder.LogicalName != "salesorder" || !salesOrder.TryGetAttributeValue("quoteid", out EntityReference quoteRef) || quoteRef == null)
return;
Guid quoteId = quoteRef.Id;
tracingService.Trace($"Checking for existing sales orders for Quote ID: {quoteId}");
// Query existing orders from the same quote (excluding cancelled)
QueryExpression query = new QueryExpression("salesorder")
{
ColumnSet = new ColumnSet("name"),
Criteria = new FilterExpression
{
Conditions =
{
new ConditionExpression("quoteid", ConditionOperator.Equal, quoteId),
new ConditionExpression("statecode", ConditionOperator.NotEqual, STATE_CANCELED)
}
}
};
EntityCollection results = service.RetrieveMultiple(query);
Entity existingOrder = results.Entities.FirstOrDefault();
if (existingOrder != null)
{
string existingOrderName = existingOrder.GetAttributeValue<string>("name") ?? string.Empty;
if (!string.IsNullOrWhiteSpace(existingOrderName))
existingOrderName = $" (Order: {existingOrderName})";
throw new InvalidPluginExecutionException(
$"This quote has already been converted to an order{existingOrderName}. " +
"Please use the existing order or cancel it before creating a new one.");
}
}
}
// Extension method (optional but neat)
public static class EntityExtensions
{
public static bool TryGetAttributeValue<T>(this Entity entity, string attributeName, out T value)
{
value = default(T); // C# 7.3 requires explicit type for default
if (entity.Contains(attributeName) && entity[attributeName] is T castValue)
{
value = castValue;
return true;
}
return false;
}
}