Dear MS Could you please just fix the following? Pretty Please🙏🥰

I love the new UI and the new timeline, but there were some choices made that never made sense. Specifically the navigation elements on the timeline.

Ideas – Please vote

https://experience.dynamics.com/ideas/idea/?ideaid=187baf8c-5fdd-ea11-bf21-0003ff68e671#

This is a OOTB case with a timeline. I want to open one of the emails to view content or reply. Either way I want to OPEN the activity.

Let’s click on the Email and see what happens…

NOPE… Only the preview of the email. Great functionality, but still not what I want.

What about the BIG Purple circle? That is the same logic as subgrids. This must be it?

NOPE… This opens the owner of the activity…. Why would anyone want this function? Seriously asking, because I have never understood why.

There it is!!!.. The tiny little OPEN button….

Subrids do it better

Check it out.. I click on the subgrid item, and magically it opens the actual record I am trying to see.

BOOM

This is more like it..

Dear MS… Please make the navigation look and feel the same as subgrids 🙂

RegardingObjectID Type fix – Flow

How to fix the RegardingObjectID Type field in FLOW

When working with the Current Environment Connector (CDS), you have 2 options for a lookup (Value and Type). For some strange reason only one of them seems to work for me.

The Value is obviously the GUID, and the Type is “incidents, accounts, contacts, opportunities etc”.

Let’s look at the data:

As you see I have values for the GUID and the Type of regardingobjectid.

When adding them to the Compose the TYPE returns blank every time.

Peek kode

{    “inputs”: “@{triggerOutputs()?[‘body/_regardingobjectid_value’]}\n@{triggerOutputs()?[‘body/_regardingobjectid_value@Microsoft.Dynamics.CRM.lookuplogicalname‘]}”}

Flow is referencing the TYPE of lookup in a way that returned NULL every time.

Solution

Manually enter the expression:
triggerOutputs()?[‘body/_regardingobjectid_type’] <- change the VALUE with TYPE

Dynamics Customer Service – B2B scenario

This post is a part of a series of posts for Customer Service. The complete GUIDE can be found here

Many years ago Opportunity retired the Customer field and replaced it with Primary Contact and Primary Account fields. Case has not yet done this for reasons I can’t really understand. As you will see in this article we achieve the same result when adding the contact field, but the customer field is still a polymorphic lookup.

Email to Case could easily add to the contact field instead of the customer field. Field service is actually dependent on account being in the customer field for it to work properly.

This is how Case has to be setup to make sense in the B2B world:

If the Contact and Customer are known to the system, they will automatically populate. If the Contact is new to the system, the connection to the Account will be missing. In this case we need to alert the Agent, and ask them to update the contact record.

JavaScript

The following JavaScript is added to the Case form. It checks the Customer field to see if it is contact. If this is the case, it will check if the Contact has a Account connected. Most likely it will not have an Account, so we will be prompted “Do you wish to update the Contact?”. Answer YES here, and a quick view of the Contact will appear. Update Account, and then the JavaScript will do the rest for you. ✨MAGIC✨

var formContext = "";

function OnCrmPageLoad(executionContext) {
    formContext = executionContext.getFormContext();
    
    //
    //You don't need to change this. Just understand that forms have one the following states when opening
    //
    var FormTypes =
    {
        Undefined: 0,
        Create: 1,
        Update: 2,
        ReadOnly: 3,
        Disabled: 4,
        QuickCreate: 5,
        BulkEdit: 6
    }
    runAlways(formContext);
    switch (formContext.ui.getFormType()) {
        case FormTypes.Create: OnNewFormLoad(); break;
        case FormTypes.Update: OnUpdateFormLoad(); break;
        case FormTypes.ReadOnly: OnReadOnlyFormLoad(); break;
        case FormTypes.Disabled: OnDisabledFormLoad(); break;
        case FormTypes.QuickCreate: OnQuickCreateFormLoad(); break;
        case FormTypes.BulkEdit: OnBulkEditFormLoad(); break;
        case FormTypes.Undefined: alert("Error"); break;
    }
}

