Tip #1212: Where are my apps?

I attended your webinar about model driven apps.
Our sandbox has been upgraded to V 9.1 and our production environment will be upgraded tomorrow.  In preparation for this, I have created and published an app .  I have added the appropriate security roles to the app, but it is still not showing up for selection for them on their mobile app. It says “we can’t find any apps for your role. To check for recently added apps, select refresh.”

Laura M

When Microsoft releases new versions of Dynamics 365, sometimes they introduce new security role permissions. If you are using custom security roles created prior to version 8.2, they likely do not have the required permission to see model driven apps.

Update the users’ security roles, ensuring that they have read privilege for model driven apps on the security role Customization tab. 

(Cover photo by Daniel Jensen on Unsplash)

Tip #1211: Mixing entities to build complex views

The trick to get developers to get your job done for free is to challenge them. Which is exactly what Steve “Mr SMB” Mordue has done.

Challenge

I am trying to create a view of activities, that will show all activities performed by anyone on my team. I know I can create specific view that filters that way, but I don’t want to create one for each of the 9 teams. I want to recognize the team I am on and show it.

Accepted

A bunch of linked entities later, Andrii “Granny’s Moonshine” Butenko had a solution:

image

And that would have been the end of it but then the discussion went something like this:

– I need me, my team, and all members of that team

– So records can belong to Team as well?

– Yes

– Aah, crap

So the challenge now was to combine the expression above with the condition “Owner Equals Current User’s Team” using OR operator. Except that visual view builder would have none of it. At some point Jonas “FXB” Rapp was summoned and solved the problem between brushing his incisors and molars. Readers digest:

  1. Build a view with the columns that you need and the condition above.
  2. Fire up XrmToolBox, load that view into View Designer then start editing query in FetchXML Builder.
  3. Mix conditions on attributes from different entities in the builder.
  4. Test your fetchxml then update your view.
  5. Done! (Note: the view will work but you won’t be able to edit that view in Advanced Find).

Winning FetchXML:

<fetch mapping="logical" output-format="xml-platform" 
        version="1.0" distinct="true" >
  <entity name="activitypointer" >
    <attribute name="activitytypecode" />
    <attribute name="subject" />
    <attribute name="statecode" />
    <attribute name="prioritycode" />
    <attribute name="modifiedon" />
    <attribute name="activityid" />
    <attribute name="instancetypecode" />
    <attribute name="community" />
    <attribute name="ownerid" />
    <attribute name="owneridname" />
    <filter type="or" >
      <condition attribute="ownerid" 
                 operator="eq-useroruserteams" />
      <condition attribute="systemuserid" 
                 entityname="tm" 
                 operator="eq-useroruserteams" />
    </filter>
    <link-entity name="systemuser" to="owninguser" 
              from="systemuserid" link-type="outer" >
      <link-entity name="teammembership" 
                 to="systemuserid" from="systemuserid" 
                 link-type="outer" >
        <link-entity name="team" 
                   to="teamid" from="teamid" 
                   link-type="outer" >
          <link-entity name="teammembership" 
                       to="teamid" from="teamid" 
                       alias="tm" link-type="outer" />
        </link-entity>
      </link-entity>
    </link-entity>
  </entity>
</fetch>

I was dead last in this contest – my own version wouldn’t even work. As it turns out, link-type="outer" is important, don’t leave home without it.

(Cover photo by Bernard Tuck on Unsplash)

Tip #1210: Getting to settings from unified interface

One objection to switching to the unified interface is that some users need to access functionality in the settings area (create workflows, manage users, system settings) and we want to have a consistent user experience for all users.

With recent updates to the unified interface, you can now easily get to the settings area from any unified interface model-driven app.

In the upper right, click the options gear and select “advanced settings”

This will take you to the settings area of Dynamics in the classic UI in a separate browser tab. Note this is only the settings area.

With this hybrid approach, all users can leverage the unified interface while still making it easy for administrators to administer and configure the system, and removing yet another reason not to use the unified interface.

(Cover photo by rawpixel on Unsplash)

Tip #1209: Embedding canvas apps in model-driven forms

For those of us who were continuosly torn between canvas apps (on yer device, pixel-perfect, task-oriented) and model-driven apps (a.k.a. good ol’ forms, views, you know, all that Dynamics 365/CRM stuff), the wait is finally over. Embedding canvas apps in model-driven forms is now available as Public preview. First, the official part.

Makers can now extend the power of WYSIWYG, low-code customization, offered by canvas apps, to model-driven forms. Using embedded canvas apps makers can easily design and create rich visual areas on model-driven forms. They can also connect and display data from over 200+ data sources in embedded canvas apps right next to data from the Common Data Service. The embedded canvas apps also provide rich data integration capabilities to bring in contextual data from the host model-driven form to the embedded canvas app unlocking a variety of scenarios.

The feature is now available in initial regions (Canada, India, Japan and South America). You can create an environment in one of these regions if you want to try the feature right away. The feature will roll out to other regions over the next few weeks and will reach North America and Europe by early January 2019 due to extended holiday deployments chedules.

