Wednesday, June 10, 2020

Set a Field on the Editable grid disabled.

Add the below script to JS webresource and add that to Form Libraries:
function setChildGridEditability(gridContext) {
    var childGrid = gridContext.getFormContext().data.entity;
    childGrid.attributes.getByName("attributeLogicalName").controls.get(0).setDisabled(true);
}
Register event handler - function setChildGridEditability on Editable Grid - OnRecordSelect event.

Set Pass execution context as first parameter  checked... and Ready!

Monday, March 16, 2020

Useful Powershell scripts

To Connect to CRM

1. Connect to CRM from Powershell Script using Command-line parameters(Ideal for using Script for automation purposes.)
# This PS snippet retreieves the Active Duplicate DEtection Rules frmo the crmDevOrg and activates them in crmTestOrg.
# The User  Name, Password and the Organization Name are to be updated before executing this.

## pass arguments OrganizationURL, UserName, Password
    [CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$true)] [string]$SourceOrganizationName,
        [Parameter(Position=1, Mandatory=$true)] [string]$SourceUserName,
        [Parameter(Position=2, Mandatory=$true)] [string]$SourcePassword,


Install-Module -Name Microsoft.Xrm.Data.Powershell -RequiredVersion 2.8.7 -Scope CurrentUser
$password = ConvertTo-SecureString $SourcePassword -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($SourceUserName,$password)
$crmDevOrg = Get-CrmConnection -Credential $credentials -DeploymentRegion NorthAmerica -OnlineType Office365 -OrganizationName $SourceOrganizationName  -MaxCrmConnectionTimeOutMinutes 5
 
2. Using interactive mode

Install-Module -Name Microsoft.Xrm.Data.Powershell -RequiredVersion 2.8.7 -Scope CurrentUser
$crmDevOrg = Get-CrmConnection –InteractiveMode 


3.Activate Duplicate detection rules with Powershell shell Script depending on the activatesd Rules in another Orgs - say - check form Source Org and ACtivate in the Destination Org

 This PS snippet retreieves the Active Duplicate DEtection Rules frmo the crmDevOrg and activates them in crmTestOrg.
# The User  Name, Password and the Organization Name are to be updated before executing this.

## pass arguments OrganizationURL, UserName, Password
    [CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$true)] [string]$DevOrganizationName,
        [Parameter(Position=1, Mandatory=$true)] [string]$DevUserName,
        [Parameter(Position=2, Mandatory=$true)] [string]$DevPassword,
 [Parameter(Position=3, Mandatory=$true)] [string]$TestOrganizationName,
        [Parameter(Position=4, Mandatory=$true)] [string]$TestUserName,
        [Parameter(Position=5, Mandatory=$true)] [string]$TestPassword
    )

Install-Module -Name Microsoft.Xrm.Data.Powershell -RequiredVersion 2.8.7 -Scope CurrentUser
$password = ConvertTo-SecureString $DevPassword -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($DevUserName,$password)
$crmDevOrg = Get-CrmConnection -Credential $credentials -DeploymentRegion NorthAmerica -OnlineType Office365 -OrganizationName $DevOrganizationName  -MaxCrmConnectionTimeOutMinutes 5
 
$duplicaterules = Get-CrmRecords -conn $crmDevOrg 'duplicaterule' -FilterAttribute statecode -FilterOperator eq -FilterValue Active
$duplicateruleIds = $duplicaterules['CrmRecords'] | select -ExpandProperty duplicateruleid

$password = ConvertTo-SecureString $TestPassword -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($TestUserName,$password)
$crmTestOrg = Get-CrmConnection -Credential $credentials -DeploymentRegion NorthAmerica -OnlineType Office365 -OrganizationName $TestOrganizationName  -MaxCrmConnectionTimeOutMinutes 5
 
foreach($ruleId in $duplicateruleIds)
        {
            write-host "publishing rule id: " $ruleId
            $ddRule_toPublish = New-Object Microsoft.Crm.Sdk.Messages.PublishDuplicateRuleRequest            
            $ddRule_toPublish.DuplicateRuleId= $ruleId
            $crmTestOrg.ExecuteCrmOrganizationRequest($ddRule_toPublish,$trace)  
            Write-Host "Rule Published"       
        }

Thursday, March 12, 2020

Set the Lookup Field value in Power automate, while using Common Data Service Connector (CDS)

When we try to set a Lookup field from the Flow, using a Guid field available in the flow, we get a Resource not found Segment for the segment error.
This is because, when the Unique If field is added directly for a Lookup, the Entity Schema name is not detected by the flow service.  Here's a Work around for it.
If the lookup target entity name is abc_list, then, first type in -  abc_lists/   and then choose the Guid field from the Dynamics entry window.

Friday, February 7, 2020

Set the BPF and Stage through Power Automate for Dynamics 365 CRM

The MS documentation clearly specifies, that the setting BPF/stage is not supported.
This method uses the deprecated Process Id field of an entity for which the BPF is to be set(Only way).
Hence, with future releases the functionality might not work.

