Sunday, December 2, 2018

Customizing D365 forms using JavaScript

I know, a lot of people have written about customizing CRM forms with JavaScript, but I am learning some cool stuff and wanted to share what I learned this week.
The big news for me was that Promises are supported in D365 forms now. I am sure this is not news to many people, and to others they have no idea what I am talking about, so this article is for them.
Why are Promises important?
If you have written a JavaScript function that uses a “call back” (passing a function name as a parameter into another function), then you have probably run into the fact that the call back can happen at any time. If you have several of them that need to be run in a sequence, they will sometimes cause your code to fail because it does not execute them synchronously.
I have seen many programmers try to solve this problem by building “Christmas tree” code that nests one function inside the other until you are 15 levels deep in brackets, and lord help you if you if there is a syntax error with one bracket out of place. Even worse is the difficulty to test and maintain all permutations of “Christmas tree” code so that you are sure there are no errors. Promises are an excellent solution to that problem.
A Promise design pattern is way to write a function that will leverage the asynchronous nature of JavaScript with the ability to sequentially perform a series of tasks. 
I learned about Promises from a Pluralsight course authored by Jonathan Mills called JavaScript Best Practices. I did some research and found a few code samples in GitHub for CRM projects that used Promises. Here are some links that I used to learn more, but frankly, some of it was deeper than I needed.
Promises
https://blogs.msdn.microsoft.com/ie/2011/09/11/asynchronous-programming-in-javascript-with-promises/
Promise API framework for CRM
https://code.msdn.microsoft.com/CRM-Web-API-Functions-and-87cd0b45#content
It uses https://github.com/stefanpenner/es6-promise
https://github.com/mariusso/WebAPI.REST.js/releases




Some of the above links say that you need to include the e6promise.js library, and that may have been necessary in earlier versions of CRM, but I am working in V9.1 and it is not necessary to add any other framework to your project, but it did help me understand what is going on.
What got me started on this article was when I needed to build a customization and realized that I needed several sequential calls to fetch data first, then create new records, but they had to be executed in order.
I noticed that Jason Lattimer’s CRM REST Builder used a Promise syntax when I used the Xrm.WebApi option to build a request for fetching data, so I decided to see if I could make that work for me. Besides, I like the succinct format of WebAPI over the XMLHTTP format.
I created a form script called Library.js and in following best practices, created a FormLib namespace so all my methods and properties are prefixed with “FormLib.”.
First I used CRM REST Builder to create an asynchronous call to get some data for me that looks like this:
Xrm.WebApi.online.retrieveMultipleRecords("tn_changeorder", "?$select=tn_changeorderid&$filter=statuscode eq 0 and  _tn_quoteid_value eq <giud>").then(
     function success(results) {
         for (var i = 0; i < results.entities.length; i++) {
             var tn_changeorderid = results.entities[i]["tn_changeorderid"];
         }
     },
     function(error) {
         Xrm.Utility.alertDialog(error.message);
     }
);
Notice the “then” that follows the async call – this was my clue that the Xrm.WebApi was a Promise.
Following Jonathan Mills instructions, I created a wrapper function :
FormLib.GetChangeOrder = function () {
     return new Promise(function (fulfill, reject) {
         // begin REST code

        // end REST code
     });
};
and then I inserted the “fulfill” and “reject” into the REST code, and put it all together so that now my code looks like this:
FormLib.GetChangeOrder = function () {
     return new Promise(function (fulfill, reject) {
         // begin REST code
         Xrm.WebApi.online.retrieveMultipleRecords("tn_changeorder", "?$select=tn_changeorderid&$filter=statuscode eq 0 and  _tn_quoteid_value eq  <guid>" ).then(
             function success(results) {
                 for (var i = 0; i < results.entities.length; i++) {
                     var tn_changeorderid = results.entities[i]["tn_changeorderid"];
                 }
                fulfill();
             },
             function (error) {
                 Xrm.Utility.alertDialog(error.message);
                 reject();
             }
         );
         // end REST code
     });
};