A huge thanks to you for your valuable time and feedback when the feature was being designed and developed. Please help Microsoft increase the awareness of this feature by blogging, tweeting, talking, shouting out from rooftops 😊.

Links to some resources

Unofficial blurb

It’s great to witness this feature finally seeing the light of the day. The number one ask on my list is bidirectional communications. While it is possible to pass the context to the canvas app to do its thing like visualizations, it’s not yet possible to communicate back to the form even in the simplest form like “hey, I’m done, these are the changed pieces, refresh yourself”. Adding that would make me to revisit all implementations that use HTML web resources.

On a plus side, the release is a huge milestone, congratulations to the team. At very least the feature is there, even in a bit rough form, even with some inconsistencies and probably bugs. But it’s there. Which is more than we can say about, for example, PowerApps Control Framework (where’s “disappointed” emoji when you need one?) 

(Cover photo by Jessica Ruscello on Unsplash)

Tip #1208: More entities now work from Unified Interface

Until recently the list of entities that didn’t work on unified interface included goals, connections, campaigns, and marketing lists. With recent updates, these entities can now be accessed from unified interface model driven apps.

This is great news if you use one of these entities–I’m especially excited about marketing lists, as there are many great alternate uses for lists.

With this update, unified interface and classic UI are now almost at full parity, so there should be no practical limitation holding you back from making the switch.

Tip #1207: Check applied entity permissions in portals

Liquid is a great templating language adding flexibility to your Dynamics 365 Portal templates. However, as any abstraction, it hides some of the things happening under the hood, including some security filtering. Consider this fragment running on authenticated page:

{% fetchxml my_contacts %}
<fetch mapping="logical" version="1.0" 
       returntotalrecordcount="true">
  <entity name="contact">
    <attribute name="firstname"></attribute>
    <attribute name="lastname"></attribute>
    <attribute name="contactid"></attribute>
    <order descending="false" attribute="lastname">
    </order>
  </entity>
</fetch>
{% endfetchxml %}

<h2>Record count: 
  {{ my_contacts.results.total_record_count }}
</h2>

And… the count is 2 while expected to be the total number of contacts in this sample environment (around 20 or so) . Er?

This is because the portal engine applies entity permissions to all constructs retrieving the data including fetchxml. To see where did the things go wrong (or right – depending whether it’s your point of view or of your system administrator), use xml property of the fetchxml object. That will tell you what’s actually being executed.

<div style="white-space: pre-wrap;">
  <code>
    {{ my_contacts.xml | escape }}
  </code>
</div>

In my case resulting fetchxml looks like this

<fetch mapping="logical" version="1.0" 
  distinct="true" returntotalrecordcount="true">
  <entity name="contact">
    <attribute name="firstname" />
    <attribute name="lastname" />
    <attribute name="contactid" />
    <order attribute="lastname" descending="false" />
    <filter type="and">
      <filter type="or" hint="union">
        <condition attribute="parentcustomerid" 
        operator="eq" 
        value="deadbeef-38c9-e711-a844-000d3ad1181d" />
        <condition attribute="contactid" 
        operator="eq" 
        value="deadbeef-38c9-e711-a844-000d3ad1181d" />
      </filter>
    </filter>
  </entity>
</fetch>

highlighted lines (injected by the portal engine) explain why I’m seeing only two records (my portal is based on Customer Service):

  • deadbeef-38c9-e711-a844-000d3ad1181d is my contact id (after I logged in)
  • condition on contactid is a result of the “self” OOB Customer Service – Contact of the User entity permission that gives portal users permissions to access their own profile
  • condition on parentcustomerid is a result of the OOB Customer Service – Contact of the Contact entity permission giving portal users access to the contacts where they are the parent customer

Tip #1206: View any Dynamics 365 record on a calendar

I want to see a calendar of my opportunities based on estimated close date (or other date field on the opportunity record). Can I do that, or do I need to license a third party add-on?

Sales Manager

If you use unified interface, you can display any record in a calendar view via the calendar control.

  1. Go to Settings->Customization->Customize the System
  2. Open the configuration for the entity that you want to use the calendar control (Opportunities in our example)
  3. Click the View tab
  4. Click “Add Control” and select the calendar control.
  5. Click the dot for every interface from which you want the calendar control to be available.

You will then need to map the calendar fields to the desired values. For example, if you want the date to be based on estimated close date, you would select estimatedclosedate for the Start date.

The view for opportunities in unified interface will now show a calendar based on the selected view.

How do I switch to the normal list view?

To switch back to the list of records, click the “…” button on the command bar, and select read only or editable grid (if enabled) to toggle to the normal list view.

I have multiple date fields that I would like to display on the calendar–can I do that?

The calendar control properties allow you to specify two different date fields–start date and end date. If you have two dates that are sequentially related, such as schedule date and installation date, you can map both of these values, and that will determine the time block duration of the item on the calendar view. If you have multiple unrelated dates or want to have different views displaying different dates, the calendar control is not designed to work that way.

Tip #1205: Local time in Flow using Common Data Service

Remember the times when you wake up and struggle to figure out where you are or what time it is? Of course, you don’t. I personally can’t recall those because lack of space and time awareness goes hand in hand with the selective amnesia. We did create a flow to help you on those occasions.