Let's consider a Custom entity- Application as the target to set the BPF for.
AS we created a workflow of category BPF (Let's assume we create one with Name "Application Flow")for an entity, System automatically creates an entity to store the BPF information.
For each of the Application record, one record(instance) of the activated BPF will be created and associated automatically.
The  last BPF instance created with Status "Active" is what shows up on the Form, also filtered additionally by the Security Role.
The stages of all the BPF in the System are referenced using Process Stage entity.

The BPF instance has a lookup to :
-The main entity
-Stage entity
-Process (The GUID of the Workflow)
which helps have the references.

To set the BPF  stage for an entity, we need to :
-Retrieve the existing Flow instances associated with the record and delete them,
-Retrieve the stage Id - passing the name of the stage.
-Create a new instance of the BPF , setting the main entity lookup field, Name, Stage Id, Status -Active,Workflow Id and then associate this new instance with the main entity additionally - by setting the Process lookup Field.
Please see the steps oulined below.

Tuesday, January 7, 2020

Create N:N Association, if not already present.
//Code follows

public void associateWithCheck(){
EntityCollection recordCollection = RetrieveMultiple_Attribute(entityLogicalName, new ColumnSet(entityField), entityField, sourceDataFields[0], client);

                            EntityCollection relatedRecordCollection = CrmHelper.RetrieveMultiple_Attribute(relatedEntityLogicalName, new ColumnSet(relatedEntityField), relatedEntityField, sourceDataFields[1], client);
                            if (recordCollection.Entities.Count > 1 || relatedRecordCollection.Entities.Count > 1)
                            {
                                // If you have more than one corresponding record in CRM do something
                                Console.WriteLine("More than 1 match for {0} - {1} please update CRM Data/Data Imported.", entityLogicalName, compareValue);
                            }

                            // Add to the update list - Match found
                            else if (recordCollection.Entities.Count == 1 && relatedRecordCollection.Entities.Count == 1)
                            {
                                Entity record = recordCollection.Entities[0];
                                Entity relatedRecord = relatedRecordCollection.Entities[0];
                                bool areEntitiesAlreadyAssociated = CrmHelper.RelationshipExists(relationshipName, record.Id, entityLogicalName, relatedRecord.Id, relatedEntityLogicalName,client);

                                if (!areEntitiesAlreadyAssociated)
                                {
                                    // entitiesToUpdate.Entities.Add(recordForUpdate);

                                    AssociateRequest associateRequest = new AssociateRequest
                                    {
                                        Target = new EntityReference(entityLogicalName, record.Id),
                                        RelatedEntities = new EntityReferenceCollection
                                        {

                                            new EntityReference(relatedEntityLogicalName, relatedRecord.Id)
                                        },
                                        Relationship = new Relationship(relationshipName)
                                    };
                                    associateRequestWithResults.Requests.Add(associateRequest);
                                    Console.WriteLine(entityLogicalName + " " + sourceDataFields[0] + relatedEntityLogicalName + " " + sourceDataFields[1] + "added to association list");
                                }
                                else {
                                    Console.WriteLine(entityLogicalName + " " + sourceDataFields[0] + relatedEntityLogicalName + " " + sourceDataFields[1] + "already related");
                                        }
                            }
}

Sunday, April 21, 2019

Import Past Dated- Created On Records

We may be wondering how to have a Past Date as Created on - on the records,
This is needed while importing legacy data and we want to have accurate Created on Date, especially if we are building Reports on this data.
The trick is to add the desired Created  on Date on to the Overriddencreatedon field.
It is not possible to achieve this by using Import Wizard/ Plugins/WFs directly.
We can get it to work by using:

1)A Console Application , which creates the records, with the attribute Overriddencreatedon set to the desired past date in the Entity created.

2)A Console Application to create the records, and have a PreCreate Plugin/WF to add the desired past date to Overriddencreatedon attribute of the Target entity.

Below are some samples

1)Console App Only

Supply username, password and url in the app.config
<add key="username" value="example@example.onmicrosoft.com" />
<add key="password" value="password" />
<add key="url" value="https://example.crm.dynamics.com" />
   
//Code Follows as below
namespace sampleUsingOverriddencreatedon
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;

    /// <summary>
    /// Class for the Core importer Logic
    /// </summary>
    public class ImporterLogic
    {
        /// <summary>
        /// Adds past dated lead
        /// </summary>
        /// <returns>Output Message</returns>
        public void createPastLead()
        {

            string connectionString  = $"Url={RetrieveFromconfig("url")};Username={RetrieveFromconfig("username")};Password={RetrieveFromconfig("password")};AuthType=Office365;RequireNewInstance=true";
            CrmServiceClient client = new CrmServiceClient(connectionString);
            Entity lead = new Entity("lead");
            lead["lastname"] = "Harri " + i;
            lead["subject"] = "testoverridencreatedon";
            lead["overriddencreatedon"] = new DateTime(year, i, 1);
            client.Create(lead);
        }
 public static string RetrieveFromconfig(string key)
        {
            string value;
            value = ConfigurationManager.AppSettings[key];
            return value;
        }
    }
}