//
//I only use the RunAlways, OnNewFormLoad and OnUpdateFormLoad, but i keep the others here if i ever would need. 
//When looking at this you can always know what funtion is running. Easy to read and debug. 
//
function runAlways() { }
function OnNewFormLoad() {}
function OnUpdateFormLoad() {
    //
    //Clean up Contact Data. If contact has account, but account not in Customer field perform update. If Contact doen's have account ask for update
    //
    GetAccountInfo();
}
function OnReadOnlyFormLoad() { }
function OnDisabledFormLoad() { }
function OnQuickCreateFormLoad() { }
function OnBulkEditFormLoad() { }


//******************************************************************** */
//CUSTOM FUNCTIONS are added below here. Below this point you add all types of functions you need. 
//******************************************************************** */
function GetAccountInfo() {
    var CustomerField = formContext.getAttribute("customerid").getValue();
    if (CustomerField != null) {
        if (CustomerField[0].entityType == "contact") {
            var CustomerGUID = CustomerField[0].id;
            CustomerGUID = CustomerGUID.replace("{", "");
            CustomerGUID = CustomerGUID.replace("}", "");

            //
            //If the Customer Field contains a contact, I want to change this. I want the Customer Field to be an account. Step 1 is to find out if the contact has account registered.
            //
            Xrm.WebApi.online.retrieveRecord("contact", CustomerGUID, "?$select=_parentcustomerid_value").then(
                function success(result) {
                    var Id = "{" + result["_parentcustomerid_value"] + "}";
                    var Name = result["_parentcustomerid_value@OData.Community.Display.V1.FormattedValue"];
                    var LogicalName = result["_parentcustomerid_value@Microsoft.Dynamics.CRM.lookuplogicalname"];

                    //
                    //IF the contact has an account I move the Contact to Case Contact, and receive the Account from the Contact and enter it to Customer on Case.
                    //
                    if (LogicalName != null){
                        formContext.getAttribute("primarycontactid").setValue(CustomerField);
                        formContext.getAttribute("customerid").setValue([{ id: Id, name: Name, entityType: LogicalName }]);
                        formContext.data.entity.save();
                    }else{
                        //
                        //Promt if you want to open contact for update?
                        //https://carldesouza.com/how-to-implement-javascript-confirmation-dialogs-in-power-apps-and-dynamics-365/ - THANK YOU
                        //
                        var confirmStrings = { text:"Contact is not connected to Account. Please update!", title:"Data Update Recommended", confirmButtonLabel:"Open Contact", cancelButtonLabel: "Not Now" };
                        var confirmOptions = { height: 200, width: 450 };
                        Xrm.Navigation.openConfirmDialog(confirmStrings, confirmOptions).then(
                        function (success) {    
                            if (success.confirmed){
                                //
                                //If the user chooses to update, I open a small contact form, and make the user set the Account. 
                                //After Save&Close i recall this function, and then I update Account and Contact for case. 
                                //
                                Xrm.Navigation.navigateTo({pageType:"entityrecord", entityName:"contact", formType:2, formId:"e4206691-b1e3-4e9d-a23a-4865b9511091", entityId:CustomerGUID}, {target: 2, position: 1, width: {value: 20, unit:"%"},height: {value: 50, unit:"%"}}).then(
                                    function success() {
                                        GetAccountInfo();
                                    },
                                    function error() {
                                        alert("The system was not able to save the change. Please reload the page and try again");
                                    }
                                );
                            }else{
                                //Say or do something if the user doesn't update Contact
                            }
                        });

                    }
                },
                function (error) {
                    Xrm.Utility.alertDialog(error.message);
                }
            );
            
        }
    }

}

Result

Dynamics 365 Email – HTML Signature and Sender

This post is a part of a series of posts for Customer Service. The complete GUIDE can be found here

Every time I setup Customer Service I encounter the same 2 problems.
1. I want to send from a QUEUE
2. I need to automatically add a signature

