Power Platform

Power Series: Subscriptions Manager – EP 1


Welcome to the first episode of the Power Series! The goal of the Power Series is to create and extend Power Platform solutions in each episode using both low-code and pure coding technologies. Expect things like Canvas Apps, Model-Driven Apps, advanced Power Automate flows, integration with Microsoft Azure and more.

You can follow along with creating the solution and all its components, or you can find the complete solution at the end of each episode.


In this episode, we will be building a Subscriptions Manager application on the Power Platform that allows our users, partners, customers to subscribe to individual subscription channels and receive e-mail notifications on those channels only.

Note
This solution will prove useful when you have/will have Power Automate flows sending out custom e-mails to your customers and need a way to configure who should receive and what – like one customer needs to receive marketing materials, while the other should receive a monthly newsletter.

Today we will be preparing the following components of the solution:

  1. Create the required entities in Common Data Service to store subscriber and channel information.
  2. Build a model-driven app to allow administrators to manage subscription channels and subscribers.
  3. Define a Power Automate flow to send e-mail notifications for a user on opportunity owner change.

Prerequisites

In this episode we will be using the following technologies and services:

  • Common Data Service
  • Model-driven apps
  • Power Automate

It is advised to be familiar with all of these services, but you can go ahead and skip to the end of this article, download the solution, import it in your environment and come back here to follow along how did I create each component of the solution.

Teaching the basics is not the goal of this article, but if you would like to know more of these services, take a look at my article about the Power Platform. But less talk, more action! Let’s get started!

Creating the solution & entities

Whenever we start a new project inside the Power Platform, we should always create a new solution that will contain all the necessary components and modules for that projects.

This way we can easily package our project and deploy it to other environments – not to mention that when we work on numerous projects simultaneously in one environment, you wouldn’t be able to keep track of where each component goes.

To create the solution

  1. Open the Power Apps portal.
  2. (Optional) Make sure you choose the correct environment when you have more of them (a development environment is preferred).
  3. Open the Solutions section.
  4. Click on New solution on the top navigation bar and fill in the details.
Power Apps - New solution
Power Apps – New solution

Note
Don’t forget to create a new publisher first so you can define an own prefix for your custom entities and columns and people will now that this awesome solution is made by you!

Next, we will be creating two custom entities inside our solution:

  • Subscription Channel: Contacts can subscribe to these channels. Of course, one channel can have as many notifications connected to it as you want.
  • Subscription: Defines a connection between a Contact and a Subscription Channel. This entity will tell us who subscribed for what.

Create the entities

  1. Open your newly created Subscription Manager solution.
  2. Click New on the top navigation bar and select Entity:
    • Display name: Subscription Channel
    • Plural display name: Subscription Channels
    • (optional) I like changing the name to contain only lowercase letters, I leave it up to you if you’d like to change it 🙂
    • Primary field:
      • Display name: Channel Title
      • Name: title (without the prefix)
  3. Once the entity is created, you can add new fields by clicking Add field button on the top navigation bar. Add the following fields:
    • Channel Type
      • Data type: Option Set
      • Values: E-mail, Phone, Other
      • Required: Required
    • Description
      • Data type: Text Area
      • Required: Optional
  4. Save the entity.
  5. Open the Forms tab of the entity.
  6. Edit the Main form of the entity to include the fields you have just added (Channel Type, Description). Organize them the way you like it and also keep the default fields on the form.
  7. Save the form.

Create another entity the same way as above but with the details described below:

  1. Create new entity:
    • Display name: Subscription
    • Plural display name: Subscriptions
    • Primary field:
      • Display name: Subscription Identifier
      • Name: name (without the prefix)
  2. Add the following fields to the entity:
    • Subscriber
      • Data type: Lookup
      • Related entity: Contact
      • Required: Required
    • Subscription Channel
      • Data type: Lookup
      • Related entity: Subscription Channel
      • Required: Required
  3. Change the type of Subscription Identifier field to Autonumber by clicking on the field on the Fields tab and changing Data type to Autonumber. Set Prefix to SUB.
  4. Save the entity.
  5. Edit the Main form of the entity as described for Subscription Channel.
Autonumber property in Common Data Service
Autonumber property in Common Data Service

We will need a way to create new records for these entities so we can manage our subscribers and channels. For that purpose, we will be creating a new model-driven app.

Create a model-driven app

Our model-driven app will be used to manage our Subscription Channels and Subscribers. Later we can extend it with more functionality like dashboards and such, but for now we will focus on the basics only.

