Monday, 3 June 2019

Automatically update the stage of a Business Process Flow with Flow 2.0

22:26 Posted by Benitez Here , , , , , No comments
From my last WTF episode:

I decided to use two Compose actions because I don't know how to store the Dynamics 365 API request in a Flow action. If you know how to do this, feel free to blog and tweet to me so that I can check it out.

I heard back from two people, hooray!

The first person I heard from was David Yack, he was wondering why I had chosen my uncanny method when really I could achieve the same outcome using the List Records action. When he explained it I was thinking to myself, hmmm... 🤔 oh... YEAH!!! It was so obvious only after hearing it from him haha. Like any other person who goes through the process of solution design - sometimes the answer is staring at you the whole time.

The second person I heard from was Yasir Safeer who I currently work with. He was going to suggest another method however I mentioned I already heard from David. However, he gave an awesome tip which made me go, really?! I tried it and to my surprise it worked.

This WTF episode talks about the two improvements I made to my Flow thanks to David and Yasir
#iAppreciateYou 🙏

Using a CDS List Records action

My Flow trigger is when the status reason of the Application has been updated. Next, I was using a CDS List Records action that would retrieve the Application Business Process Flow record so that I could identify the  associated Process Stage ID.

Rather than storing the Review stage ID and the Approved stage ID in two Compose actions after calling the API request in a separate browser using the Process stage ID, I can simply use the CDS List Records action against the Process Stage entity. I was able to use a filter query from David's suggestion that would only return the Process Stage record that had the stage name of "Review."


It's so funny to me because it was staring at me when I was reviewing the API request. It clearly tells you the entity to reference and the field as well. Thanks David for showing me way 😁 It was not obvious at the time but now it is.

I then applied a Parse JSON action where I used the first function. 

first(body('1.4.1_Get_Process_Stage_Review_record')?['value'])


I'm only after after a single record and the first function prevents the Apply to Each from appearing downstream in the Flow. I am using the properties later on in the Flow. I briefly covered the first function in another previous WTF episode so take a look when you can.

I applied the same methods for the Approve stage however what you'll see differently this time is that I am using parallel branching. Parallel branching is useful when you have actions that can be executed that are not dependent on the previous action or each other. Since I am retrieving the stage IDs through the List Records action both actions can run at the same time.

Changes to the last action

My very last action in the Flow is updating the Application Business Process Flow record. In the Active stage field of the action I am referencing the stage ID through the Parse JSON action. Previously I was achieving this through my two compose actions.


The cool tip that Yasir shared with me is that you don't need to update the Traversed Path value. I was puzzled because I followed what was in the docs.microsoft.com article but I trust Yasir's advice given that he's an awesome consultant so I gave it a go. I cleared my previous expression and left it blank.

Flow in action

When you submit an Application, the Flow succeeds as I expected.


When there are two approvals (one from the External Reviewer and the other form the Internal Reviewer) the Flow succeeds as I expected.


In both use cases the traversed path correctly updates. Amazing. Thanks Yasir, good tip man.

Summary

By using a CDS List Records action against the Process Stage entity, it will allow you to reference to the stage IDs of your Business Process Flow entity. You also don't need to use an expression to update the Traversed Path field either, it magically works 🧙‍♂️

My WTF Flows is available for download on the TDG Power Platform Bank.

Till next time, toodles.

Thursday, 9 May 2019

Automatically update the stage of a Business Process Flow with Flow

I have worked on Dynamics 365 for Portals projects and one of the things I get asked is how to reflect the lifecycle of an application back in the model-driven app. This is for the purpose of users who need to interact with the application to progress it for the ultimate goal of the application being approved. Naturally Business Process Flows come to mind because it's a visual aid to help users understand what is to be completed in each stage.

I wanted to see if it is possible to automatically update a Business Process Flow using Flow based on interactions by multiple types of end users. These would be end users of the portal and end users of the model-driven app. I put Flow to the test and it worked 😄 In this WTF episode I cover how to automatically update a Business Process Flow stage with the power of Flow.

Quick lesson on behind the scenes of Business Process Flows

For the folks in the community who have been around the Dynamics 365 circuit for a while, the method of retrieving and updating BPF fields within the record is deprecated.


For example Stage ID and Traversed Path will display as deprecated in the Application entity customization settings. Note: for some reason in https://web.powerapps.com the Stage ID was not displaying so my screenshot is from the classic solution editor.


The current supported method is to reference fields in the BPF entity that would have been created when your BPF was created. In my scenario I created a custom Application BPF and a custom BPF entity was also created. There are fields within this entity that will be used in my WTF Flow which are
  • Active Stage ID - this will contain the stage ID value of the Business Process Flow stage the application is currently in
  • Application - this is the lookup to the application record
  • Business Process Flow Instance ID - this is the ID of the record that will be used in a Flow action
  • Status
  • Status Reason
  • Traversed Path - this will contain the active stage IDs the Business Process Flow has gone through in its lifecycle

Use case

I am extending my Grant Application Management solution to replicate the real world of an organisation. I have previous vlogs and blogs that cover it.
  1. Grant application management part 1: Universal Resource Scheduling
  2. Grant application management part 2: the external reviewer and applicant experience
  3. Dynamics 365 Saturday Scotland 2019 - Grant Application Management
In a nutshell
  • a grant application is submitted through the portal
  • an external reviewer is assigned to the application where they are required to approve or reject it through the portal
  • an internal reviewer also approves or rejects it within the model-driven app
  • until there are two approvals, the application will not be updated to Approved
To keep it simple and for demo purposes I have three stages in my custom Application Business Process Flow.
  1. In Progress
  2. Review
  3. Approved

Here is the interactions of the end users that will trigger the Flow
  1. When an application is submitted by an Applicant through the portal, the Business Process Flow stage of the application record should automatically move from the In Progress stage to the Review stage. This is so that anyone within the organisation can see that the Application is now in the Review stage.
  2. When both the External Reviewer and Internal Reviewer has approved the Application, the Business Process Flow stage of the application record should automatically move from the Review to Approved stage.
This is a Business Process Flow that uses a single entity.

Let's Flow

1 - The trigger

The trigger will be when the status reason of the Application has been updated.

2 - Retrieving the Application Business Process Flow record

Since the supported method is to reference the fields in the Business Process Flow record, the List Records action is used to retrieve the Application BPF record associated to the Application.

The filter query is for the purpose of only returning the Application BPF record associated to the Application. If a filter query is not used then ALL Application BPF records will be returned.

3 - Parse JSON

To reference the properties returned in the JSON response from the List Record returned, the Parse JSON action will be used. In my expression I am use the first function which I covered briefly in my previous WTF episode.

4 - Compose action for the Review stage ID

To move the Business Process Flow from one stage to another, the stage ID needs to be captured in the traversed path field. I am using two compose actions to store the value of the stage IDs.

To identify the stage ID values of the Business Process Flow there is a Dynamics 365 API request which can be found in the docs.microsoft.com article.


In the API request you reference the Dynamics 365 organisation URL along with the ID of the business process flow record. The simplest way to grabbing the ID is to do it from the Business Process Flow record.


Once you execute it in a browser it will look something like this:

Copy and paste into Notepad++ and use the JSON viewer plugin so that the response can be easier to read for the Business Process Flow stage IDs.


The Review stage ID can now be referenced in the Compose action.


I decided to use two Compose actions because I don't know how to store the Dynamics 365 API request in a Flow action. If you know how to do this, feel free to blog and tweet to me so that I can check it out.

5 - Compose action for the Approved stage ID

This Compose action references the Approved stage ID.

6 - Initialize Variable action for the Switch action

If you have not used the Switch action before I recommend checking out the Flow blog and Pieter Vienstra's blog to learn about the Switch action. He has a couple of great blog posts on the Switch action.
The reason why I am using a Switch action is that there are multiple outcomes for the Application Business Process Flow based on the Application Status Reason. Using the Condition action would work too but it means that there will be a few branches and if you have a Business Process Flow with more than 3 stages, the Flow could look like a mess.

Using a Switch is just as effective and provides the desired output based on the Application Status Reason. A single field is defined in the Switch that will drive what should happen next in the Flow.

The Initialize Variable allows me to reference the Application Status Reason in my switch. I set the type to Integer as the Status Reason is an Option Set where each value in the Option Set is an integer.

7 - Switch it up

In the Switch action we reference the variable. Based on the value of the Status Reason a switch will be performed. The two cases can are defined as
  • If the Status Reason has been updated to Submitted the Business Process Flow record needs to be updated from In Progress to Review.
  • If the Status Reason has been updated to Approved the Business Process Flow record needs to be updated from Review to Approved.

7.1 - Moving to the Review stage

When the Status Reason equals Submitted, the CDS Update a record action will be used to automatically move the stage from In Progress to Review.

Entity

The entity referenced will be the Application BPF. Reminder that this is the entity that was automatically created when the custom business process flow was created.

Record Identifier

The Record Identifier will be the business process flow instance id from the Parse JSON action. This property uniquely identifies the business process flow record associated to the Application.

Traversed Path

The Traversed Path is a field as mentioned earlier that represents the lifecycle of the business process flow as it contains the stage IDs the Business Process Flow as gone through. The Traversed Path field value needs to be updated to include the stage ID of the current active stage it will be moved to. This is the Review stage.

To include the stage ID in the Traversed Path field the concat function is used in an expression. This allows the Review stage to be appended to the existing Traversed Path field value which can be derived from the Traversed Path property in the Parse JSON action.

The expression will be the following

concat(body('1.3_Parse_JSON')?['traversedpath'], ',',outputs('1.4_Review_Process_Stage_ID'))

Active Stage

This field value will be the earlier Compose action that references the Review stage ID.

Application

The final field to ensure you populate is the lookup that associates the Business Process Flow record to the Application. This is done through the Application ID from the trigger. 


7.2 - Moving to the Approved stage

When the Status Reason equals Approved, the CDS Update a record action will be used to automatically move the stage from Review to In Progress.

Same definitions except for a couple

The same field definitions apply however there's two more that is required in the CDS Update a record action since the Approved stage is the final stage in the Business Process Flow. This is so that the final state of the Business Process Flow is correctly reflected to the end user in the model-driven app. For further information refer to the docs.microsoft.com article.
  • Status Reason - this will be set to Finished
  • Status - this will be set to Inactive

Flow in action

Time to run the Flow. When the Application has been submitted through the Portal, the Business Process Flow of the application record will automatically move from In Progress to Review.


When the Application has two approvals - one from the External Reviewer and the other from the Internal Reviewer, the Business Process Flow of the application record will automatically move from Review to Approved where the state will show as finished.

Summary

Based on different end user interactions whether it is through Dynamics 365 for Portals or within the model-driven app, the business process flow of a record can be automatically updated to progress from one stage to the other using the power of Flow.

Don't forget to subscribe to my YouTube channel.

Toodles.

Sunday, 14 April 2019

Storing the date input value in a Dynamics 365 or CDS DateTime field

In Flow there are triggers and one of the CDS triggers available is the "When a record is selected." In this trigger you can configure an input that will allow the end user to enter information. The available inputs today are the following:


When you configure your trigger to use the date input, it might puzzle you at first when you look at the value in your model-driven app. For example in my Flow the end user is selecting a date and the value will be used as the Due Date of a Task that is created from the Flow.


When you review your Flow run history it may look like this:


The Flow will be successful however when you look into the run detail you'll notice that in the Task action the default time value associated is midnight.


When the end user views the Task in the model-driven app it will look like the following:


This may not make sense at all to the end user. The reason behind it is due to how Flow, Dynamics 365 and CDS use UTC for DateTime fields. In a model-driven app the end user is viewing it in their time zone. In my case I am in the Melbourne, Australia time zone and UTC midnight equals 11am in Melbourne.


So how do you display it accordingly? That's what this WTF episode covers.

Retrieving the time zone of the user who triggered the Flow

Since the trigger is "When a record is selected," it's not possible to use the "Get record" action to retrieve the user's time zone as you would've seen in my previous WTF episode. This action is more suited to when you want to retrieve information based on a user lookup field. However since the Flow will be triggered from an end user selecting a record, the method this time has to be different.

Enter two other MVP sources
  1. Tip #1205: Local time in Flow using Common Data Service
  2. CDS, Microsoft Flow and DateTime formats
Both outline methods that allow you to identify a user's time zone. For this WTF episode I am using the method described in the CRM Tip of the Day post. The Flow in the CRM Tip of the Day post is available for download as well.

For the remainder of this blog post I'll now break down the Flow.

1 - The trigger

The trigger is when a record is selected in CDS through the model-driven app and the date input is used as seen earlier.

2 - Retrieving the date input value

Use a compose action to grab the date input value of the trigger. This is so that it can be referenced in the last CDS action.

3 - Get the end user's Office 365 profile information

Use either the Office 365 Get My Profile or Get User Profile - either one will work, by referencing User ID from the trigger. 



The purpose of this action is to retrieve a value that will identify the Dynamics 365 or CDS user through their Office 365 ID in order to retrieve their time zone from their defined personal settings. This value is what will be used in the next action to associate it to the user's Azure Active Directory Object ID.

4 - List records to grab details of the user in Dynamics 365 or CDS

The entity to references is Users and the filter query is the following,


This will identify the user in Dynamics 365 or CDS. If you look at the output of this action and view it in Notepad++, it's this property that lives in the Users entity:

5 - Retrieve the user GUID

This step is not necessary but it keeps your Flow tidy. If you don't do this step, the Apply to Each action will appear. Use a compose action to retrieve the systemuserid value. The function you're going to use is first. In a list record action, multiple results are usually returned. When you know that you're only going to reference one record returned by the query, the first function is handy because it'll make the output appear as "one" rather than a list of records. This will prevent the Apply to Each from appearing. Your expression will look like this

first(body('1.4_List_executing_user')?['value']).systemuserid

6 - Retrieving the time zone information of the user

This get record action is the same action from my last WTF episode where you retrieve the user's personal settings to identify their time zone through the timezonecode property. Reference the output of the previous compose action that has the systemuserid.

7 - Retrieving the time zone name of the user's time zone

This list records action is the same action my last WTF episode where you reference the time zone definition entity to retrieve the time zone name. The time zone of the user is defined through the property timezonecode.

8 - Retrieve the time zone name

Similar to #5 where you use the first function in an expression to retrieve the time zone name from the standardname property. This will keep your Flow tidy.

first(body('1.7_Get_Time_Zone_Name_of_User')?['value']).standardname

9 - Set the Time of the DateTime value

When you select a date from within the trigger (#1) the default time will be midnight. To avoid confusing the end user when they are viewing the DateTime field that will reference the selected date, provide a set/fixed time. In my vlog I was using 9am which is 09:00:00.

Use a compose action and the function you are going to use in your expression is formatDateTime to reference the output of the Date Input followed by a string format of the date and time. In the string format is where you included your desired set/fixed time.

formatDateTime(outputs('1.2_Date_input_value'), 'yyyy-MM-ddT09:00:00')

10 - Convert time zone action

This is your best friend when it comes to storing date and time values in Dynamics 365 or CDS DateTime fields. To display the desired set/fixed time of 9am, you must convert 9am in the context of the end user's time zone into UTC.  Since Flow, Dynamics 365 and CDS use UTC, this is required whenever you want to display a DateTime value that makes sense to the end user based on their time zone.
  1. For the base time, the output of the compose action in #9 is used.
  2. For the the format time, use the usual ISO format. To do this select custom and enter the format.
  3. For the source time zone, use the output of the compose action in #8.
  4. For the destination time zone, use UTC.

You can also use a compose action and use the convertTimeZone function in an expression if you want to be ultra nerdy and not use the official convert time zone action. This works too #TriedAndTested

11 - Grabbing the converted time

In my action that is creating a new Task record, I am referencing the output of the convert time zone action as the Due Date. 

Ta da!

Now when you run the Flow and view the record in the model-driven app, the date and time now displays correctly according to the end user's defined time zone.

Summary

Whenever you use the Date Input in your "When a record is selected" action and need to display the value back to the end user, it has to be defined in the local time zone of the user and then converted into UTC. To reference the user's personal settings who triggered the Flow for their time zone information, you'll need to grab details of their Office 365 profile to identify their user record in Dynamics 365 and CDS.

Thursday, 14 March 2019

How to populate a date and time field based on a user's local time zone

22:17 Posted by Benitez Here , , , , , , No comments
There's been questions from the Dynamics community about not being able to successfully populate a date and time field in Dynamics 365 or CDS. A cryptic error is presented at times and often leads to frustration because when populating a date and time field in classic Dynamics 365 workflows it is a breeze. Hold on to that thought though.

In this WTF episode I show you how to populate a date and time field based on a user's local time zone. Yes, you read that right. This has been a problem for organisations that use Dynamics 365 or a Model-Driven app where end users are in multiple time zones. Now with the power of Flow you can do it without code and it's fast.

Use case

When a Case is created, create a new Task for the Owner with a Due Date by adding 2 days and set the date to 9am. Guilty - I forgot to explain this in my WTF vlog episode 😂 #oops

What you're familiar with today

There's two methods in classic Dynamics 365 workflows that are available when configuring the Due Date of an activity.

Using operators

You can add or subtract the following
  • Months
  • Days
  • Hours
  • Minutes
Nice but not good enough. Why?

You can't use a fixed time of 9am. It's either add or subtract the Hours and Minutes.

Using a default Date and Time

You can set a default date and time value.

Nice but still not good enough. Why?

You're restricted to the fixed date you've selected and cannot use the add or subtract function. However you can set a fixed time of 9am.


If you do choose to default the date and time, there's till an underlying problem that exists. It's to do with the time zone of a user.

The time set is based on the time zone of the user who created the classic Dynamics 365 workflow. For users in a different time zone of that particular user, they will see the time of the Due Date field in their local time.

As seen in my vlog - a user in the Melbourne, Australia time zone will see the Tasks with a Due Date of 9am.


A user in the Wellington, New Zealand time zone will have their Task created with a time of 11am for the Due Date. This is because Wellington is 2 hours ahead of Melbourne, Australia time zone.


This has always been a constraint when working with classic Dynamics 365 workflows.

Still think populating a date and time field in classic Dynamics 365 workflows is a breeze? 
No soup for you!

Show me the power of Flow

The solution I've come up with applies the convert time zone action which was covered previously in WTF episode 11 where I showed you how to delay sending a birthday email based on the time zone of recipient.
  • Watch WTF episode 11 here

1.2 Get the User of the Case

The trigger of the Flow will be when a Case is created. Through the Owner field, we can retrieve the user record using the CDS Get Record action.

1.3 Get the User's time zone

In Dynamics 365 and CDS a user's time zone is configured through Personalization Settings.



We want to retrieve this information about the user. To achieve this, use the CDS Get Record action and reference the User Settings entity. This entity is not visible from within Dynamics 365 or CDS and is traditionally accessed through the Dynamics 365 SDK.


When you run this Flow and observe the response returned in this action, you'll see a property (which is a field in the User Settings entity) called timezonecode.


This represents the time zone of the user. However we want to know the name of the time zone so that it can be used later in the Convert Time Zone action.

1.4 Get the time zone name of the time zone code

As per this docs.microsoft article, there are three entities that store time zone information in Dynamics 365 (and I also assume CDS). The entity that has the time zone code information is the Time Zone Definition entity. This entity is not visible from within Dynamics 365 or CDS and is traditionally accessed through the Dynamics 365 SDK.

Use the CDS Get Record action to retrieve the time zone definition entity.


When you run this Flow and observe the response returned for this action, you'll see an array of all the time zone definitions for Dynamics 365. For each of the time zones there will be a property called standardname that represents the time zone name.


How do you return only the time zone that is associated to the user's settings?

1.5 Use a query through the CDS List Records action

This is a tip I learnt from fellow MVP and colleague Natraj. The CDS List Records action allows you to query against an array. In previous episodes I showed how to query against records in Dynamics 365. This time round, I am going to use it against the returned response.

The filter query expression to use is to reference the timezonecode field in the Time Zone Definitions entity and the timezonecode field from the User Settings entity from the earlier action (1.3 Get User's Personal Settings). 


This will then only return the time zone definition details of the user's configured time zone.

1.6 Configuring the date and time for the value of the Due Date field

Use a Compose action to set the date and time. In my example, I am adding 2 days to the current date and setting the time to 9am. To achieve this I am using the addDays function
  • To reference the current date, I am using the utcnow function
  • To set the number of days, I am using the integer of 2
  • To set the time, I am entering a string value
The expression I have used is addDays(utcNow(), 2, 'yyyy-MM-ddT09:00:00')

1.7 Convert the local time into UTC

You would have seen or read me cover this in WTF episode 11. I'll outline what I am doing slightly different this time.
  • For the Base Time, I am referencing the output from the previous action where I've set the date and time.
  • For the Format String value it has to be in the UTC Date time format.
  • The source time zone will be the standardname property from 1.5 Get Time Zone Name of User action. When you select this, the Apply to Each will appear.
  • The destination time zone will be the UTC time zone. 

Quick recap on why UTC

  • Remember, Dynamics 365 underneath the hood stores date and time as UTC. Time zone entity definitions + user's time zone is what makes it appear as "local" in a Model-Driven app.
  • Stephen's blog post explains that Flow treats Date and Time in UTC.

1.8 Creating the Task

The last action is to create the Task and reference the output of the convert time zone action as the Due Date value.


The result

When you trigger the Flow as a user based in Wellington, New Zealand, the Task will have a time of 9am in their local time for the Due Date.


When you trigger the Flow as a user based in Melbourne, Australia, the Task will have a time of 9am in their local time for the Due Date.


If you compare the Tasks with each other the due date and time will be different.

As the Wellington based user, I will see the Melbourne user's Task have a due time of 11am.


As the Melbourne based user, I will see the Wellington user's Task have a due time of 7am.


To see it in action watch my WTF vlog.

Summary

Using the power of Flow you can now set the Due Date of an activity or any other date and time field based on a user's local time zone. You are not able to achieve this functionality today in a classic Dynamics 365 workflow.

This Flow is available for download in the TDG Power Platform Bank.

For another great time zone related post, check out Tip #1205.