Am I really the only one having these problems, or are we all doing the same silly tasks every time?

Standard Signature OOTB

You can enter a standard signature per user, but this signature does not support HTML formatting for some reason. The email you are writing to is in fact a HTML email. Signature that is injected is text into a HTML, but the signature editor is a simple text editor.

When we open the email, the default signature will appear.

PlussMinus
1. You can use standard MS functions to auto insert signature

2. Users can easily make changes to personal signature.


1. Does not support HTML formatting of signature

2. Every user can configure personal signature, and you can’t control it for company profiling.

3. If you work with customer service you have to 4-5 clicks to find the correct signature for Customer Service to enter.

Standard Sender FROM

Whenever you open an email in Dynamics it will default to your email address. Normally I would say this if fine, but why on earth would you want to do this when setting up a Customer Service system?

A user would have to change the FROM to the Customer service

Imagine having to do this every single time you want to answer an email in Dynamics Customer Service! I personally would go crazy.

Design

I solve this by creating a custom entity called Signature and use a standard field on User “Default Queue” to solve the 2 problems. This involves some javascript, but will provide everything you need. In my last post of this series, I will also include the managed and unmanaged files you need to do it yourself.

From the Email I will now retrieve the HTML signature and default sender for this contact.

1. HTML Signature

I found this little tool that generates an HTML signature. It seems like a cool little piece of free software that will create nice HTML signatures. The HTML you generate, can be copy pasted directly into the signature entity.

https://si.gnatu.re/

After messing about for a while I got the following result.

Example HTML

<table width="351" cellspacing="0" cellpadding="0" border="0"> <tr> <td style="vertical-align: top; text-align:left;color:#000000;font-size:12px;font-family:helvetica, arial;; text-align:left"> <span><span style="margin-right:5px;color:#000000;font-size:15px;font-family:helvetica, arial">Customer Service Team</span> <br><span style="margin-right:5px;color:#000000;font-size:12px;font-family:helvetica, arial">Super Duper Helper</span></span> <br> <span style="font:12px helvetica, arial;">E-mail&nbsp;<a href="mailto:support@support.com" style="color:#3388cc;text-decoration:none;">support@support.com</a></span> <br> <span style="font:12px helvetica, arial;">Telephone&nbsp;<span style="color:#000000">22222222</span></span> <br> <table cellpadding="0" cellpadding="0" border="0"><tr><td style="padding-right:5px"><a href="https://facebook.com/https://www.facebook.com/pointtakenas" style="display: inline-block;"><img width="40" height="40" src="https://s1g.s3.amazonaws.com/d927102059ee8fca87e6e3f49e77e9e9.png" alt="Facebook" style="border:none;"></a></td><td style="padding-right:5px"><a href="https://twitter.com/https://twitter.com/point_taken_" style="display: inline-block;"><img width="40" height="40" src="https://s1g.s3.amazonaws.com/83255843bbcec47d809669aff3b22691.png" alt="Twitter" style="border:none;"></a></td><td style="padding-right:5px"><a href="https://linkedin.com/company/https://www.linkedin.com/company/pointtaken-as" style="display: inline-block;"><img width="40" height="40" src="https://s1g.s3.amazonaws.com/85f05a94630abd611533bc2566751eb7.png" alt="LinkedIn (Company)" style="border:none;"></a></td><td style="padding-right:5px"><a href="https://youtube.com/https://www.youtube.com/channel/UC4rPzEDfHPp393oqOozUqaw" style="display: inline-block;"><img width="40" height="40" src="https://s1g.s3.amazonaws.com/a6f64a587978d338c0b8f6cc2d90bd0b.png" alt="YouTube" style="border:none;"></a></td><td style="padding-right:5px"><a href="https://instagram.com/https://www.instagram.com/pointtakenas/" style="display: inline-block;"><img width="40" height="40" src="https://s1g.s3.amazonaws.com/05f979c6025f3a336303ec824ebb815c.png" alt="Instagram" style="border:none;"></a></td></tr></table><a href="https://www.pointtaken.no" style="text-decoration:none;color:#3388cc;">www.pointtaken.no</a> </td> </tr> </table> 