2) Pre-Create Plugin which would override the Created of the Record Created from any external application
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
namespace OverRidePlugin
{
    public class UpdatedCreatedOn :IPlugin
    {
        public void Execute(IServiceProvider serviceProvider) {
            ITracingService tracingService =
                (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            // Obtain the execution context from the service provider.
            IPluginExecutionContext context = (IPluginExecutionContext)
                serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
            if (context.InputParameters["Target"] is Entity && context.Depth==1) {
                Entity entity = (Entity)context.InputParameters["Target"] ;
                entity["overriddencreatedon"] = new DateTime(2012, 2, 22);
            }

        }
    }
}

Friday, November 9, 2018

Quick Tricks

Merge multiple solutions into one
Steps:
-Create the solution which should contain the merged set of components.
-Considering and example - where i have "solution1", "solution2" and "solution3" as the schema names of the solutions to merge into one destination solution - "solutionfinal"
-Export "solution2", unzip,open the Solution Xml and update the UniqueName property from "solution2" to "solution1".
Zip the updated solution xml with rest of the export file components.
Import the above file back to CRM.
This would merge the components of the solution2 into solution1.
The Display name of solution1 would have now changed to that of solution2, update it back as needed.

Export "solution3", unzip,open the Solution Xml and update the UniqueName property from "solution3" to "solution1".
Zip the updated solution xml with rest of the export file components.
Import the above file back to CRM.
This would merge the components of the solution3 into solution1.
The Display name of solution1 would have now changed to that of solution3, update it back as needed.

You'are done!

The approach leverages the fact that the solution Components are additive upon Import.




 

Thursday, May 10, 2018

Use the View data in the Chart- html Javascript for further processing

 function getParametersFromQuery(query) {

            var parametersDictionary = new Array();

            var parameters = query.split('&');

            for (var i = 0; i < parameters.length; i++) {

                var keyAndValue = parameters[i].split('=');

                parametersDictionary[unescape(keyAndValue[0])] = unescape(keyAndValue[1]);

            }

            return parametersDictionary;

        }
 function loadChartFromCrm(callback) {
           
            var parameters = getParametersFromQuery(window.location.search.substring(1));
            entityName = parameters["typename"];
            parameters = getParametersFromQuery(parameters["data"]);

            var id = parameters["visid"].substr(1, 36);
            var viewId = parameters["viewid"].substr(1, 36);
            var type = parameters["vistype"];
        }
The above retrieved View Id  can be used to retrieve the FetchXml of the view- field Name- "FetchXml" to retrieve the View fetchXml, which in turn can be directly used as the fetch query to retrieve the data corresponding to the View, which can be used for further processing in scenarios like placing Push pins on Bing Map for All the Accounts in NYC / Highlighting the locations where Contacts exist etc.

Sample RemoveFromQueueRequest - Dynamics 365


public void removeRecordFromQueue(Guid entId, IOrganizationService service)
{

    string queueItemQuery = @"<fetch distinct='false' mapping='logical' output-format='xml-platform' version='1.0'>
                        <entity name='queueitem'>
                            <attribute name='queueitemid' />
                            <filter type='and'>
                                   <condition attribute='objectid' value='{0}' operator='eq'/>
                            </filter>
                          </entity>
                        </fetch>";

    queueItemQuery = string.Format(queueItemQuery, entId.ToString());

    EntityCollection returnEntityCollection = service.RetrieveMultiple(new FetchExpression(queueItemQuery));

    foreach (var returnEntity in returnEntityCollection.Entities)
    {       
        RemoveFromQueueRequest removeFromQueueRequest = new RemoveFromQueueRequest
        {
            QueueItemId = returnEntity.Id
        };
        service.Execute(removeFromQueueRequest);
    }
}

Sample Dynamics 365 CRM- Web API Call

 In the below example, "abc_vehicles" is the Plural name of the Entity data being retrieved, scs_name (Filter has been applied on this)and scs_value(This is the field being retrieved) are fields on this entity.

function sampleWebAPIRetrieve{
var vehName = "Honda";
    var vehValue = "";
   var  orCriteria += "scs_name eq '" + vehName + "'";
    var req = new XMLHttpRequest();
    //Added for single service call start
    var reqString = Xrm.Page.context.getClientUrl() + "/api/data/v8.0/abc_vehicles?$select=scs_values&$filter=" + orCriteria;
    req.open("GET", reqString, false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Prefer", "odata.include-annotations=\"OData.Community.Display.V1.FormattedValue\"");

    req.send();

    var results = JSON.parse(req.response);

    if (results.value.length > 0) {

        for (var i = 0; i < results.value.length; i++) {
            vehValue += results.value[i]["scs_values"] + ";";
        }
    }
}

The query can be easily built using CRM Rest Builder.

Using the $expand, the Fields(except lookup field) can be retrieved from the record referred in the Lookup field.