Now every time I make an async call, I create one of these functions (above) and can fire them sequentially using a syntax that looks like this:
FormLib.GetChangeOrder()
            .then(FormLib.CreateRelatedCase)
            .then(FormLib.SetupDetails)
The magic is the fulfill() that calls the next item in the “then-chain”. The reject() allows you to call an error handler and gracefully exit the chain. In my example above, the “.then(FormLib.CreateRelatedCase)” is passed into GetChangeOrder() and executed after it has completed its task of looking for an existing record.
You could argue that it is easier to just call the next function in the chain by using the specific function name instead of calling fulfill(), but then you would have tight coupling and it is difficult to maintain when you have to decipher the code to figure out what the chain is.
Promises solves the problem of deep nesting of functions by splitting them all out to discrete, re-useable, loosely coupled, and testable functions that can be called sequentially. The Promise Design Pattern also makes handling errors and parallel tasks easier to manage. I recommend you learn this design pattern if you are going to do any amount of JavaScript coding.

Sunday, November 25, 2018

Capture pictures to Dynamics Customer Engagement (CRM)

This week, I got side-tracked on figuring out how to take pictures from a PowerApps Canvas app and put them into a CRM “model driven” app (The most frustrating part is getting around the terminology).

I started with a Canvas app I was creating to let people in the field work with cases. On the edit form, I wanted to let a user capture a picture and store it with the case for future reference. The Canvas app is fairly straight forward; you select a contact from a gallery, then either open an existing case from a gallery or create case, and then the user will be on an Edit form. I was able to kick-start my development by generating an app from data. I am not going to recount all those steps as there are a bunch of good videos on that already. What I found lacking in the community was a discussion about how to connect pictures with CRM, so I will provide the steps needed here.

Normally on a Canvas app, all the data you want to save in CRM is in the Edit Form, but that will not work for pictures. In order to get pictures to be captured and put into CRM, you need to use Flow. If you have not used Flow before, this is as good a time as any to start because eventually you will need it. And before we can modify our Canvas app, we need to have the Flow created first.

1. First create a Flow with a PowerApps trigger. There is nothing to configure at this step. Behind the scenes, this trigger action will manage all the parameters needed to make our connection with the Canvas app work.

2. Add a Compose Data Operation action, click on the “…” to rename it to “convert picture” (note that this is in lower case).

2018-11-25_1753_001

3. Click in the Inputs field, and in the Expression, paste this:

        base64(decodeDataUri(triggerBody()['convertpicture_Inputs']))

2018-11-25_1758

This line of code will take your picture and convert it to a format the is acceptable to CRM. This code is case sensitive and depends on the name you provided in step 2 above.

4. Add an action to create a new record in CRM. Here are the values I provided for this example:

2018-11-25_1800

You will be prompted to select the instance of CRM you want to connect the Flow with, then you must choose Notes as the Entity because that is how CRM stores all pictures as attachments on notes. For purpose of this example, I have included only a couple fields as parameters – the Document is where the picture is located, and the Regarding is the ID of the case record you are relating it to (it is called “incidents” in the Regarding Type field).

5. For the Regarding field, you will need to click into that field, then click on the PowerApps / See More / Ask in PowerApps and it will create a new field called “Createanewrecor_Regarding” and insert it into that field. 2018-11-25_1813

6. Save the flow. Mine was automatically named as “Create a new record”

7. In my Canvas app, I inserted a Camera control:

2018-11-25_1823

8. Select the new control and place it on the form where you want it to appear.

9. In the OnSelect property of the camera, I connected it with the flow using this one line of code (note the semi-colon separating two function calls in this one step).

ClearCollect(photo,Camera1.Photo); 'PowerApp->Createanewrecord'.Run(First(photo).Url , BrowseGallery1.Selected.Case)

2018-11-25_1826

Now when the user taps (or clicks) on the image in the app, it will add the picture to a collection called ‘photo’ and then call the new Flow with the photo as the first parameter, and the ID of the case as the 2nd parameter.