Next you click on COPY HTML and open the Support Signature record (CUSTOM) on the user entity.

Just copy paste the HTML right inn to the text area. Save and Close

2. Javascript

Now you have to create a JavaScript file on the Email form. In the solution you can download in my last post you will find that I add a form to Email that you can use. I chose not to overwrite the default form.

var formContext = "";

function OnCrmPageLoad(executionContext) {
    formContext = executionContext.getFormContext();
    
    //
    //You don't need to change this. Just understand that forms have one the following states when opening
    //
    var FormTypes =
    {
        Undefined: 0,
        Create: 1,
        Update: 2,
        ReadOnly: 3,
        Disabled: 4,
        QuickCreate: 5,
        BulkEdit: 6
    }
    runAlways(formContext);

    switch (formContext.ui.getFormType()) {
        case FormTypes.Create: OnNewFormLoad(); break;
        case FormTypes.Update: OnUpdateFormLoad(); break;
        case FormTypes.ReadOnly: OnReadOnlyFormLoad(); break;
        case FormTypes.Disabled: OnDisabledFormLoad(); break;
        case FormTypes.QuickCreate: OnQuickCreateFormLoad(); break;
        case FormTypes.BulkEdit: OnBulkEditFormLoad(); break;
        case FormTypes.Undefined: alert("Error"); break;
    }
}

//
//I only use the RunAlways, OnNewFormLoad and OnUpdateFormLoad, but i keep the others here if i ever would need. 
//When looking at this you can always know what funtion is running. Easy to read and debug. 
//On my OnNewFOrmLoad I am now calling a function "GetDefaultQueueAndSignature"
//
function runAlways() { }
function OnNewFormLoad() {
    GetDefaultQueueAndSignature();
}
function OnUpdateFormLoad() {
    GetDefaultQueueAndSignature();
}
function OnReadOnlyFormLoad() { }
function OnDisabledFormLoad() { }
function OnQuickCreateFormLoad() { }
function OnBulkEditFormLoad() { }


//
//CUSTOM FUNCTIONS are added below here. Below this point you add all types of functions you need. 
//
function GetDefaultQueueAndSignature() {
    //Get User GUID and replace "{" and "}" with blanks. 
    var UserID = Xrm.Utility.getGlobalContext().userSettings.userId;
    UserID = UserID.replace("{", "");
    UserID = UserID.replace("}", "");

    //Get User Default Queue and Signature via WebApi
    Xrm.WebApi.online.retrieveRecord("systemuser", UserID, "?$select=_queueid_value&$expand=cs_Signature($select=cs_htmlsignature)").then(
        function success(result) {
            var Id = "{" + result["_queueid_value"] + "}";
            var Name = result["_queueid_value@OData.Community.Display.V1.FormattedValue"];
            var LogicalName = result["_queueid_value@Microsoft.Dynamics.CRM.lookuplogicalname"];
            if (result.hasOwnProperty("cs_Signature")) {
                var Signature = result["cs_Signature"]["cs_htmlsignature"];
            }
            if (LogicalName == null || Signature == null) {
                alert("User Record missing Queue and/or Signature");
                return;
            }

            //Set FROM lookup to queue
            formContext.getAttribute("from").setValue([{ id: Id, name: Name, entityType: LogicalName }]);
            //Set signature before current text in body
            var Body = formContext.getAttribute("description").getValue();
            if(Body != null){
                formContext.getAttribute("description").setValue("<br /><br />" + Signature + Body);
            }else{
                formContext.getAttribute("description").setValue("<br /><br />" + Signature);
            }
            
        },
        function (error) {
            Xrm.Utility.alertDialog(error.message);
        }
    );
}

Save and publish.

The Result is beautiful

We have now saved the service technician many clicks, and the signature looks great. Follow the next post to see how we manage the subject field to “master” the Smart Matching function.

