Approvals in Power Apps with Power Automate, Teams, and Adaptive Cards

Introduction

Are you looking for a simple and extensible no-code solution to do approvals in Power Apps? Perhaps you have built automation within PowerAutomate and want to provide a mechanism to “gate” or confirm your process before it executes. Or, you could be using quoting within Dynamics Customer Engagement and want to have your Sales manager review and approve quotes before they are sent to a customer. In any of these scenarios, you have come to the right place.! In this article, I will show you how to create custom approvals using PowerAutomate/Flows, Teams, and AdaptiveCards.

But first, let’s explore what Adaptive Cards are. 

This image shows the Adaptive Cards 
this image shows the what Adaptive Cards are

To summarize, Adaptive Cards allow you to embed small custom UI elements within a web application (or any application that can render HTML, such as Outlook or Teams) to provide additional information or interactivity in the case of approvals. In the following scenario, we will build a simple model within DataVerse to store our approval activities and then build an Adaptive Card, which we will expose within Microsoft Teams to notify users when they have pending approvals.

I will start by creating a custom approval activity in Power Apps. It can be customized with additional attributes as needed. I will keep this blog post simple. 
Further Reading: Dataflows In Power BI

this image shows custom approval activity in Power Apps

Next, let’s create a Flow. I will use the trigger when a record is created, updated, or deleted. I will get the approval request record with the details of From and To and the regarding record. This information will later be used in the adaptive card and Teams.

This image shows the adaptive card and Teams

Now, I will initialize some variables that will hold the values to be filled in the adaptive card.

This image shows hold the values to be filled in the adaptive card

Streamline Approvals with Expert Power Apps and Power Automate Solutions

Our services are tailored to improve your approval workflows and increase productivity. Are you ready to take your approvals to the next level?

Request a Demo

Now, I need to set the variables I initialized in the previous step with the From and to values.

this i age shows the set the variables

In the first two steps, I am extracting information from the activity party,  setting the formatted values in Name and setting the schema name and id in the second. 
Since we need the e-mail address, we will first have to call the Metadata Service and get the correct pluralized EntitySetName. 

Next, I am getting the record’s e-mail address based on if it was from a system user or a queue. 

Finally, I am updating the From e-mail.

I will repeat the same steps for the recipient: 

this image shows repeat the same steps for the recipient

Now that I have all my information, I will use Post an Adaptive Card to a Teams user and wait for a response action.

this image shows Post an Adaptive Card to a Teams user

For the message field, build your adaptive card Designer | Adaptive Cards copy card payload and insert it. I am entering the information from my variables.