To create a new model-driven app

  1. Open your Subscription Manager solution
  2. Click on New and select App > Model-driven app
    • Name: Subscription Manager
    • Enable “Use existing solution to create the App”
    • Select Solution: Subscription Manager
    • Enable “Configure site map later”
  3. Click Done to create your app.

After the app is created, you will be presented with the App Designer.

Model-driven app designer
Model-driven app designer

Here you can make customizations to your app to change the navigation, the entities, forms, views you want to use in your app.

Design the app

  1. Select Components tab on the right of your screen.
  2. Choose Entities.
  3. Select Contact, Subscription, Subscription Channel and click back.
  4. Click on the pencil next to the Site Map to edit it.
  5. Rename the primary area to Manage by hovering over the area’s name and clicking on the pencil on the right of it.
  6. Rename the primary group to Business.
  7. Add Contacts subarea to this group:
    • Click on the Business group.
    • Click on Add and select Subarea.
    • Change the details of the new subarea on the right of your screen:
      • Type: Entity
      • Entity: Contact
      • Title: Contacts
  8. Create a new group named Subscriptions by clicking on Management area, click Add and select Group.
  9. Add Subscribers and Channels subareas the way we have added Contacts.
  10. Click on Save to save all changes.
  11. Click on Publish to have all changes published.
Power App Sitemap Designer
Power App Sitemap Designer

Your model-driven app is now ready and can be accessed. To open the app, click on App Designer on the top left of the current screen and click Play, or head back to your solution, click on the three dots next to the model-driven app and choose play.

Subscription Manager
Subscription Manager

Create initial data

Since we will need some data that we can use later, let’s create some records now:

  1. Create a Subscription Channel by navigating to Channels and clicking on New.
  2. Give the channel a Channel Title, select a Channel Type and fill in the Description field so the users will know what notifications they should expect.
  3. (optional) Create one channel for E-mails and one for Phone too.
  4. Create a Contact that has exactly the same e-mail address that you use for logging in here. We will discuss this in detail later when we create our flow why it is necessary.
  5. Create a new Subscriber by navigating to Subscribers and clicking on New.
  6. Set the Subscriber to be the contact you have just created and the Subscription Channel.
  7. (optional) Create a Subscriber for both channels.

Advanced Tips
The more advanced users might come to the conclusion that we could manage subscriptions with a direct connection between Contact and Subscription Channel. This is true, however with creating a separate Subscriber entity, you will be able to extend it with further details like expiration date and such, which would be impossible with a direct relationship.

Create a notification flow

Finally, we will be creating our flow that will send out the notification e-mails to the contacts who have subscribed.

Power Automate Flow Overview
Power Automate Flow Overview

The flow will run when an Opportunity is created or is assigned to a new user. It will find the Contact in our environment with the same e-mail address as the owning User of our opportunity, determines if the contact has an active Subscription for the defined Subscription Channel and sends out the e-mail if necessary.

Note
The reason why we have chosen to use Contacts instead of Users is because this is the only way to ensure that anyone can become a Subscriber, not just those who has a license in our environment. Furthermore, if we extend our application with a Power App Portal, it will use Contacts for authentication.

Building the flow

To create a new Flow

  1. Open your Subscription Manager solution.
  2. Click on New and select Flow.
  3. Change its title on the top right from Untitled to Subscription | Notify on opportunity assign.

Because we are inside of a solution, we can use the Common Data Service (current environment) connector. This is not the same as the Common Data Service connector, so please ensure that when you create any action in your flow, you are using the proper one!

Notes
The main difference between the two connectors is that you do not need to define the current environment for the first one. Other than that, you have access to a lot of new actions and you will have the opportunity to define a trigger for multiple events in CDS with one flow (like create and update).

I will walk you through all the steps of the flow one by one. If you are stuck somewhere or you do not understand something, do not worry. The flow is part of the solution you can download at the end of this article!

1. Create the trigger by selecting Common Data Service (current environment) connector and click When a record is created, updated or deleted.

Our trigger defines that it should run when an Opportunity is getting created or updated by anyone inside of the organization. As you can see, we have defined a Filtering attribute which tells the flow to only run when the ownerid attribute has been changed.


2. Add a condition by clicking on Add an action after our trigger. Choose Control and click on Condition. The condition will terminate our flow if the Owner (Type) is not set to systemusers.

I have encountered a bug where picking the Owner (Type) field did not working properly, so instead of selecting the field directly from Dynamic content, use the following expression: triggerBody()?['_ownerid_type']

The condition is required because sadly, we are unable to define type filtering in the trigger’s filtering attributes.


3. For easier configuration, we will add a Variable to our flow by adding a new action and choosing Variable and clicking on Initialize variable. Give the variable a Name, define the Type to be string and the value should be the Channel Title of your Subscription Channel.

We will be searching for subscriptions for this subscription channel later in our flow. But instead of hardcoding it in our flow, it is advised to put it inside a variable which can be modified way easier later on.


4. Add a new action by choosing Common Data Service (current environment) connector and Get record action. Set the Entity name to be Users and Item ID to be Owner (Value).

We need to retrieve the owning User record so we can retrieve the e-mail address of the user. We will be using this e-mail address to search for the corresponding Contact.


5. Add a new List records action from CDS (current environment).

The Entity name should be Contacts and the Filter query should be emailaddress1 eq '@{outputs('Get_owner_user')?['body/internalemailaddress']}'

Note that the filter query assumes that you have renamed the previous step to Get owner user. If you didn’t, you can replace the dynamic value with the Primary Email of the retrieved User as shown on the image above.

We will be using the retrieved Contacts to find active Subscriptions. This is why we needed a contact with the exact same e-mail address, because we will be looking for contacts with the user’s e-mail.

Note
The reason why we are using List records instead of Get record is because a single record can only be retrieved by its GUID. Right now, the CDS connector does not support using alternate keys to retrieve a single element.


6. Add another List records action from CDS (Current environment) to list Subscription Channels.

The Filter Query should be set to gaborg_title eq '@{variables('Subscription Name: E-mail Notifications')}' and statecode eq 0

Note that the prefix of the property and the name of the variable might be different in your flow, ensure you have added both of them correctly as shown on the image above.

The statecode eq 0 part of the filter query defines that we are searching for active Subscription Channels only. This action will retrieve a list of subscription channels which we will iterate through – it will be only one record anyways.


7. Add two nested Apply to each loops from Controls. The outer loop should iterate through the values of the Contact List, while the inner loop should iterate through the values of the Subscription Channel List.

Click on Select an output from previous steps. You will see that both your List records actions has returned a value property. You should select the corresponding one for each loop as defined above.

For each of the Contacts we have found for the e-mail of the owning User, we will look for active Subscriptions for each of the Subscription Channels retrieved.


8. Inside the innermost loop, we will add another List records action from CDS (current environment) to list the subscriptions for the current Contact and Subscription Channel. We will search for active subscriptions only.

Please make sure that you use the correct prefixes for each property and you add the correct dynamic values from your previous steps. The Contact property is coming from our Get contact(s) for user step, while the Subscription Channel propery is coming from our Get subscription channels step.

The Filter Query in our example is the following: _gaborg_subscriber_value eq @{items('Send_notification_to_contacts')?['contactid']} and _gaborg_subscriptionchannel_value eq '@{items('Get_subscriptions_for_channel_found_by_name')?['gaborg_subscriptionchannelid']}' and statecode eq 0

The action will retrieve a list of active Subscriptions where the Subscriber field contains the current Contact of the loop and the current Subscription Channel of the loop.


9. Last but not least, we will add a Condition to check if the Subscription list contains any element. If yes, we will Send an email using Outlook 365 to the Contact’s e-mail address with some message.

You can use the length() expression with the returned value of the Subscriptions List and compare if it is not equal to 0.

This is the final step of the flow, where we send out our notification if we have found an active subscription for the channel we have defined in our variable at the beginning.


Test your flow

To test the flow – and apparently the whole solution -, create a new Opportunity inside your environment where your user is assigned as an owner. The flow should be triggered and you should receive a notification e-mail.

Note
Try deactivating your Subscription for the e-mail notifications and create another Opportunity. This time you shouldn’t receive any notification.

Resources

The solution files (both managed and unmanaged) containing all the entities, apps and flows that we have created above can be downloaded from here.

Summary

In this first episode we have created the foundations of our solution where we can manually configure the subscriptions of our contacts for each channel and we have created an example Power Automate flow to send out e-mail notifications to subscribed contacts.

In the next episode we will be extending the current solution with the option for our subscribers to unsubscribe from e-mail notifications. Plus, we will be creating a Canvas App where people can manage their own subscriptions and can receive push notifications!

Did you enjoy the first episode of the series? I’d really love to hear your feedback so the next episode can become even better! Sound your comments below!

Power Platform
Microsoft Power Platform: Approach with Low-Code
Power Platform
3 ways to get the Organization URL in your Plug-in
Power Platform
Dataverse Virtual Entities: QueryExpression to Linq
There are currently no comments.