Dynamics 365 Case Cascading Rules

This post is a part of a series of posts for Customer Service. The complete GUIDE can be found here

The OOTB cascading rules for Case are not optimal for the setup that I like to use. I will try to explain why, and at the same time show what I feel needs to be done for it to work better. Keyword is Parental Relationships that we have to STOP. If you wonder what I am talking about, below is the timeline from Case displaying activities.

What happens when you have parental relationship on, and you assign the case to another user, all of the related entities like Task, Emai, Phone Call etc will also be reassigned. Normally you you could ask why that would matter, but for CASE that is a real issue.

You also happen to change the “Modified On” data for the records leaving them potentially unsorted in a manner that will confuse the service agents. This applies to all activities, even the ones that have been closed as complete.

There are MANY other ways to sort activities, but Emails are almost always historical activities and happen at a given time. Tasks and Phone calls can be in the future. This is why I like modified on date, to keep a sort of chronological order. If possible the best sorting would be chronological order for completed activities, and due date sorted on top of that for open activities. Don’t think that is possible unfortunately.

Configuration

As you can see, the default behavior is Parental for Email, Phonecall and Task. I could have chosen more, but these are the entities I use the most in Case.

Do the following for all 3 relationships. Select Configurable Cascading and then Cascade None for the Assign. Microsoft DOCS cascading – If you wan to see more about Cascading Rules.

Why not NEW UI Config?

At the time of writing this blog, the configuration still isn’t possible for relationships. If you are familiar with configuring, the main point is just showing what I need to do for Dynamics.

Dynamics 365 – Email to Case

This post is a part of a series of posts for Customer Service. The complete GUIDE can be found here

The new name for this function is now called “Automatic Record Creation and Update Rules”. You find it under Service Management in the settings area.

Setup

I will try to explain why I believe this is the proper way to set it up, even though many of you probably will have a different preference.

Queue:
Choose the queue that we created in the previous post

Create Cases for activities associated with a resolved case:
The purpose of this field is to create a new Case when you receive an email on an old existing case.

I believe this setting together with 1 minute is the correct setting. Many will argue that I m wrong, but there is a reason why. Dynamics doesn’t have an automatic case reopen when an email is received on a closed case (A mystery why they haven’t done anything about it yet). Without this feature the email would just land on the closed case and never bee seen. With this setup a new case will be created once you receive an email for a case that is closed.

Certain support metrics work against their purpose. Just think about the good old
“Number of cases closed in a day”
“Time Case was open before closed”

In the end, the customer wants to be treated well, and feel confident that the organizations can help with the issue. I try to educate that the case close confirmation should be done for every case.

With the current setting, emails will create Cases that Customer Service will be able to follow up. Sure you might get more cases, but you won’t loose any. A case not answered might be a customer lost!

Email Template:
The template provided here is a nice start. Do what you need for changes. Notice that the case number here is included in the subject, and this is something we want to use later on also! Stay tuned for later post:)

Creating the record

Once you choose CASE as entity to create, the system will provide with default values that are fine.

Email Router Tracking – Smart Matching vs Tracking Token

This post is a part of a series of posts for Customer Service. The complete GUIDE can be found here

I am sure there are equally many opinions about the best practice here as there are for the Managed vs UnManaged discussion for solutions in Dynamics. I have my preference, and I hope it all makes sense when I am done with my blog series about Customer Service:)

Why I hate Tracking Token

Why someone at Microsoft thought this was a smart number to add to an email is beyond anything i can understand. Every support system I have tried uses this type of functionality in emails, but the number is always the same as the case number. Microsoft managed to choose this logic🤢

Struktur for sporingstoken

While this gives the system a fairly unique number to work with, the number itself is completely useless for reference. If a customer calls inn regarding this case number you will not get many hits in the Case search. This number is not even unique pr case. It will change based on who is answering the Case, just to confuse the users even more.

This number should be the case number, and that is what I will fix in a later post.

Why I hate Smart Matching

