November 9, 2017

Catch the Revise Quote message inside a Plugin

A user in Dynamics CRM/365 can revise a Quote, it's a process where the old quote is closed and a new quote is created in draft state and ready to be updated.
Dynamics doesn't support a specific message that we can intercept (in order to register a plugin step) when a quote is revised, however one of the possible ways is to deal with the Create message.

When quote are revised the integer (Whole Number) field revisionnumber is increased, this field is managed by the platform as it is not valid for Create or for Update according to its Metadata.
So when a new quote is created the revision number is 0, and the revised quotes will have 1,2,3...
Fetching the quote with the previous revision number is not a clever method to retrieve the revised quote. For example if we have an original quote (0) in Closed state and a revised quote (1) in Closed state too (because we cancelled), we are able to revise the original quote (0) and the new quote will have 2 as revision number.

My friend Daryl LaBar (@ddlabar) suggested to check the ParentContext property inside the plugin in order to access to the ReviseQuote message that initialized the create message.
In the end I wrote a plugin (registered on the Create message, Pre-Operation, Synchronous) to check the Parent Context and get the reference of the revised quote. Here the code:
public void Execute(IServiceProvider serviceProvider)
    IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

    if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
      Entity currentQuote = (Entity)context.InputParameters["Target"];
      if (currentQuote.LogicalName != "quote") { return; }
      // check the revision number first
      int revisionNumber = currentQuote.GetAttributeValue<int>("revisionnumber");
      if (revisionNumber > 0)
        IPluginExecutionContext parentContext = context.ParentContext;
        // check if the Parent Context contains the QuoteId parameter of the ReviseQuote message
        if (parentContext.InputParameters.Contains("QuoteId") && parentContext.InputParameters["QuoteId"] is Guid)
          Guid revisedQuoteId = (Guid)parentContext.InputParameters["QuoteId"];
          IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
          IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

          Entity revisedQuote = service.Retrieve("quote", revisedQuoteId, new ColumnSet(true));
          // rest of the code

  catch (Exception ex)
    throw new InvalidPluginExecutionException(ex.Message);