Note:

  • ClearCollect(photo,Camera1.Photo) is necessary to temporarily store the photo so that it can be passed as a parameter to the Flow. The ClearCollect() function wipes out anything that was in the collection variable and puts in new values.  A collection is a variable that can have many values contained in it.
  • The reason we used “First(photo).Url” is because the picture was in a collection, the First() function just pulls out the first one (even though there was only one picture).
  • The Case [Global Unique] ID was accessible through a gallery I had in my app. This would only work if the case is already existing. If this was a new case, it would require some additional work to first create the case, then get the ID before you are able to save a picture.

If your flow was called a different name, then use the Action menu in the canvas app editor to select your flow, and it will prompt you for the order of the parameters it is expecting. 2018-11-25_1831

Testing!

Now when I run my canvas app, and click on the picture, it (should) run my Flow to create a new record in CRM. Flow can be a bit finnicky, so you may find that it does not always work the first time. My first few times failed because I didn’t have the code correct at step 3. Here is how I debugged it:

While you are in Edit mode in the Flow, click on the Test icon:

2018-11-25_1850

Then choose your most recent run and click Save & Test

2018-11-25_1852

There will be a red X next to the step that failed, and you can click on a link to see the inputs and outputs to see what went wrong. Once you have the flow working, you should be able to open the case in CRM and see the picture in the Notes area:

2018-11-25_1857

Let me know if you have questions and I will try to help!

Good luck!

Friday, November 16, 2018

PowerApps survival tips for CRM: Option sets & Drop Downs

I have been playing with PowerApps (technically a Canvas app) on and off for about a year and the parts are finally coming together for this to be a viable product to integrate into my CRM solutions. One of the stumbling blocks I have been frustrated with are CRM Option Sets because it was not easy to implement in a Canvas App as a Drop Down or Combo box control. MS has released an update that takes care of that for you now.

If you have tried to add an Option Set to a form in a Canvas app, and you have noticed that you only get its value displayed as a number, then you have not seen the latest updates. Now you can easily put option sets on forms without all the hassle of creating collections of values.

Displaying the option set text value in a Gallery

Good news here – our friends at MS have included option set labels as fields in queries so that you can include them in the gallery. For example, I wanted to show the case type in a gallery, so now I can simply choose the “_casetype_label” field and it is translated into “ThisItem.'Case Type Label' ” so there is no need to do any fancy translation just to display the current field value.

image

Add a Drop Down control to a form

When you select fields, choose the Case Type Label

image

and the option set will be populated with the appropriate values:

image

When you change the value on the form and save it, the correct value is updated in CRM.

Wednesday, July 11, 2018

How To set up your fiscal year in Dynamics 365

Why you would do this:
For clients that have a fiscal year that starts on January 1st, the system default is already set and you don't need to do anything else at this point. However, some of my clients have a fiscal year that starts on a different month, and this article is for them. Setting up the fiscal year allows you to use features in your views and sales goals based on the fiscal year, for example
image
To set your fiscal year: You need to have System Administrator rights to access this feature. If you do, then navigate to Settings/Business Management/Fiscal Year Settings
clip_image002
Then update the start date to 9/1/18 or what ever the first day is of your last fiscal year (the year is not important in this date field, only the Month/Day)
clip_image004





Wednesday, June 27, 2018

Too much whitespace on Dynamics 365 v9 forms–workaround!

I was frustrated with the amount of whitespace on the new v9 D365 CE forms so I started doing some research. Using the Chrome browsers DevTools (press F12), I was able to identify the style I wanted to modify:

TABLE.ms-crm-FormSection td

This style adds 10px of padding to the top and bottom of all form elements.

I found a nice bit of JavaScript code that uses appendChild() to insert a modified style into the Head of the document. It seemed to work…for about a day, then the form seemed to go back to the previous rendering. Having some (not much) experience with styles, I know that that styles can be affected by many things, including the order they are loaded, and I have no patience for diving in any deeper. Instead I found a nice workaround: stylebot. This is an extension to Chrome that allows me to define my own styles for any given domain. After adding the extension, navigate to CRM (or refresh your page if you are already there), then click on the “css” icon in the top-right corner and choose Open Stylebot to get here:

