Search code examples
c#dynamics-crm

Dynamics CRM products and bundles in a order


I am experimenting with the example CalculatePrice on the Dynamics CRM example page. And im having a hard time understanding how to get products and bundles in a good manner.

What i wanna try and do is get products from an order with a productstructure attribute and a producttypecode. But it seems whatever i try i get a error The given key was not present in the dictionary.

The query below should look for productID from salesorder based on productID

            QueryExpression query = new QueryExpression("salesorderdetail");
            query.ColumnSet.AddColumns("quantity", "salesorderispricelocked", "priceperunit", "producttypecode", "_productid_value");
            query.Criteria.AddCondition("salesorderid", ConditionOperator.Equal, entity.Id);

            QueryExpression query2 = new QueryExpression("product");
            query2.ColumnSet.AddColumns("productstructure", "productnumber" , "productid");
            query.Criteria.AddCondition("productid", ConditionOperator.Equal, ec.Entities["_productid_value"]);

Then i try to iterate the list of objects to see if they have productstructure and their producttypecode

            for (int i = 0; i < ec.Entities.Count; i++)
            {
            if (ec.Entities[i].GetAttributeValue<int>("producttypecode") == 6)
            { you are a product 
            if (ec.Entities[i].GetAttributeValue<int>("productstructure") == 3){ you are a bundle

This is the link to the sample code i use: https://learn.microsoft.com/en-us/dynamics365/customer-engagement/developer/sample-calculate-price-plugin


Solution

  • For starters, the _productid_value notation is the WebAPI's way to access a lookup field. To access the productid using the SDK's late-bound paradigm, use:

    myEntity["productid"] or

    myEntity.GetAttributeValue<Guid>("productid") or

    myEntity.GetAttributeValue<EntityReference>("productid").

    Beyond that, since Product is a lookup on the OrderDetail, using a couple LinkEntity objects you could get away with a single query.

    I would probably use LINQ and do something like this:

    private void getProducts(Guid salesOrderId)
    {
        using (var context = new Microsoft.Xrm.Sdk.Client.OrganizationServiceContext(svc))
        {
            var query = from od in context.CreateQuery("salesorderdetail")
                        join so in context.CreateQuery("salesorder") 
                        on od.GetAttributeValue<Guid>("salesorderid") equals so.GetAttributeValue<Guid>("salesorderid")
                        join p in context.CreateQuery("product")
                        on od.GetAttributeValue<Guid>("productid") equals p.GetAttributeValue<Guid>("productid")
                        where od.GetAttributeValue<Guid>("salesorderid").Equals(salesOrderId)
                        select new
                        {
                            OrderDetailId = od.GetAttributeValue<Guid>("salesorderdetailid"),
                            ProductId = od.GetAttributeValue<EntityReference>("productid"),
                            Quantity = od.GetAttributeValue<decimal?>("quantity"),
                            IsPriceLocked = so.GetAttributeValue<bool?>("ispricelocked"),
                            PricePerUnit = od.GetAttributeValue<Money>("priceperunit"),
                            ProductTypeCode = od.GetAttributeValue<OptionSetValue>("producttypecode"),
                            ProductStructure = p.GetAttributeValue<OptionSetValue>("productstructure"),
                            ProductNumber = p.GetAttributeValue<string>("productnumber")
                        };
            var results = query.ToList();
            var products = results.Where(e => e.ProductStructure.Value == 6).ToList();
            var bundles = results.Where(e => e.ProductStructure.Value == 3).ToList();                
        }
    }
    

    Please note that local variables results, products, and bundles are an anonymous type. You can loop through and access the properties of each object, but there's also a strong chance you'd want to cast them into instances of a real class.