web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

No record found.

News and Announcements icon
Community site session details

Community site session details

Session Id :
Customer experience | Sales, Customer Insights,...
Answered

How to auto populate products from opportunity to quote using plugin?

(0) ShareShare
ReportReport
Posted on by 50

Hi,

I need to auto populate products given in opportunity form to quote form when a custom create quote button is clicked. All these need to be achieved using plugin. Can anyone help me regarding this?

Thanks in advance

I have the same question (0)
  • Community Member Profile Picture
    on at

    Can you please verify this is the flow of things?

    Opportunity is using Opportunity Products (OOB entity), custom button will be on the Opportunity form.  On click of custom button create a quote and add all quote products from the opportunity products?

    If this is true, is there a reason for a custom button vs. the OOB functionality?  Possibly a better work around than a plugin.

    If its a must - then the button would need to call something that then triggers the plugin because the buttons trigger JavaScript and not a plugin directly.  You have a few options:

    - look into an action that gets called from your javascript, which then calls a custom workflow activity.

    - Have the Javascript create something - could be the quote, could be a staging entity (quote queue).  The queue could trigger the plugin.

    If you provide more information on the need, I can probably provide a better practice of how to build it out.

    - Realtime vs. background?

    - Why NOT use the OOB button process?

  • Priya_1 Profile Picture
    50 on at

    Hii,

    Actually the main task is that a custom quote button is to be created using ribbon work bench on opportunity form and JavaScript code has to be written so that on click of that button a new quote form has to be created with price lists getting auto populated from opportunity to quote. This is done.

    The next thing is to write a plugin code so that products from opportunity has to get auto populated to quote. This is the task to be completed

  • Verified answer
    Community Member Profile Picture
    on at

    You'll get some errors to work through, but here is some code I used to do something similar, I tried to remove most of the unnecessary thing that were specific to my requirements and anything in ALLCAPS needs to be replaced.  This is a custom workflow activity, I like these better than plugins, but you can convert it if you like.  Make sure to substitute your fields for the ones I have.

    using System;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using System.Activities;
    using Microsoft.Xrm.Sdk.Workflow;

    namespace WILLAUTOPOPULATE
    {
    public sealed class CLASSNAME : CodeActivity
    {
    protected override void Execute(CodeActivityContext context)
    {

    try
    {
    this.ExecuteBody(context);
    }
    catch (Exception ex)
    {
    Message.Set(context, String.Format("{0} - {1}", LogMessage, ex.Message));
    IsSuccess.Set(context, false);
    }
    }

    public void ExecuteBody(CodeActivityContext executionContext)
    {
    var service = GetService(executionContext);
    var quoteRef = QuotRef.Get(executionContext);
    var optyRef = OptyRef.Get(executionContext);

    try
    {
    var fetchData = new
    {
    OPTYGUID = optyRef.Id.ToString()
    };
    var fetchXml = $@"
    <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
    <entity name='OPTYPRODUCTSENTITYNAMEHERE'>
    <attribute name='name' />
    //ADD FIELDS YOU WANT
    <filter type='and'>
    <condition attribute='OPTYLOOKUPFIELDSCHEMA' operator='eq' value='{fetchData.OPTYGUID}'/>
    </filter>
    <link-entity name='product' from='productid' to='product' visible='false' link-type='inner' alias='parentProduct'>
    <attribute name='defaultuomid' alias='defaultUOMID' />
    <attribute name='transactioncurrencyid' alias='defaultCurrency' />
    <filter type='and'>
    <condition attribute='statuscode' operator='eq' value='1'/>
    </filter>
    </link-entity>
    </entity>
    </fetch>";

    EntityCollection optyProdCollection = service.RetrieveMultiple(new FetchExpression(fetchXml.ToString()));
    if (null == optyProdCollection || null == optyProdCollection.Entities || optyProdCollection.Entities.Count == 0)
    {
    //No account products found
    return;
    }
    else
    {
    foreach (Entity optyProds in optyProdCollection.Entities)
    {
    Guid uomtoUse = ((EntityReference)optyProds.GetAttributeValue<AliasedValue>("defaultUOMID").Value).Id;

    Entity quoteProdCreate = new Entity("quoteproduct");
    quoteProdCreate["quoteproductname"] = optyProds.GetAttributeValue<string>("name");
    quoteProdCreate["productid"] = new EntityReference("product", optyProds.GetAttributeValue<EntityReference>("prefix_product").Id);
    quoteProdCreate["opportunityid"] = new EntityReference("opportunity", optyRef.Id);
    quoteProdCreate["uomid"] = new EntityReference("uom", uomtoUse);
    quoteProdCreate["transactioncurrencyid"] = new EntityReference("transactioncurrency", ((EntityReference)optyProds.GetAttributeValue<AliasedValue>("defaultCurrency").Value).Id);

    quoteProdCreate["skippricecalculation"] = new OptionSetValue(0);
    quoteProdCreate["pricingerrorcode"] = new OptionSetValue(0);
    quoteProdCreate["quantity"] = new decimal(1);
    quoteProdCreate["ispriceoverridden"] = true;
    quoteProdCreate["producttypecode"] = new OptionSetValue(1);
    quoteProdCreate["propertyconfigurationstatus"] = new OptionSetValue(2);
    quoteProdCreate["isproductoverridden"] = false;
    service.Create(quoteProdCreate);
    }
    }
    }
    catch (Exception ex)
    {
    Message.Set(executionContext, String.Format("{0} - {1}", LogMessage, ex.Message));
    IsSuccess.Set(executionContext, false);
    }
    }

    [Input("Quote")]
    [ReferenceTarget("quote")]
    public InArgument<EntityReference> QuoteRef { get; set; }
    [Input("Opportunity")]
    [ReferenceTarget("opportunity")]
    public InArgument<EntityReference> OptyRef { get; set; }
    [Output("Message")]
    public OutArgument<string> Message { get; set; }
    [Output("IsSuccess")]
    public OutArgument<bool> IsSuccess { get; set; }
    public IOrganizationService GetService(ActivityContext executionContext, Guid? user)
    {
    if (executionContext == null)
    {
    throw new ArgumentNullException("executionContext");
    }
    var svcFactory = executionContext.GetExtension<IOrganizationServiceFactory>();

    if (user == null)
    {
    var workflowContext = executionContext.GetExtension<IWorkflowContext>();
    return svcFactory.CreateOrganizationService(workflowContext.UserId);
    }
    else
    {
    return svcFactory.CreateOrganizationService(user);
    }
    }
    public IOrganizationService GetService(CodeActivityContext executionContext)
    {
    return this.GetService(executionContext, null);
    }
    public ITracingService GetTracingService(ActivityContext executionContext)
    {
    if (executionContext == null)
    {
    throw new ArgumentNullException("executionContext");
    }

    ITracingService tracingService = executionContext.GetExtension<ITracingService>();

    return tracingService;
    }
    }
    }

  • Priya_1 Profile Picture
    50 on at

    Thank you

  • Priya_1 Profile Picture
    50 on at

    Is this a correct workflow code

    using System;

    using Microsoft.Xrm.Sdk.Workflow;

    using Microsoft.Xrm.Sdk;

    using Microsoft.Xrm.Sdk.Query;

    using System.Activities;

    namespace Order

    {

    public class Order : CodeActivity

    {

    protected override void Execute(CodeActivityContext executionContext)

    {

    ITracingService tracingService = executionContext.GetExtension<ITracingService>();

    IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();

    IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();

    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

    //var service = GetService(executionContext);

    var quoteRef = QuotRef.Get(executionContext);

    var orderRef = OrderRef.Get(executionContext);

    try

    {

    tracingService.Trace("No incident");

    var fetchData = new

    {

    QuoteGUID = quoteRef.Id.ToString()

    };

    var fetchXml = $@"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>

    <entity name='quotedetail'>

    <attribute name='productid' />

    <attribute name='productdescription' />

    <attribute name='priceperunit' />

    <attribute name='quantity' />

    <attribute name='extendedamount' />

    <attribute name='quotedetailid' />

    <order attribute='productid' descending='false' />

    <link-entity name='quote' from='quoteid' to='quoteid' link-type='inner' alias='aa'>

    <filter type='and'>

    <condition attribute='quoteid' operator='eq' value='{fetchData.QuoteGUID } />

    </filter>

    </link-entity>

    </entity>

    </fetch>

    ";

    EntityCollection quoteProdCollection = service.RetrieveMultiple(new FetchExpression(fetchXml.ToString()));

    if (null == quoteProdCollection || null == quoteProdCollection.Entities || quoteProdCollection.Entities.Count == 0)

    {

    return;

    }

    else

    {

    foreach (Entity quoteProds in quoteProdCollection.Entities)

    {

    Entity orderProdCreate = new Entity("salesorderdetail");

    orderProdCreate["salesorderdetailid"] = new EntityReference("salesorder", orderRef.Id);

    EntityReference uOM = quoteProds.GetAttributeValue<EntityReference>("uomid");

    orderProdCreate["uomid"] = new EntityReference("uom", uOM.Id);

    orderProdCreate["productid"] = new EntityReference("product", quoteProds.GetAttributeValue<EntityReference>("productid").Id);

    orderProdCreate["quantity"] = quoteProds.GetAttributeValue<decimal>("quantity");

    orderProdCreate["ispriceoverridden"] = false;

    service.Create(orderProdCreate);

    }

    }

    }

    catch (Exception ex)

    {

    throw new Exception(ex.Message);

    }

    }

    [Input("Order")]

    [ReferenceTarget("salesorder")]

    public InArgument<EntityReference> OrderRef { get; set; }

    [Input("Quote")]

    [ReferenceTarget("quote")]

    public InArgument<EntityReference> QuotRef { get; set; }

    }

    }

    I am getting it like "invalid XML"

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Introducing the 2026 Season 1 community Super Users

Congratulations to our 2026 Super Stars!

Meet the Microsoft Dynamics 365 Contact Center Champions

We are thrilled to have these Champions in our Community!

Congratulations to the March Top 10 Community Leaders

These are the community rock stars!

Leaderboard > Customer experience | Sales, Customer Insights, CRM

#1
ManoVerse Profile Picture

ManoVerse 196 Super User 2026 Season 1

#2
11manish Profile Picture

11manish 129

#3
CU11031447-0 Profile Picture

CU11031447-0 100

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans