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.

Friday, September 29, 2017

Why use Azure to extend Dynamics 365?

What are some good use cases for building logic for your Dynamics 365 using Azure?

1. Inconsistent workload demands
Have you started using the Dynamics 365 portal? It is pretty cool, but if you have waves of people hitting the web site and making updates, and you have numerous plugins and workflows running, you may find that your system can be sluggish if not outright slow. By moving some of your plugins and workflows to an Azure service, you can mitigate some of the effects of the portal. Consider using Azure Functions.

2. Offloading batch processes
Are you an association that needs to update 100k membership records at the same time, or generate 20k invoices on the last day of the month? You shouldn't even try to do that with workflows or your users coming after you with torches and pitchforks. Just like #1 above, you could have an on-demand service running in Azure to do the dirty work without seriously impacting your users. Consider using a Cloud Service that you can deploy, run, then shut down.

3. Scheduled jobs are not easily managed within D365
You want a system update to run at 5PM every Friday? I dont think you can do it in D365 without writing some plugin code and a workflow, but Azure has an OOTB solution for that. Take a look at Azure Logic Apps. You can schedule them to run at a specific time.

4. You are moving to D365 from an on-premises environment that uses SQL Stored Procedures
You have some SQL queries and views you use to support reporting systems. CRM has a feature to replicate an entire entity to an Azure SQL database. You want to push updates back? That is a bit more tricky, but perhaps you can manage it with Azure Logic Apps or Azure Functions.

5. Plugins and workflows in D365 have a timeout limit of 2 minutes
Yep, trying to update more than a few records in a single plugin is detrimental to your employment. In one case, I found that a client had created a bunch of small plugins, but what the developer(s) didn't realize is that they had created a chain of plugins that was over 1500 lines of code and periodically failed from time to time, depending on the current server load. The worst part was that there was no way to re-trigger the plugins because they were designed to work only with a Create event message, and the code did not support idempotent transactions, so you could only run it once and hope it worked the first time. Consider using an Azure Cloud Service, Web Job, Service Fabric, or Function, depending on what you are trying to accomplish.

(update)
6. Consolidate Business Logic 
Perhaps you have several places in your system that do the same thing, like processing a credit card. If you put the logic in a plugin, it is not easily accessible to your web site (yes you can do it, but it is not a good user experience). You could use a WebJob that works with both CRM and your web site.