2018-06-27_1146

in the field that says  “Select an Element” type in

TABLE.ms-crm-FormSection td

The domain name should appear directly under it. Click the Advanced button, and enter the style code:

padding-top: 0px;
padding-bottom: 0px;

then click the “x” to close stylebot and refresh your page. Now the whitespace is gone! Hope this makes you day a bit better.

Wednesday, February 14, 2018

OData Queries in Azure Logic Apps

I am building some Azure Logic Apps and came across a problem where I wanted to get a List of records from Dynamics 365 Customer Engagement (CRM) and update some data in SharePoint. In order to get the records I wanted from CRM, I needed to use an OData filter expression. I was not sure what it should look like so I turned to the XRMToolbox FetchXML Builder which generates OData expressions like this

https://xxxxxx.api.crm.dynamics.com/XRMServices/2011/OrganizationData.svc/AnnotationSet?$top=50&$filter=ObjectId/Id eq (guid'9a19c4eb-bc3b-45e1-adc8-c5cf1716101b')

I could see the filter used an unusual notation of “ObjectId/Id eq (guid'9a19c4eb-bc3b-45e1-adc8-c5cf1716101b')” and if I executed that REST call then I could get a response from CRM. But when I use the filter expression in the Logic App, I would get this error message.

“Could not find a property named ‘ObjectID’…”

clip_image002

So I created a stand-alone Logic App that had a single List Records from CRM (oops, Dynamics CE) to see what it returns:

image

I noted that GUID field names were converted to using an underscore in front of the field name, and “_value” after the field name, and that the field name was all lower case. This told me that under the covers, OData is dealing with EntityReference fields by converting the GUID to a string value. So I changed the Filter to use the adjusted field name together with “eq” and the unique identifier from a prior query like this:

clip_image002[4]

which now returns exactly the list I needed.

Wednesday, October 4, 2017

Find other accounts near an address

I have a customer in NYC that we are helping to implement Field Service using Dynamics 365 (online). One of their hot issues is making it easy for them to find all other accounts near a given location, so I started thinking about the problem.

One of the features built into that solution is geocoding, so that all account addresses get a geocode. If I could use SQL queries, I would be able to use a native SQL query to find all addresses near a given point. As far as I know, the FetchXML syntax does not do those kinds of queries.

To narrow down the problem space a bit, my client only works in the NYC area which makes things a bit easier because we can simplify the variables: We don't need to worry about the curvature of the Earth over long distances, or the distance between longitudes for a given latitude. I am going to simplify this a bit more. If I ignore the fact that a radius around a point is the best representation of what is nearby, and I use a rectangle which is good enough for my clients purposes, then the query is super simple because now I just need compare the current Lat/Long with ones that are between "+" or "-" a difference in order to define the rectangle.

Lets say, from a given Lat/Long, we need to know who is inside a vicinity of  1 square mile. That means we are interested in all locations that are roughly 1/2 mile North, 1/2 mile South, 1/2 mile East and 1/2 Mile West from the current point.

Each degree of latitude is 69.99 miles apart.
At 40 degrees latitude (NYC), the longitudes are 53.08 miles apart.

Therefore, 1 mile is about (keep it simple):
1/69=0.0145 degrees of latitude
1/53=0.0189 degrees of longitude

So if we search for all addresses that are within one square mile, then we are looking for a Lat/Long that fall within the range of the
current location +/- half the 1 mile area.

So if we are at this location: 40.61938 Lat, -73.91799 Long, then we are looking for all addresses where the latitude is:

40.61938-(.0145/2)=40.61213 and 40.61938+(.0145/2)=40.62663 (up to 1/2 mile South and 1/2 mile North of us)

And the longitude is:
-73.91799-(.0189/2)=-73.90854 and -73.91799+(.0189/2)=-73.92744 (up to 1/2 mile East and 1/2 mil e West of us)

and in Advanced Find, would look like this:


Remember, because NYC is in the western hemisphere, the longitude is negative.

Ultimately my goal is to take this kind of query, build it into a JavaScript on a form and populate a map with the points. But that is a blog for another day.