So Smart Matching is supposed enables us to not use Tracking Token…. Or does it? Smart Matching tries to understand the subject, to/from etc etc to figure out where to track this email. Does this process fail? You bet your sweet ass it does:) If you have a customer sending a new email with the same subject but for 2 completely different matters, it might connect it to the wrong record.

Is there a better solution?

Some prefer to combine the two options. I still don’t want the tracking token, so I have a slightly different approach. I will show you in a later post in the series, where I discuss how I handle the email subject.

Settings

Back to the actual post.

Lets open the System Settings to see what I choose. You can also go via https://admin.powerplatform.microsoft.com to navigate via new setup, but for some reason Microsoft doesn’t auto fill out the numbers below. I still do this old school.

Filter: ^[\s]([\w]+\s?:[\s])+
Max number of subject: 20
Min diff: 0
Min Number: 2

Other Bloggers

You can head on over to CRM Ninja and Neil Parkhurst to see their opinions about the matter. Neil explains what is possible, and CRM Ninja talks about a certain case he had. https://neilparkhurst.com/2016/11/19/mb2-710-track-and-correlate-email/
https://dynamicsninja.blog/2019/04/18/when-smart-matching-became-dumb-matching/

Dynamics 365 QUEUE setup with shared mailbox

This post is a part of a series of posts for Customer Service. The complete GUIDE can be found here
I assume you have a Dynamics Environment at this point.

Exchange

Open https://admin.microsoft.com – login with the credentials you got from the trial, or make sure you are a Global Admin to complete the following tasks.

You now have a shared mailbox in Exchange. We will be using this email address to configure a queue in Dynamics Customer Service.

Dynamics 365 – Queue

If you don’t remember the address to your dynamics environment, you can always find your environments at https://admin.powerplatform.microsoft.com <- click … and then open.

Locate the queue setup from Dynamics Customer Service Hub. This is where we create a new queue for Support@. For the owner we choose Customer Service Team.

Click Save, and the system will automatically give you a new mailbox.

To configure the mailbox, we need to navigate to Advanced Settings.

Email Configure

Open Mailboxes and find Support@ that we created.

Your picture should look something like below. Following order
1. Approve Email – You must be global admin to do so.
2. Test & Enable Mailbox
3. Follow progress in Alerts

If you have done it right, you should see the following. This process can be tricky, and there are lots of great guides out there that might cover this better. Connecting Exchange with Dynamics it typically really easy, or really hard.

Lets se if it works

So after waiting for a few minutes, I now see the email in the queue 🙂

Dynamics Customer Service Autonumber

This post is a part of a series of posts for Customer Service. The complete GUIDE can be found here

Why on earth did anyone think that this was a reasonable number to include in Customer Service cases?

This number is way to hard to relate to, and too hard to explain why came to be. It has absolutely nothing to do with the Email Tracking Token, leaving the customer utterly confused when talking about numbers.

Might be a little hard to see here, but I open my solution from https://make.powerapps.com and select the case entity. In the Case entity I have the default Case Number field. When choosing to edit this field I simplify the autonumber. This will make even more sense later on.

A larger image

All of this will be included in my Customer Service Solution later on in the guide.

Dynamics 365 Customer Service Team

This post is a part of a series of posts for Customer Service. The complete GUIDE can be found here

I prefer to define a team with a security role when i create Customer Service solutions. The idea is that the incoming case is assigned to the Customer Service team. This way it is clear to see what cases are new and not yet assigned.

NB! Reassigning Cases to a new user Out Of The Box is not great. The cascading rules changes the sorting of emails because of modified on dates. I will therefore include a post on how to modify the cascading rules.

Security Role

Open Dynamics in any app and find the Advanced Settings

This will open up the good old Dynamics Setup. This is where we can access the security model.

We need to create a security role for the team.

These are the entities that I needed to make my scenario work. It is a very minimal role, but I won’t be needing more than this for Customer Service Team.

Team

Open teams and create a new team. I will call mine Customer Service. Make sure you assign the security role to the newly created team.