Reopening Won Quotes in Dynamics 365 Sales Professional / Enterprise (C#)

Reopening Won Quotes in Dynamics 365 Sales Professional / Enterprise (C#)
Featured image of post Reopening Won Quotes in Dynamics 365 Sales Professional / Enterprise (C#)

After you’ve spent any length of time working with the out of the box sales process within Dynamics 365 Sales Professional / Enterprise, you get used to some of the behavioural quirks that can commonly cause you challenges during an implementation. A prime candidate for consideration here concerns the various types of tables used by the application. When we consider these in detail, such as the Opportunity, Quote and Order table, many of the assumptions that we make about how things work are instantly proven wrong, as these tables tend to operate by their own set of rules. For example, the ability to easily map across attributes between the different product line table types (Opportunity Product, Quote Product etc.) becomes a challenge; we must instead revert to using custom code instead to satisfy this requirement. Little things like this can exasperate both new and long-time users of the application and can often be quite frustrating when explaining to organisations using the software. 😅 Notwithstanding these gripes, I still do genuinely believe the Dynamics 365 Sales platform provides a solid base for organisations to leverage out of the box functionality, with the ability to customise further, as needed. And, when we start to bring into the equation more advanced capabilities, via things such as custom pricing plug-ins, you begin to move to an entirely new level when it comes to what we can do with this application.

A particularly annoying behaviour quirk I dealt with recently involved Quotes marked as Won in the system. The organisation I was working with needed to, on occasions, modify details of a Won Quote after the fact. For example, if the salesperson included the wrong item or the customer changed their order after confirming it. As we can observe in the below screenshot, we have no option on the ribbon to reactivate the Quote once Won in the application:

The only “out of the box” way of dealing with this was to create and re-input all details into a new Quote; not a viable and time-effective solution. Fortunately, there is a faster way we can achieve the objective by working through the following outline steps:

  1. First, we need to change the Status & Status Reason of the Quote back to Draft & In Progress.
  2. After we have made modifications to the Quote, it needs to be set as Active again.
  3. Once Active, the Quote then must be closed as Won. Microsoft wraps the logic for this within the WinQuote action, which we can call via the SDK or against the Microsoft Dataverse Web API.

These steps should be achievable via either a classic workflow or a Power Automate cloud flow automation, which would typically be our first preference for a requirement like this. However, in our case, we wanted to call these steps as part of a Custom API definition, which could then be called via a JavaScript action on a Ribbon button, similar to how I’ve described previously on the blog. And, most crucially, we needed all steps to be completed synchronously. So, given these requirements, we had to look at a solution leveraging C# instead.

With all of this in mind, let’s jump into the reason why you’re probably reading this post. 😉 To open a Won Quote using C#, we would need to write and execute the following code:

//TODO: Implement code to generate your IOrganizationService reference. For plug-ins, this would look something like this:
//IOrganizationServiceFactory serviceFactory = serviceProvider.GetService<IOrganizationServiceFactory>();
//IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

Guid quoteID = new Guid("9cc66ad5-2506-4394-854d-f60c35185d96");
Entity quote = new Entity("quote", quoteID);
quote["statecode"] = new OptionSetValue(0); // Draft
quote["statuscode"] = new OptionSetValue(1); // In Progress

Then, once we’re ready to return the Quote to its previous state, we’d then run the following code to re-close the Quote. Note in particular, at this stage, we need to execute two separate actions and ensure they are completed successfully:

//TODO: Implement code to generate your IOrganizationService reference. For plug-ins, this would look something like this:
//IOrganizationServiceFactory serviceFactory = serviceProvider.GetService<IOrganizationServiceFactory>();
//IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

// We execute everything in a transaction, so we can rollback cleanly on failure
ExecuteTransactionRequest transactionRequest = new ExecuteTransactionRequest()
    Requests = new OrganizationRequestCollection(),
    ReturnResponses = true,
ExecuteTransactionResponse transactionResponse;

Guid quoteID = new Guid("9cc66ad5-2506-4394-854d-f60c35185d96");

// First, we need to Activate the Quote ...
Entity quote = new Entity("quote", quoteID);
quote["statecode"] = new OptionSetValue(1); // Active
quote["statuscode"] = new OptionSetValue(2); // In Progress

UpdateRequest updateRequest = new UpdateRequest()
    Target = quote,


// ...with this done, now we can re-close the Quote as Won
Entity quoteClose = new Entity("quoteclose");
quoteClose["subject"] = "Quote Close" + DateTime.Now.ToString();
quoteClose["quoteid"] = quote.ToEntityReference();

WinQuoteRequest winQuoteRequest = new WinQuoteRequest()
    QuoteClose = quoteClose,
    Status = new OptionSetValue(-1),


transactionResponse = (ExecuteTransactionResponse)service.Execute(transactionRequest);
tracer.Trace($"Quote ID {quoteID} closed as won successfully!");

As stated earlier, if there wasn’t a need to execute these actions synchronously, then leveraging Power Automate cloud flows would be something I’d actively encourage instead, as both the ability to update and call action steps are supported via this tool. So before you act too gung-ho with the above, validate your approach against the requirements you are working against.

Regardless of the precise approach you take, it is a minor point of frustration that these types of steps are not natively supported within Dynamics 365 Sales. I understand why the system behaves like this, and there are arguable benefits to having a Quote locked after it’s been approved. However, I imagine the ability to make quick edits to a Won Quote is a common requirement across many different organisations, and expecting users to have to go through raising an entirely new Quote is both impractical and ludicrous in equal measure. It’s good to know that the underlying platform supports us in building workarounds such as this so that we are not left entirely adrift with a system that must fit around the business instead of the other way around.

Published on:

Learn more
The CRM Chap
The CRM Chap

Anything and everything to do with the #PowerPlatform, #MSDYN365, #Azure and more!

Share post:

Related posts

Interview Questions and Answers Dynamics 365 CE and Power Platform – Ultimate Guide

In today's business landscape, Dynamics 365 Customer Engagement (CE) and the Power Platform have emerged as game-changing tools that have tran...

3 days ago

Back to Basics # 72: Limit Special Characters Using a Webresource in Dynamics CRM

Recently we got a requirement to restrict user to enter special characters. Step 1 : Use the below method for restricting special characters S...

12 days ago

{How to} Get real time tips and suggested answers during Teams meetings on Dynamics 365 Sales

Hello Everyone,Today I am going to share my thoughts on the real time tips and suggested answers during Teams meetings on Dynamics 365 Sales.L...

19 days ago

Leveraging Copilot in Dynamics 365 Sales to prepare for sales meeting

In today’s rapidly evolving sales environment, staying ahead of the curve is more crucial than ever. The post Leveraging Copilot in Dynamics ...

20 days ago

{How to} Allow sellers to track performance with out of box forecasting in Dynamics 365 Sales

If you're looking to improve your sales performance using Dynamics 365 Sales, this tutorial is the right resource for you. By using the out-of...

21 days ago

Elevating email efficiency using Copilot in Dynamics 365 Sales and the rich text editor 

In today's digital age, effective communication is key to build and maintain strong business relationships and accelerate sales success. As su...

22 days ago

Transform seller effectiveness with Dynamics 365 Sales Copilot

If you want to boost your sales team's productivity, Dynamics 365 Sales Copilot might just be the solution you're looking for. With natural-la...

23 days ago

20 Most commonly used JavaScript Scenarios with Sample code Snippet in Form Script Dataverse/ Dynamics 365 CE

JavaScript is a powerful tool for developers working with Dataverse (formerly known as Common Data Service) and Dynamics 365 Customer Engageme...

23 days ago

New and Retired Microsoft Dynamics 365 Certifications

Microsoft has recently shared updates regarding new and retired certifications for Microsoft Dynamics 365. This post provides an overview of t...

24 days ago

Embed a Power BI Report as a System Dashboard in Dynamics 365 CE Using Environment Variables

Integrating Power BI with Dynamics 365 CE can elevate your decision-making processes by providing seamless access to actionable insights. This...

25 days ago
Stay up to date with latest Microsoft Dynamics 365 and Power Platform news!
* Yes, I agree to the privacy policy