Monday, August 1, 2022

Create complex dynamic views in Dynamics 365 CRM

Views in Dynamics are based on the filter.Via a filter a query is in fact defined. However, the possibilities are limited when defining a filter. In this blog I will explain an approach with which it is possible to create more complex view filters. This approach uses a pre-operation RetrieveMultiple plugin, which modifies the view filter query before it is executed in Dynamics. In this way much more complex views can be created than is normally possible.

The case

In this example, we will create a dynamic view, which allows you to see a list of records from the based on logged in user State along with TPA and investor values.




below 2 values I'm trying to set dynamic values.

The approach

As said a view in Dynamics is nothing else than a query. When you, as a Dynamics user, use a view to look at certain records, a RetrieveMultiple call takes place in Dynamics where the filter query is given, executed and the found records are returned and shown.

The way we are going to make the view logic dynamic consists of the following steps:

Defining the view filter, containing a certain specific condition
Building a RetrieveMultiple plugin, which recognizes the view filter from step 1 and adapts it
Adding the plugin step, so the plugin will be used


Step 1: Definition of the view filter
In this step, we define the view filter (as System View, so it is available to all users). We include a dummy condition [Name Equals CallReportsOfInterestToCurrentUser] to make the filter query recognizable to our plugin to be built.


Step 2: building the plugin
In this step, we first create the plugin code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;
using System.Web;

namespace FilterQuoteView
{
    public class FilterQuoteView : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {

            ITracingService Tracingservice = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
            try
            {

                if (context.MessageName == "RetrieveMultiple" && context.InputParameters.Contains("Query") && context.Depth < 2)
                    if (context.InputParameters["Query"] is FetchExpression)
                    {
                        var thisQuery = context.InputParameters["Query"];
                        var fetchExpressionQuery = thisQuery as FetchExpression;
                        var query = fetchExpressionQuery.Query;
                        if (fetchExpressionQuery != null)
                        {
                                //QueryExpression query = (QueryExpression)context.InputParameters["Query"];

                                string queryString = query.ToString();
                                Tracingservice.Trace("Query Value : {0}", queryString);
                                if (!(queryString.Contains("abc_tpacommissionamount")))
                                {
                                    Tracingservice.Trace("Selected non TPA/Investor commission View");
                                    return;
                                }
                                Guid user = context.UserId;
                                Tracingservice.Trace("User :" + user);

                                string userquote = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
                                      <entity name='quote'>
                                        <attribute name='quoteid' />
                                        <attribute name='createdon' />
                                        <attribute name='abc_customer' />
                                        <attribute name='quotenumber' />
                                        <attribute name='ownerid' />
                                        <order attribute='createdon' descending='true' />
                                        <filter type='and'>
                                          <condition attribute='abc_overallstatus' operator='eq' value='799240001' />
                                          <condition attribute='ownerid' operator='eq' uitype='systemuser' value='" + user + @"' />
                                        </filter>
                                        <link-entity name='abc_address' from='abc_addressid' to='abc_address' visible='false' link-type='outer' alias='ab'>
                                          <attribute name='abc_state' />
                                          <attribute name='abc_district' />
                                          <attribute name='abc_city' />
                                        </link-entity>
                                      </entity>
                                    </fetch>";

                                EntityCollection QuoteDetails = service.RetrieveMultiple(new FetchExpression(userquote));
                                Tracingservice.Trace("Quote :" + QuoteDetails.Entities.Count);
                                
                                if (QuoteDetails.Entities.Count > 0)
                                {
                                    Tracingservice.Trace("User has Quotes for TPA/Investor Approval");

                                    string Mapping = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
                                              <entity name='abc_usergeographicalmapping'>
                                                <attribute name='abc_usergeographicalmappingid' />
                                                <attribute name='abc_name' />
                                                   <attribute name='abc_state' />
                                                <attribute name='createdon' />
                                                <order attribute='abc_name' descending='false' />
                                                <filter type='and'>
                                                  <condition attribute='abc_employee' operator='eq' uitype='systemuser' value='" + user + @"' />
                                                </filter>
                                              </entity>
                                            </fetch>";
                                    EntityCollection userMapping = service.RetrieveMultiple(new FetchExpression(Mapping));


                                    Tracingservice.Trace("User States :" + userMapping.Entities.Count);

                                    List<Guid> stateId = new List<Guid>();


                                    if (userMapping.Entities.Count > 0)
                                    {
                                        Tracingservice.Trace("User has States Assigned");
                                        //Guid[] guids = new Guid[] { };

                                        foreach (Entity userGraphicalMapping in userMapping.Entities)
                                        {
                                            //guids = userMapping.Entities.Select(con => userGraphicalMapping.GetAttributeValue<EntityReference>("abc_state").Id).ToArray();

                                            stateId.Add(userGraphicalMapping.GetAttributeValue<EntityReference>("abc_state").Id);

                                        }
                                        String State = "";
                                        for (var i = 0; i < stateId.Count; i++)
                                        {   // Assuming that you have array of Guid which is GuidArray .
                                            State += "<value>" + stateId[i] + "</value>";
                                        }
                                        Tracingservice.Trace("Query Value : {0}", State);

                                        string TPAratedetails = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
                                                              <entity name='abc_benchmarkrate'>
                                                                <attribute name='abc_benchmarkrateid' />
                                                                <attribute name='abc_type' />
                                                                <attribute name='abc_state' />
                                                                <attribute name='abc_rate' />
                                                                <attribute name='abc_clienttype' />
                                                                <order attribute='abc_clienttype' descending='false' />
                                                                <filter type='and'>
                                                                  <condition attribute='abc_state' operator='eq' value='" + stateId[0] + @"' />
                                                                  <condition attribute='abc_type' operator='eq' value='2' />
                                                                  <condition attribute='abc_clienttype' operator='eq' value='{7667B824-0A15-EB11-A813-000D3AF0247A}' />
                                                                </filter>
                                                              </entity>
                                                            </fetch>";
                                         EntityCollection TPADetails = service.RetrieveMultiple(new FetchExpression(TPAratedetails));
                                        List<Money> tpa = new List<Money>();

                                        foreach (Entity abc_benchmarkrate in TPADetails.Entities)
                                        {
                                            //guids = userMapping.Entities.Select(con => userGraphicalMapping.GetAttributeValue<EntityReference>("abc_state").Id).ToArray();

                                            tpa.Add(abc_benchmarkrate.GetAttributeValue<Money>("abc_rate"));
                                            

                                        }
                                        Money TPArate = tpa[0];
                                        Tracingservice.Trace("TPA Rates :" + tpa[0].Value.ToString());

                                         string Investorratedetails = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
                                                              <entity name='abc_benchmarkrate'>
                                                                <attribute name='abc_benchmarkrateid' />
                                                                <attribute name='abc_type' />
                                                                <attribute name='abc_state' />
                                                                <attribute name='abc_rate' />
                                                                <attribute name='abc_clienttype' />
                                                                <order attribute='abc_clienttype' descending='false' />
                                                                <filter type='and'>
                                                                  <condition attribute='abc_state' operator='eq' value='" + stateId[0] + @"' />
                                                                  <condition attribute='abc_type' operator='eq' value='1' />
                                                                  <condition attribute='abc_clienttype' operator='eq' value='{7667B824-0A15-EB11-A813-000D3AF0247A}' />
                                                                </filter>
                                                              </entity>
                                                            </fetch>";
                                         EntityCollection InvestorDetails = service.RetrieveMultiple(new FetchExpression(Investorratedetails));

                                        List<Money> invstrrate = new List<Money>();

                                        foreach (Entity abc_benchmarkrate in InvestorDetails.Entities)
                                        {
                                            //guids = userMapping.Entities.Select(con => userGraphicalMapping.GetAttributeValue<EntityReference>("abc_state").Id).ToArray();

                                            invstrrate.Add(abc_benchmarkrate.GetAttributeValue<Money>("abc_rate"));


                                        }
                                        Money InvestorRate = invstrrate[0];
                                        Tracingservice.Trace("Investor Rates :" + invstrrate[0].Value.ToString());

                                        int pageNumber = 1;
                                        // Specify the current paging cookie. For retrieving the first page, 
                                        // pagingCookie should be null.
                                        string pagingCookie = null;

                                        string Quotefilter = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' no-lock='false'>
                                                            <entity name='quote'>
                                                            <attribute name='name'/>
                                                            <attribute name='abc_customer'/>
                                                            <attribute name='createdon'/>
                                                            <attribute name='abc_product'/>
                                                            <attribute name='abc_ordervalidity'/>
                                                            <attribute name='abc_remainingquantity'/>
                                                            <attribute name='quotenumber'/>
                                                            <attribute name='abc_quantity'/>
                                                            <attribute name='abc_cancelledquantity'/>
                                                            <attribute name='abc_orderdate'/>
                                                            <attribute name='abc_warehouse'/>
                                                            <attribute name='abc_approvalstatus'/>
                                                            <attribute name='ownerid'/>
                                                            <attribute name='abc_deliveryrequiredfrom'/>
                                                            <attribute name='abc_dealncrpermt'/>
                                                            <attribute name='abc_additionalexpense'/>
                                                            <order attribute='createdon' descending='true'/>
                                                            <filter type='and'>
                                                            <condition attribute='ownerid' operator='eq' uitype='systemuser' value='" + user + @"'/>
                                                            <condition attribute='abc_overallstatus' operator='eq' value='799240001'/>
                                                            <filter type='or'>
                                                            <condition attribute='abc_tpacommissionamount' operator='gt' value='" + TPArate.Value + @"'/>
                                                            <condition attribute='abc_investorcommissionamount' operator='gt' value='" + InvestorRate.Value + @"'/>
                                                            </filter>
                                                            </filter>
                                                            <link-entity name='msdyn_warehouse' from='msdyn_warehouseid' to='abc_warehouse' visible='false' link-type='outer' alias='a_dc89ff502000ec1194ef000d3af0435a'>
                                                            <attribute name='msdyn_description'/>
                                                            </link-entity>
                                                            <link-entity name='abc_address' from='abc_addressid' to='abc_address' visible='false' link-type='outer' alias='a_ff3ebc91c000ec1194ef000d3af0435a'>
                                                            <attribute name='abc_state'/>
                                                            <attribute name='abc_district'/>
                                                            <attribute name='abc_city'/>
                                                            </link-entity>
                                                            <link-entity name='account' from='accountid' to='abc_customer' visible='false' link-type='outer' alias='a_1e7e13870900ec1194ef000d3af0435a'>
                                                            <attribute name='abc_customerclassification'/>
                                                            <attribute name='abc_customeridfinance'/>
                                                            </link-entity>
                                                            <attribute name='abc_tpacommissionamount'/>
                                                            <attribute name='quoteid'/>
                                                            </entity>
                                                            </fetch>";
                                        Quotefilter = string.Format(Quotefilter, pageNumber, pagingCookie);
                                        Tracingservice.Trace("Retreived the Quote Details");
                                        var conversionRequest = new FetchXmlToQueryExpressionRequest
                                        {
                                            FetchXml = Quotefilter
                                        };
                                        var conversionResponse = (FetchXmlToQueryExpressionResponse)service.Execute(conversionRequest);

                                        // Use the newly converted query expression to make a retrieve multiple
                                        // request to Microsoft Dynamics CRM.
                                        QueryExpression queryExpression = conversionResponse.Query;


                                        context.InputParameters["Query"] = queryExpression;
                                        Tracingservice.Trace("Passed to input Context");

                                }
                                }
                        }
                    }
                    else
                    {
                        Tracingservice.Trace("Context Value : {0}", context.InputParameters["Query"]);
                    }
            }

            catch (Exception e)
            {
                throw new InvalidPluginExecutionException(e.Message);
            }
        }
    }
}


Step 3: adding the plugin step

Finally, we need to add a plugin step for the message retrieveMultiple, on the quote entity


Output:

our view created in step 1 is now dynamically modified by plugin code and expanded with TPA and Investor values based on the logged in user state.








No comments:

Post a Comment