That flow worked using trigger tokens (and Bing Maps API) that work when you actually push the button on a mobile device. Sometimes you don’t have a button to push, or time is unrelated to the flow itself. I am talking about datetime fields in Common Data Service, of course. Those are UTC as well so how do we convert the values into the realm of a user? It could be the user who pushed another button, or user who invoked a flow from their model-driven app, or simply the user who created the record in the first place.

Why does it matter, apart from the reasons we described in tip #1141? Imagine sitting on a beach in Hawaii, doing the numbers and, bingo!, you close that elusive sale in the evening on September 30, just in time to make your quota for the quarter. Except that you didn’t because it was already October 1 in the UTC timezone so here goes your quarterly bonus.

Since we don’t have the user location, we’d have to use user options that actually exist precisely for the purpose of localizing datetime values:

image

Getting from a user to the timezone in the format we need is not a one-step operation so these are the steps: (and remember I promised to cut down on the screenshots so here we are):

  1. Manually trigger a flow. Self-explanatory. Could be When Record is Selected CDS trigger, could be something else.
  2. Get my profile action. Gets O365 profile of the current user running the Instant Flow (i.e. triggered manually).
  3. List Records action on Users (systemuser) entity to get the list of user records for the current user (i.e. list of exactly 1 record). We could filter records by email provided by the manual trigger but that will fail miserably for B2B guest users.
  4. Initialize variable action to declare ExecutingSystemUserID variable and set it to the current system user id. Keep your flow tidy.
    Note: step 2-4 are courtesy of my bad masterclass crony, David “Xrm.Tools” Yack. They apply to Instant Flows when you have the executing user. For automatic flows you would use createdby or ownerid , or some other field containing the target user id.
  5. List Records action on User Settings (usersettings) entity to get user settings include mysterious timezonecode.
  6. List Records action on TimeZone Definitions (timezonedefinition) entity to get the name of the timezone.
  7. Initialize variable action to declare User Timezone variable. Again, keep your flow tidy. Now we are ready!
  8. List Records on account entity. Completely optional action extracting first active account owned by the user just to demonstrate the technique.
  9. Convert date time action to get the local value for createdon.

Result:

image

Since we have limited number of pictures, you can download, import, and dissect the flow in your own environment. You’ll need to provide your own Office 365 Users and Common Data Service connections.

(Cover photo by Heather Zabriskie on Unsplash)

Tip #1204: Export marketing lists with more information

Is there a way to export a marketing list and include email addresses and other information? When I export a marketing list, I just get the lead or contact’s name.

Reader

Yes — you can get email address, phone number, address, and any other information from the contacts or leads who are members of the list. This is a common request when people want to build a list in Dynamics and then do something with it — mail merge in Microsoft Office, or export to a third party non integrated marketing platform like Constant Contact or Mail Chimp.

If you want to include details from contacts or leads associated with a marketing list, you need to do it from the contact or lead level. Do an advanced find for contacts and filter by the related marketing list entity. You can then include any field you want from the contact or lead, including fields from parental relationships like parent customer.

In this example we are filtering contacts by the related marketing list called “contact list.” This search returns all members of the marketing list.

Tip #1203: When and where you pushed that button

There is a time in life of every developer when they have to clench their fists and… start learning Flow. Today’s topic – localized date time.

Flows run on a… in a …. wherever Flows run. Time is UTC in that world. So how does one bring the concept of a time, local to the user, into that world?

Let’s start with a simple case of a manual flow, a.k.a. push a button on your mobile device. Here’s the challenge – whatever button passes to the flow, including a timestamp, is in UTC. Challenge accepted.

  1. Read about trigger tokens, all device goodness is there but, as I said, timestamp is UTC.
  2. Latitude and longitude are also among trigger tokens and available when you run a button flow
    image
    Note: if you are using these values, your phone mobile device must have location services enabled otherwise:
    image
    Ok, now that we have latitude and longitude, we need to convert them into the time zone information.
  3. In your Azure account, add Bing Maps API for Enterprise (don’t worry, it’s free up to 10,000 transactions per month). Don’t have Azure account and really don’t want one? You can still use https://www.bingmapsportal.com/ for a time being to register an account and get yourself an API key. Check the usage rights because copyright message is very explicit:

    This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.

  4. The API we are after is Find Time Zone and the call looks like this:
    image
  5. Use Postman to get a sample response and then use Parse JSON action to extract values from the API response. The coveted value is
    body('parse_json_action')['resourceSets'][0]['resources'][0].timeZone.genericName
    (Don’t ask)
  6. Convert time zone action will give us the conversion we are after (button is kind to give us the timestamp when it was pushed)
    image
  7. Finally, we can call a location API to get the place or neighborhood (full address is available as a trigger token) and then send a notification to ourselves telling us what was the time and where we pushed that button
    image

The results are awesome:

image

Afterthoughts

I noticed that all posts about Flow are full of images. I fell into that trap too, it seems, but for the last time. Instead, download the flow (sans the keys) here and import into your environment to play with it.

(Cover photo by Ehimetalor Unuabona on Unsplash)