You can read about our findings in Alex’s post below.
Let’s start with some background. The tables and data in this post have been built only for the purpose of this post. In our case we have a transaction record that has certain information about the details of a particular purchase or acquisition. After the record is created, it is submitted for multiple levels of approval by an analyst, associate, director, legal and finally after all the approvals have been completed it can be completed or published. The screenshot below shows a transaction record with some of the data populated.
As the user requests for Approvals, a flow is executed, and based on the Action Type (Submission, Approval or Rejection), the team that this is sent to (Analyst Team, Associate Team, Director Team or Legal Team), the flow executes and processes the request. The screen below shows the different stages that this approval is going through.
Now let’s briefly look at the flow that we created. For testing purposes, I created a flow with a manual trigger that accepts three input parameters the Action Type, the Next Stage (or Status) and the Transaction Unique Identifier. For the actual implementation I have a transition entity that specifies what action can be performed on a particular stage, and what the subsequent stages can be. For example if I am in Associate Review, the two available types of Actions are Approve and Reject. If I approve, the subsequent stage will be Director Review, and if I reject, the subsequent status will move back to Analyst Review.
The flow starts by querying a few different entities and getting some parameters from our Dataverse instance. We start by querying the System User entity and getting the System User Id, and then querying the String Maps and getting the Action Type Code (as shown in the screenshot below)
The Expression for the System User is: first(outputs('List_Systemuser_records')?['body/value'])?['systemuserid']
The Expression for the String Map is:
Next, we need to get the stage id of the next stage, and the unique identifier of the last transaction stage record which needs to be updated with the action and the stage.
The Expression for the System User is: first(outputs('List_stage_records')?['body/value'])?['bas_stageid']
The Expression for the String Map is:
Now that we have all the information we can start updating the data in our existing transaction stages and transaction tables.
The first thing that will be updated is the Transaction stage record that is In Progress. This will be updated with the Action Type, the ending stage, the User that completed the action, and the completion date. The screenshot below shows that update.
Next, we need to create a new transaction stage record. This will contain the stage as the beginning stage of this record and the owner of the new record. The owner will be available in the Stage Transitions table which contains the name of the owning team.
Finally we will update the transaction entity with the current stage so that the users navigating to the record can see the current status, as well as this allows us to manage security on the record by reassigning the record to a different team that will have editable access.
Now that all of the updates have been completed, I need to get some data from the Transaction record, and related records to be able to populate in the email. We will get all data from the transaction table, and then only the Account Name from Accounts, the Full Name from Contacts and the Full Name from User for the name of the approver.
Before we look at the email, let’s take at a few links, that allow us to design the adaptive card.
The Adaptive Card Designer allows you to design cards, not only for Outlook but also for other hosting apps, such as Bot Framework, Microsoft Teams, Cortana and other Windows applications. You can copy the payload of your card to flow from here as well.
The Actionable Message Designer is a tool that allows you to customize the Adaptive Card that will be used for Outlook. You can design it using a visual designer, and then use the JSON Payload to copy into your flow.
Both designers provide a list of predefined samples which you can use when designing your Adaptive Card. In our particular case, we used the Expense Approval sample card from the Actionable Message Designer.
Now let’s get back to our flow, and see the implementation of the adaptive card.
We enter the To and Subject in the Email Message, and before we paste the body of the email, we have to embed it into an Html page. The following is the required content:
The content of the adaptive card payload is long, so I will show this in an animated gif below. It will contain information about the transaction, the clients and the status history of the transaction.
After the flow has been completed, the below email containing the adaptive card will be received.
Now that we have created the adaptive card, there are a few things that we need to keep in mind. There are certain security requirements that will allow you to send an adaptive card to any user. If you are only doing this within your organization, this might be a little easier, but if it’s global, there are additional requirements.
You will need to register an originator for your actionable messages and add that to the script of your actionable card. Publishing is done by adding an account that will have access to send actionable cards:
The full solution can be found in my github repository, and hopefully I can create a video of this sometime soon.