Disqualify Single or Multiple Quotes in Dynamics 365 with One Click!
If you’ve ever needed to mark multiple quotes as lost in Dynamics 365, you know the default “Close Quote” dialog can be slow and repetitive.
In my recent project, the sales team wanted a faster way, one click from the main Quotes view, to disqualify single or multiple quotes, without opening each one or clicking through extra prompts.
Using the out-of-the-box CloseQuote action, a small JavaScript function, and a custom Ribbon Workbench button, I built exactly that. Here’s how.
Why I Needed This
Our sales team often manages multiple quotes at once. The standard process meant:
- Open each quote individually
- Click “Close Quote”
- Fill in the dialog
- Save and repeat for the next one
It was time-consuming, especially for bulk operations. We needed a quick, grid-based action that would:
- Set quotes to Closed – Lost status
- Work for single or multiple selections
- Refresh the grid automatically
Step 1 – Using the OOB CloseQuote
Action
Dynamics 365 provides a built-in CloseQuote
bound action that changes the state and status of a quote to closed. Instead of creating a custom action, I decided to call this OOB action directly from JavaScript.
Step 2 – JavaScript to Call the OOB Action
Here’s the function I wrote to handle both single and multiple quotes:
function disqualifyQuotes(selectedControl) {
// Get the IDs of the records selected in the grid
var ids = selectedControl.getSelectedIds();
// If no records are selected, show a message and stop execution
if (!ids.length) {
Xrm.Navigation.openAlertDialog({ text: "Please select at least one quote." });
return;
}
// Show a progress indicator while processing
Xrm.Utility.showProgressIndicator("Disqualifying quotes...");
// Create an array of requests to process each selected record
var requests = ids.map(function (id) {
// Create the payload for the CloseQuote action
var quoteClose = {
"quoteid@odata.bind": `/quotes(${id.replace(/[{}]/g, "")})`, // Bind to the Quote record
subject: "Quote closed as Lost", // Subject shown in quote close activity
description: "Disqualified via custom script" // Optional description
};
// Build the request object for the OOB CloseQuote action
var request = {
QuoteClose: quoteClose,
Status: 979570003, // Status Reason: Lost
getMetadata: function () {
return {
boundParameter: null,
parameterTypes: {
QuoteClose: { typeName: "Microsoft.Dynamics.CRM.quoteclose", structuralProperty: 5 },
Status: { typeName: "Edm.Int32", structuralProperty: 1 }
},
operationType: 0,
operationName: "CloseQuote" // OOB action name
};
}
};
// Return the execution promise for this request
return Xrm.WebApi.online.execute(request);
});
// Execute all requests and handle the responses
Promise.all(requests)
.then(function () {
// Success: show confirmation and refresh the grid
Xrm.Navigation.openAlertDialog({ text: "Quotes disqualified successfully." });
selectedControl.refresh();
})
.catch(function (err) {
// Error handling
Xrm.Navigation.openAlertDialog({ text: "Error: " + err.message });
})
.finally(function () {
// Close the progress indicator
Xrm.Utility.closeProgressIndicator();
});
}
Step 3 – Adding the Ribbon Button in Ribbon Workbench
- Open Ribbon Workbench and load the Quote entity.
- On the Quote Home Grid, I added a new custom button labeled Close Quote As.
- Unlike the out-of-the-box (OOB) Close Quote option — which typically has a fixed dialog — I enhanced this button with a dropdown menu containing multiple closure reasons tailored to our business needs. The dropdown allows users to directly choose from predefined statuses such
- Expired
- Not Competitive
- Job Cancelled
- Domestic
- Not as Spec
- This approach streamlines the process by letting sales representatives select the appropriate closure reason in one click from the grid, without navigating through additional dialogs. It also ensures consistency in status values while providing more flexibility than the default OOB functionality.
- Assign the JavaScript library containing the
disqualifyQuotes
function. - Pass SelectedControl as the parameter.
- Publish the changes.
Now, the button will be available directly on the Quotes view.

Step 4 – Testing the Feature
- Navigate to the Quotes view in Dynamics 365.
- Select one or more quotes.
- Click the ‘Close Quote as’ button.
- The status of selected quotes changes to Closed – Lost, and the grid refreshes immediately.
This reduced what was previously a multi-click, per-record task into a single action for any number of quotes.
Why This Works Well
- No custom server-side logic – leverages a tested, built-in Dynamics action.
- Bulk friendly – works for multiple records at once.
- Time saving – ideal for busy sales teams handling multiple opportunities.
- Easy to maintain – no extra workflows or plugins required.
To conclude, by combining the OOB Close Quote
action with Ribbon Workbench, I could instantly disqualify quotes from the main grid, saving hours over the course of a month.
If you’re looking to simplify repetitive processes in Dynamics 365, start by exploring what’s already available out of the box, then add just enough customization to make it your own.
🔗 Need help implementing a custom button or enhancing your Dynamics 365 sales process?
At CloudFronts, we help businesses design and implement scalable, user-friendly solutions that streamline daily operations and improve adoption. Whether it’s customizing Ribbon Workbench, integrating OOB actions, or building tailored automation, our team can make it happen.
📩 Reach out to us at transform@cloudfronts.com and let’s discuss how we can optimize your Dynamics 365 environment.