I’ve used Expense Report as a starting point https://adaptivecards.io/samples/ExpenseReport.html. Once opened in the designer, switch the host app to Teams Dark mode. To keep things simple for this scenario, I’ve customized it as follows: 

    “type”: “AdaptiveCard”, 

    “body”: [ 

        { 

            “type”: “Container”, 

            “style”: “emphasis”, 

            “items”: [ 

                { 

                    “type”: “ColumnSet”, 

                    “columns”: [ 

                        { 

                            “type”: “Column”, 

                            “items”: [ 

                                { 

                                    “type”: “TextBlock”, 

                                    “size”: “Large”, 

                                    “weight”: “Bolder”, 

                                    “text”: “**EXPENSE APPROVAL**”, 

                                    “wrap”: true, 

                                    “style”: “heading” 

                                } 

                            ], 

                            “width”: “stretch” 

                        }, 

                        { 

                            “type”: “Column”, 

                            “items”: [ 

                                { 

                                    “type”: “Image”, 

                                    “url”: “${status_url}”, 

                                    “altText”: “${status}”, 

                                    “height”: “30px” 

                                } 

                            ], 

                            “width”: “auto” 

                        } 

                    ] 

                } 

            ], 

            “bleed”: true 

        }, 

        { 

            “type”: “Container”, 

            “items”: [ 

                { 

                    “type”: “ColumnSet”, 

                    “columns”: [ 

                        { 

                            “type”: “Column”, 

                            “items”: [ 

                                { 

                                    “type”: “TextBlock”, 

                                    “size”: “ExtraLarge”, 

                                    “text”: “${purpose}”, 

                                    “wrap”: true, 

                                    “style”: “heading” 

                                } 

                            ], 

                            “width”: “stretch” 

                        }, 

                        { 

                            “type”: “Column”, 

                            “width”: “auto” 

                        } 

                    ] 

                }, 

                { 

                    “type”: “TextBlock”, 

                    “spacing”: “Small”, 

                    “size”: “Small”, 

                    “weight”: “Bolder”, 

                    “text”: “[${code}](https://adaptivecards.io)”, 

                    “wrap”: true 

                }, 

                { 

                    “type”: “FactSet”, 

                    “spacing”: “Large”, 

                    “facts”: [ 

                        { 

                            “title”: “Submitted By”, 

                            “value”: “**${created_by_name}**  ${creater_email}” 

                        }, 

                        { 

                            “title”: “Duration”, 

                            “value”: “${formatTicks(min(select(expenses, x, int(x.created_by))), ‘yyyy-MM-dd’)} – ${formatTicks(max(select(expenses, x, int(x.created_by))), ‘yyyy-MM-dd’)}” 

                        }, 

                        { 

                            “title”: “Submitted On”, 

                            “value”: “${formatDateTime(submitted_date, ‘yyyy-MM-dd’)}” 

                        }, 

                        { 

                            “title”: “Reimbursable Amount”, 

                            “value”: “$${formatNumber(sum(select(expenses, x, if(x.is_reimbursable, x.total, 0))), 2)}” 

                        }, 

                        { 

                            “title”: “Awaiting approval from”, 

                            “value”: “**${approver}**  ${approver_email}” 

                        }, 

                        { 

                            “title”: “Submitted to”, 

                            “value”: “**${other_submitter}**   ${other_submitter_email}” 

                        } 

                    ] 

                } 

            ] 

        }, 

        { 

            “type”: “ColumnSet”, 

            “spacing”: “Large”, 

            “separator”: true, 

            “columns”: [ 

                { 

                    “type”: “Column”, 

                    “items”: [ 

                        { 

                            “type”: “TextBlock”, 

                            “horizontalAlignment”: “Right”, 

                            “text”: “Total Expense Amount t”, 

                            “wrap”: true 

                        }, 

                        { 

                            “type”: “TextBlock”, 

                            “horizontalAlignment”: “Right”, 

                            “text”: “Non-reimbursable Amount”, 

                            “wrap”: true 

                        }, 

                        { 

                            “type”: “TextBlock”, 

                            “horizontalAlignment”: “Right”, 

                            “text”: “Advance Amount”, 

                            “wrap”: true 

                        } 

                    ], 

                    “width”: “stretch” 

                }, 

                { 

                    “type”: “Column”, 

                    “items”: [ 

                        { 

                            “type”: “TextBlock”, 

                            “text”: “$${formatNumber(sum(select(expenses, x, x.total)), 2)}”, 

                            “wrap”: true 

                        }, 

                        { 

                            “type”: “TextBlock”, 

                            “text”: “(-) $${formatNumber(sum(select(expenses, x, if(x.is_reimbursable, 0, x.total))), 2)} t”, 

                            “wrap”: true 

                        }, 

                        { 

                            “type”: “TextBlock”, 

                            “text”: “(-) 0.00 t”, 

                            “wrap”: true 

                        } 

                    ], 

                    “width”: “auto” 

                }, 

                { 

                    “type”: “Column”, 

                    “width”: “auto” 

                } 

            ] 

        }, 

        { 

            “type”: “Container”, 

            “style”: “emphasis”, 

            “items”: [ 

                { 

                    “type”: “ColumnSet”, 

                    “columns”: [ 

                        { 

                            “type”: “Column”, 

                            “items”: [ 

                                { 

                                    “type”: “TextBlock”, 

                                    “horizontalAlignment”: “Right”, 

                                    “text”: “Amount to be Reimbursed”, 

                                    “wrap”: true 

                                } 

                            ], 

                            “width”: “stretch” 

                        }, 

                        { 

                            “type”: “Column”, 

                            “items”: [ 

                                { 

                                    “type”: “TextBlock”, 

                                    “weight”: “Bolder”, 

                                    “text”: “$${formatNumber(sum(select(expenses, x, if(x.is_reimbursable, x.total, 0))), 2)}”, 

                                    “wrap”: true 

                                } 

                            ], 

                            “width”: “auto” 

                        }, 

                        { 

                            “type”: “Column”, 

                            “width”: “auto” 

                        } 

                    ] 

                } 

            ], 

            “bleed”: true 

        }, 

        { 

            “type”: “ColumnSet”, 

            “columns”: [ 

                { 

                    “type”: “Column”, 

                    “verticalContentAlignment”: “Center”, 

                    “items”: [ 

                        { 

                            “type”: “TextBlock”, 

                            “id”: “showHistory”, 

                            “horizontalAlignment”: “Right”, 

                            “color”: “Accent”, 

                            “text”: “Show history”, 

                            “wrap”: true 

                        }, 

                        { 

                            “type”: “TextBlock”, 

                            “id”: “hideHistory”, 

                            “horizontalAlignment”: “Right”, 

                            “color”: “Accent”, 

                            “text”: “Hide history”, 

                            “wrap”: true, 

                            “isVisible”: false 

                        } 

                    ], 

                    “width”: 1 

                } 

            ] 

        }, 

        { 

            “type”: “Container”, 

            “id”: “cardContent4”, 

            “isVisible”: false, 

            “items”: [ 

                { 

                    “type”: “Container”, 

                    “items”: [ 

                        { 

                            “type”: “TextBlock”, 

                            “text”: “* Expense submitted by **${created_by_name}** on {{DATE(${formatDateTime(created_date, ‘yyyy-MM-ddTHH:mm:ssZ’)}, SHORT)}}”, 

                            “isSubtle”: true, 

                            “wrap”: true 

                        }, 

                        { 

                            “type”: “TextBlock”, 

                            “text”: “* Expense ${expenses[0].status} by **${expenses[0].approver}** on {{DATE(${formatDateTime(approval_date, ‘yyyy-MM-ddTHH:mm:ssZ’)}, SHORT)}}”, 

                            “isSubtle”: true, 

                            “wrap”: true 

                        } 

                    ] 

                } 

            ] 

        }, 

        { 

            “type”: “Container” 

        } 

    ], 

    “$schema”: “http://adaptivecards.io/schemas/adaptive-card.json“, 

    “version”: “1.5”, 

    “fallbackText”: “This card requires Adaptive Cards v1.2 support to be rendered properly.” 

Make sure to replace sample values with expressions from PowerAutomate variables of data from Approval Request.
Further Reading: How To Use Power Automate To Enhance Power BI

this image shows Power Automate variables of data from Approval Request

Lastly, we must update the approval request in Power Apps. Once we get the response back from Teams action, I will use the Update a record action and update the approval activity with the appropriate Activity Status and Status Reason.

this image shows Activity Status and Status Reason

Transform Your Workflow with Power Apps and Power Automate

Discover how to seamlessly integrate approvals in your Power Apps using Power Automate, Teams, and Adaptive Cards with AlphaBOLD. Our specialized services are designed to enhance your business processes and workflow automation.

Request a Demo

Here is how the run looks.

This image shows how the run looks
this image shows update record - Adaptive Cards

And there you have it. I hope this blog post got your creative juices flowing and showed you the power of Power Apps, Power Automate, Teams, and Adaptive Cards. 

Explore Recent Blog Posts

Infographics show the 2021 MSUS Partner Award winner

Related Posts

Receive Updates on Youtube