Syncing Product From Quotes To Opportunity

Requirement

The quote product should be synched to the opportunity when a quote is activated.

Implementations

In the traditional sales life cycle, we create quote from opportunity which inherit all the opportunity data as well as products from opportunity.

Syncing product from Quotes to Opportunity

But sometimes while working on the quote negotiations with the customer some information can be updated on the quote products or may new product is added or maybe the existing product is not required anymore by the customer and this can be easily done in the quote. But what about if we want to synchronize quote products with opportunity product once the quote is final maybe when the quote is activated? We can do this using a plugin, let’s see how.

I am not going to provide steps to create VS solution but if you are new to plugin development please refer to Dynamics 365 CE SDK for how to write plugins.

Back to the topic. So we want to synchronize products when the quote is activated which means we need to make sure our plugin is triggered on Quote Activation, earlier we used to do that in different events like setstate, etc. but now we can simply register it on Update of quote entity.

Entity quoteEntity = null;
Entity postupdateQuote = null;
if (pluginContext.InputParameters.Contains("Target") && pluginContext.InputParameters["Target"] is Entity) {
    quoteEntity = (Entity) pluginContext.InputParameters["Target"];
    if (pluginContext.PostEntityImages.Contains("postimage")) {
        postupdateQuote = (Entity) pluginContext.PostEntityImages["postimage"];
    }
    //check if quote is active
    if (quoteEntity.Contains("statecode") && quoteEntity.GetAttributeValue < optionSetValue > ("statecode").Value == 1) {
        if (postupdateQuote.Contains("opportunityid")) {
            SyncQuoteProductToOpportunityProduct(postupdateQuote.GetAttributeValue < EntityReference > ("opportunityid").Id, quoteEntity.Id);
        }
    }
}

In the above code, we are getting our entity object and getting postupdatequote from the post entity image as we need the opportunity and we will not get it under the quote entity input parameter. So we need to get it using entity image. Once we have the quote entity we are checking if statecode value is 1 which means the quote is activated.

Now next in our SyncQuoteProductToOpportunityProduct method, we need to get the opportunity product and quote product to compare, we can do this like below

private void SyncQuoteProductToOpportunityProduct(Guid parentoppid, Guid parentquoteid) {
    EntityCollection oppproducts = null;
    EntityCollection quoteproducts = null;
    bool ismatchfound = false;
    oppproducts = GetOpportunityProducts(parentoppid); //this method is to get all opportunity products based on opportunity
    quoteproducts = GetQuoteProducts(parentquoteid); //this method is to get all quote products based on quote
    //check all quote product available in opportunity product if yes update properties if not add new product
    foreach(Entity quoteprod in quoteproducts.Entities) {
        ismatchfound = false;
        foreach(Entity oppprod in oppproducts.Entities) {
            if (oppprod.GetAttributeValue < EntityReference > ("productid").Id == quoteprod.GetAttributeValue < EntityReference > ("productid").Id) {
                ismatchfound = true;
                //sync field values
                Entity oppprodUpdate = new Entity("opportunityproduct");
                oppprodUpdate.Id = oppprod.Id;
                oppprodUpdate["priceperunit"] = quoteprod.GetAttributeValue < Money > ("priceperunit").Value;
                oppprodUpdate["quantity"] = quoteprod.GetAttributeValue < decimal > ("quantity");
                oppprodUpdate["uomid"] = quoteprod.GetAttributeValue < EntityReference > ("uomid");
                oppprodUpdate.Update(oppUpdate);
            }
        }
        //if no match found add new product
        if (!ismatchfound) {
            Entity oppprodCreate = new Entity("opportunityproduct");
            oppprodCreate["productid"] = quoteprod.GetAttributeValue < EntityReference > ("productid");
            oppprodCreate["priceperunit"] = quoteprod.GetAttributeValue < Money > ("priceperunit").Value;
            oppprodCreate["quantity"] = quoteprod.GetAttributeValue < decimal > ("quantity");
            oppprodCreate["uomid"] = quoteprod.GetAttributeValue < EntityReference > ("uomid");
            oppprodCreate["opportunityid"] = quoteprod.GetAttributeValue < EntityReference > ("opportunityid");
            orgService.Create(oppprodCreate);
        }
    }
    //reset flag
    ismatchfound = false;
    //finally delete extra opportunity products
    foreach(Entity oppprod in oppproducts.Entities) {
        foreach(Entity quoteprod in quoteproducts.Entities) {
            if (oppprod.GetAttributeValue < EntityReference > ("productid").Id == quoteprod.GetAttributeValue < EntityReference > ("productid").Id) {
                ismatchfound = true;
            }
        }
        //if oppprod not found on quote delte it
        if (!ismatchfound) {
            orgService.Delete("opportunityproduct", oppprod.Id);
        }
    }
}

Once our plugin is ready we can register it on Quote update make sure to select setstatecode under filtering attributes.

Syncing product from Quotes to Opportunity

Summary

This is how we can sync products from quote to opportunity

Hope it will help someone !!

Keep learning and Keep Sharing !!


Similar Articles
HIMBAP
We are expert in Microsoft Power Platform.