Friday, January 17, 2020

How to make Email signature not editable in email body in Dynamic CRM


Recently, one of the clients asked me to have a preview of email signature on email entity (not to be edited) and signature must be a part of email body when sending out email from Dynamic CRM.

Solution

As the email body is an open editor user can edit the content within it, which might include email signature. The only solution which I find is to create a web-resource to show the preview of email signature and inject it into email body.

1) Let’s begin with creating a sample email signature in Dynamic CRM.
    Navigate to Settings -> Templates -> Email Signatures -> New



2) Create a Webpage (HTML) webresource



Here is a content of web-resource
Note : You can optimize the code further, here it is written to make it more readable.

<html>
<head>
<title></title>
<script>
    function resourceOnLoad()
    {
        debugger;
        var ownerId = parent.Xrm.Page.context.getUserId();
        var entityName = "emailsignature";
        var filterQuery = "?$filter=_ownerid_value eq " + ownerId + " and isdefault eq true";
        window.parent.Xrm.WebApi.online.retrieveMultipleRecords(emailsignature, filterQuery, 1).then(
            function success(result)
            {
                var signatureStr = result.entities[0].presentationxml;
                signatureStr = window.decodeURI(signatureStr);

                signatureStr = signatureStr.replace(/</g, '<');
                signatureStr = signatureStr.replace(/>/g, '>');
                signatureStr = signatureStr.replace(/&/g, '&');
                signatureStr = signatureStr.replace(/"/g, '\'');   // Single Quote

                xmlDoc = (new DOMParser()).parseFromString(signatureStr, "text/html");
                signatureStr = xmlDoc.getElementsByTagName('presentationxml')[0].innerHTML;

                document.getElementById('sig').innerHTML = str;
            },
            function (error)
            {
                Xrm.Utility.alertDialog(error.message);
            }
            );
    }
</script>
</head>
<body onload="resourceOnLoad()">
    <div id="sig">

    </div>
</body>
</html>


3) Inject the web-resource on email entity

Customize the form and Add Web Resource



4) Create a New Email Record and see email signature in preview.




Additional Findings

  • Set email signature as Default to automatically inject email signature to email body.
  • You cannot create any relationship with Email Signature entity in D365 CRM

Here are some more articles

>> Enhanced Email Communication in Dynamic 365 CRM

>> Configure email synchronization and Mailboxes on Microsoft Dynamics CRM 365 Online

>> How to make Email signature NOT editable in email body in Dynamic CRM

>> Send an email from Dynamic CRM in C#

>> Change the email template content dynamically in Dynamic CRM

>> Error: The email must have at least one recipient before it can be sent.

Wednesday, January 8, 2020

How to migrate Personal Views, Dashboard and Charts in Dynamic CRM


I was involved in Data migration activity for one of my customer’s and whose CRM Users have heavily created Personal Views, Personal Dashboard and Personal Charts too. It seems the reporting was required daily.

Why I ended up creating C# Console App
This client wanted to move to latest version of Dynamic CRM and wanted to move from one tenant to another tenant, so simply taking DB backup and migrating it with Deployment manager was rejected by Microsoft itself as during 2018 it was not supported, so I help them with their migration activity in combination of some supported tools and little bit of C# applications.

Here in this article, I am sharing C# code to migrate
  • Personal Views,
  • Personal Dashboard and
  • Personal Charts




C# Code Sample


  • Code is provided with comments to help with better understanding. 
  • Recommend to run it in Debugging more to see it working. 


ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
CrmServiceClient orgSvc_Source = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Source"].ConnectionString);
CrmServiceClient orgSvc_Target = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Target"].ConnectionString);

if (!(orgSvc_Source.IsReady && orgSvc_Target.IsReady))
{
    Console.ReadKey();
    return;
}
QueryExpression userQueryExp = new QueryExpression("systemuser") { ColumnSet = new ColumnSet(true), NoLock = true };

EntityCollection systemUsersFromSource = orgSvc_Source.RetrieveMultiple(userQueryExp);

