SujataNarayana's avatar
SujataNarayana
Microsoft Employee
1 year ago

Approval workflows

You can allow users to kick-off approval workflows to enable admins or specific users to approve or reject various requests.

For example, on the report below non-admin users can propose a discount and submit it as request such that an admin will be notified of the request.



The admin will get the discount request in a Teams channel, and when they click approve, they are redirected to a separate admin report that is automatically filtered to the right data and shows the requested discount percentage. The admin can do the final review and apply the requested discount.



This approval workflow scenarios requires two user data functions to:

  • Send a request : Request for an admin to approve a discount
  • Approve a request: Admin can apply the discount

Here is the user data function for the Send a request scenario: 

import fabric.functions as fn
import logging
import requests

# Initialize the UserDataFunctions
udf = fn.UserDataFunctions()

#This function is designed for sending an approval request message to a specific Microsoft Teams channel using the Microsoft Graph API
@udf.function()
def RequestDiscount(user: str, comment: str, discount: float, revenue: float, URLfilter: str) -> str :

    logging.info('Python UDF trigger function processed a request.')
    try:
        
        # Define the endpoint URL for Microsoft Graph API to send a message to Teams
        team_id = "<team id>"  # Replace with your actual team ID
        channel_id = "<channel id>"  # Replace with your actual channel ID
        url = f"https://graph.microsoft.com/v1.0/teams/{team_id}/channels/{channel_id}/messages"
         

        # Define the headers including the authorization token
        headers = {
            "Authorization": "<auth token here>",  
            "Content-Type": "application/json"
        }
          

        Discountpercent = str(discount) + "%"
        Discountdollars = '${:,.2f}'.format(((discount/100) * revenue))
       
        ApprovalURL = "<Report URL here>" + URLfilter + "%20and%20DiscountValues%2FValues%20eq%20" + str(discount) #add your report URL here
        
        # Define the message body with HTML links
        #I only configured an approval flow for demo purposes. You will need to add reject action as well or remove this option.
        message_body = f"""
            <div>
                <strong>Discount Request from {user}</strong><br>
                <p>Discount percentage: {Discountpercent}</p> 
                <p>Discount total: {Discountdollars}</p>
                <p>Comment: {comment}</p>
                <p>
                    <a href={ApprovalURL} target="_blank">Approve</a>  |   
                    <a href="https://example.com/reject" target="_blank">Reject</a> 
                </p>
            </div>
        """

        # Define the payload
        payload = {
            "body": {
                "content": message_body,
                "contentType": "html"
            }
        }
        
        # Make the POST request to the Microsoft Graph API
        response = requests.post(url, headers=headers, json=payload)
      
        # Check if the request was successful
        if response.status_code == 201:
            return "Approval request successfully posted in Teams."
        else:
            raise fn.UserThrownError("Failed to post approval request.", {"Status code": response.status_code}, {"Response": response.text})  
            
    except Exception as e:
        raise fn.UserThrownError("We ran into an issue.", {"Error:": str(e)})

 

Here is the user data function for the Approve a request scenario: 

import fabric.functions as fn
import logging

udf = fn.UserDataFunctions()

@udf.connection(argName="sqlDB", alias="Translytical")
@udf.function()
def ApproveDiscount(sqlDB: fn.FabricSqlConnection, opportunities: str, discountinput: float, comment: str)->str :
     
    logging.info('Python UDF trigger function processed a request.')
    
    connection = sqlDB.connect()
    cursor = connection.cursor()

    if (discount < 0):
        raise fn.UserThrownError("Discount cannot be negative")
    if (discount > 1):
        discount = discount / 100
    if (discount > 0.50):
        raise fn.UserThrownError("Discount cannot exceed 50%")

    # SQL update command
    SQL_update_command = "UPDATE [dbo].[Opportunity] SET [Discount] = " + str(discount) + " WHERE Opportunity_Number IN (" + opportunities + ")"
    cursor.execute(SQL_update_command)
                           
    # Commit the transaction
    connection.commit()

    # Close the connection
    cursor.close()
    connection.close()
    
    try:
        # Define the endpoint URL for Microsoft Graph API to send a message to Teams
        team_id = "<team id>"  # Replace with your actual team ID
        channel_id = "<channel id>"  # Replace with your actual channel ID
        url = f"https://graph.microsoft.com/v1.0/teams/{team_id}/channels/{channel_id}/messages"
         

        # Define the headers including the authorization token
        headers = {
            "Authorization": "<auth token here>",  
            "Content-Type": "application/json"
        }
                  
  
        # Define the message body with comment
        message_body = f"""
            <div>
                <strong>Approved Discount Request</strong><br>
                <p>Comment: {comment}</p>
            </div>
        """

        # Define the payload
        payload = {
            "body": {
                "content": message_body,
                "contentType": "html"
            }
        }
        
        # Make the POST request to the Microsoft Graph API
        response = requests.post(url, headers=headers, json=payload)
      
        # Check if the request was successful
        if response.status_code == 201:
            return "Discount has been approved and applied. Team has been notified."
        else:
            raise fn.UserThrownError("Failed to post approval request.", {"Status code": response.status_code}, {"Response": response.text})  
            
    except Exception as e:
        raise fn.UserThrownError("We ran into an issue.", {"Error:": str(e)})

 

Feel free to use this code as inspiration for your approval workflow scenarios!

2 Replies

  • KBO's avatar
    KBO
    Memorable Member

    Hi :),

    maybe you can add the permissions you need to give via graph explorer ๐Ÿ˜‰

     

    Best regards,

    Kathrin