foreach (Entity userRecSource in systemUsersFromSource.Entities)
{
    if (userRecSource.Attributes["userlicensetype"].ToString() == "-1")
    {
        continue;   // User must have valid License Type
    }
    if (userRecSource.Id != Guid.Parse("72F2F31C-EF96-45EB-AAB5-F84FAE173D78"))
    {
        continue;   // If you need to Skip any Specific Users
    }

    Guid instanceOneUserId = userRecSource.Id;
    orgSvc_Source.CallerId = instanceOneUserId;

    QueryExpression userSavedQueries = new QueryExpression("userquery")
                    { ColumnSet = new ColumnSet() { AllColumns = true }, NoLock = true };

    QueryExpression query1 = new QueryExpression("userqueryvisualization")
                    { ColumnSet = new ColumnSet() { AllColumns = true }, NoLock = true };

    QueryExpression query2 = new QueryExpression("userform")
                    { ColumnSet = new ColumnSet() { AllColumns = true }, NoLock = true };

    //Fetch all personal views, charts and dashboards
    List personalViews = orgSvc_Source.RetrieveMultiple(userSavedQueries).Entities.ToList();
    List personalCharts = orgSvc_Source.RetrieveMultiple(query1).Entities.ToList();
    List personalDashboards = orgSvc_Source.RetrieveMultiple(query2).Entities.ToList();

               
    EntityCollection systemUsersFromTarget = orgSvc_Target.RetrieveMultiple(userQueryExp);
    foreach (Entity userRecTarget in systemUsersFromTarget.Entities)
    {
        if (!(userRecTarget.Id == Guid.Parse("325BF9DE-AF11-E911-A994-000D3A33AFD1")))
        {
            continue;   // Here you can decide which user you wish to Assign
        }
        Guid instanceTwoUserId = userRecTarget.Id;
        orgSvc_Target.CallerId = instanceTwoUserId;

        //Personal Views
        personalViews.ForEach(e =>
        {  
            Console.WriteLine(e.Attributes["name"].ToString());
            // On my case we have only ONE Root BU, please handle you case specifically
            e.Attributes["owningbusinessunit"] =
                    new EntityReference("businessunit", Guid.Parse("33EA22FE-F004-E911-A956-000D3A37FBCE"));

            e.Attributes["ownerid"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["owninguser"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["modifiedby"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["createdby"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);                       
            orgSvc_Target.Create(e);
        });

        //Personal Charts
        personalCharts.ForEach(e =>
        {
            Console.WriteLine(e.Attributes["name"].ToString());
            e.Attributes["owningbusinessunit"] =
                    new EntityReference("businessunit", Guid.Parse("33EA22FE-F004-E911-A956-000D3A37FBCE"));

            e.Attributes["ownerid"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["owninguser"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["modifiedby"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["createdby"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            orgSvc_Target.Create(e);
        });

        //Personal Dashboards
        personalDashboards.ForEach(e =>
        {
            Console.WriteLine(e.Attributes["name"].ToString());
            e.Attributes["owningbusinessunit"] =
                    new EntityReference("businessunit", Guid.Parse("33EA22FE-F004-E911-A956-000D3A37FBCE"));

            e.Attributes["ownerid"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["owninguser"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["modifiedby"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            e.Attributes["createdby"] = new EntityReference(userRecTarget.LogicalName, userRecTarget.Id);
            orgSvc_Target.Create(e);
        });
    }//end foreach inner
}//end foreach outer





I wish you all the best with the code.

Thanks
Vipin Jaiswal
vipinjaiswal12@gmail.com

Tuesday, December 31, 2019

How to create SSRS Report in Dynamic 365 CRM

Note : You need to setup your machine to begin with SSRS report development.
Refer here for more details

How to setup Workstation to Create SSRS Reports for Dynamics 365



To create reports, launch Visual Studio.

Click on File -> New -> Project

The New Project Dialog will appear.

From the Templates, choose Business Intelligence -> Reporting Services and select Report Server Project.



Once that is loaded, from the Solution Explorer 
on the right-hand side, right click on the Reports folder, choose Add -> New Item


Choose to create a Report file and give it a name.  
The “RDL” extension stands for “Report Definition Language” which is an XML interpretation
of the report you will create.


The report design surface will appear.


The first step is to create a link to your Dynamics 365 system.  
On the left of the report designer window, in the Report Data section, 
Right click on the Data Sources folder and click “Add Data Source”.



If the Report Authoring extensions were installed correctly, you should see “Microsoft
 Dynamics 365 Fetch” as a type. 


Provide the Data Source with a name and enter in your URL for your Dynamics 365 system.



Click on credentials and enter in your Dynamics 365 login and password. 


Note that these will not be “carried” with the report, but just used in the designer. 
When we eventually load the report in Dynamics 365 it will run in the context 
of the logged in user (and applicable security roles will apply)




We need to add a Dataset to pull data from Dynamics 365.  We will be using a query language called “FetchXML”.

While you could construct a FetchXML by hand, it is easier to generate using a tool.

One quick way to get a FetchXML query is from Dynamics 365 Advanced Find.



Looking at the FetchXML file, you can see the structure identifying the entity, the fields and filters.





Again on the Report Data section, right click on the Datasets folder and choose “Add Dataset”




Provide a name, choose to use the embedded dataset that we created earlier and paste in the FetchXML statement.




You should now see a dataset in the Report Data section.




For the first report, we will just drag a “table” component onto the design surface.

Left Click on the table and select Tablix Properties

Provide Dataset Name




Populate the field in the table.



Once we have defined our layout (pretty simple at this point) we can click the “Preview” button to see what our report will look like.




Now that we have our report created, lets load it to Dynamics 365!

Loading the Report to Dynamics 365

Login to Dynamics 365 and choose Sales or Service and click on the Reports icon.


You will see the list of out of the box reports.  Click on the +NEW button to add your new report.

Change Report Type to Existing File and Choose your ContactList.rdl file.

Select Related Record Types and other option as depicted in the image below.





The report should now appear on the list of available reports.  Double click the report to run.



You should now see your report rendered within the context of Dynamics 365.  You can now print or download to a variety of formats.




The report we created in this article needs a lot of formatting to be production ready and VST provide a way to do that.

Refer here my other post to understand a bit more about SSRS Report in Dynamic CRM.

Dynamic CRM SSRS Report best configuration

https://vjcity.blogspot.com/2019/05/dynamic-crm-ssrs-report-best.html

Dynamic CRM SSRS Report Syntax Help