How to integrate D365FO with Microsoft Flow using the new Business Events

The Dynamics 365FO Business Events functionality is currently available as a preview feature since the release of Dynamics 365 Finance and Operations Platform Update 24. With the new Business Events functionality, we can finally integrate D365FO directly with workflow based cloud development tools like Flow and Logic apps.
Here in this article I will demonstrate how to create a new D365FO Business Event and use it directly from a Microsoft Flow using the new D365FO “When a Business Event occurs” trigger.

Enabling Business Events in D365FO

First let’s enable the business events feature and start the batch job for it. The Business Events parameters should be available as a separate tab in System administration>Setup>System parameters form (In this article, I use a PU25 environment):

If you cannot see it there, it is because the feature is currently in preview mode, and you need to do some magic to make it visible. For that; first go to SQL Management tool, open a new query window for your AxDB and run the following sql query :

INSERT INTO SYSFLIGHTING (FLIGHTNAME, ENABLED, FLIGHTSERVICEID) VALUES ('BusinessEventsMaster', 1, 12719367)

Then go to your web.config file for AX and make sure these values in it look like this :

<add key="DataAccess.FlightingEnvironment" value="" />
<add key="DataAccess.FlightingCertificateThumbprint" value="1c2b9bb178c4303d269c39ddf9306ae374129381" />
<add key="DataAccess.FlightingServiceCatalogID" value="12719367" />

Then restart your iss, and you should be able to see the tab now. If not, try restarting iss couple of times, sometimes it does not work immediately.

Enable business events by clicking enable here and click on the Start business events job button to setup the events batch. Well; in Microsoft documentation it states that running the batch job is not needed and only to be used in special situations but in my tests it did not work if I did not start it.. :

Creating a new business event

In this demo I will create a new one from scratch to show all the process involved. As a trigger data source, I will use my visit schedule service project which I have been using in my other blog posts so far. I have updated this project with added business events and uploaded in my github page (that is optional, you can use your own data sources to test as well) :

https://github.com/sertanyaman/SertanDevAXExamples/blob/master/AndVisitScheduleWithBusinessEvent.axpp

First you need to create a business event data contract class. This is a simple data contract class that contains fields for the data source you are planning to send and derives from the “BusinessEventsContract” class:

[DataContract]
public class AndVisitScheduleAddedBusinessEventContract extends BusinessEventsContract
{
    int lineNum;
    str custAccount, custName, address;
    utcdatetime visitDateTime;
    HcmPersonnelNumberId	worker;

    public static AndVisitScheduleAddedBusinessEventContract newFromAndVisitSchedule(AndVisitSchedule	_visitSchedule)
    {
        var retVal = AndVisitScheduleAddedBusinessEventContract::construct();
        CustTable	     custTable = _visitSchedule.custTable();


        retVal.parmWorker(_visitSchedule.dispWorkerId());
        retVal.parmCustAccount(_visitSchedule.CustAccount);
        retVal.parmCustName(custTable.name());
        retval.parmAddress(custTable.postalAddress().Address);
        retVal.parmVisitDateTime(_visitSchedule.VisitDateTime);		

        return retVal;
    }

    [DataMember('visitdatetime'), BusinessEventsDataMember('visitdatetime')]
    public utcdatetime parmVisitDateTime( utcdatetime _visitDateTime = visitDateTime )
    {
        visitDateTime = _visitDateTime;

        return visitDateTime;
    }

    [DataMember('worker'), BusinessEventsDataMember('worker')]
    public HcmPersonnelNumberId parmWorker( HcmPersonnelNumberId _worker = worker )
    {
        worker = _worker;

        return worker;
    }

    [DataMember('custaccount'), BusinessEventsDataMember('custaccount')]
    public str parmCustAccount( str _custAccount = custAccount )
    {
        custAccount = _custAccount;

        return custAccount;
    }

    [DataMember('custname'), BusinessEventsDataMember('custname')]
    public str parmCustName( str _custName = custName )
    {
        custName = _custName;

        return custName;
    }

    [DataMember('address'), BusinessEventsDataMember('address')]
    public str parmAddress( str _address = address )
    {
        address = _address;

        return address;
    }

    protected void new()
    {
    }

    public static AndVisitScheduleAddedBusinessEventContract construct()
    {
        AndVisitScheduleAddedBusinessEventContract         retVal = new AndVisitScheduleAddedBusinessEventContract();

        return retVal;
    }

}

See that we need to add both data member and “BusinessEventsDataMember” attributes to define the name of the field. Datamember is used in the schema and a fixed string and the business events data member one is used in the setup form descriptions, which you should better use a Label for.

After the contract is created, create your Business event class deriving from the BusinessEventsBase class as shown below:

[BusinessEvents(classStr(AndVisitScheduleAddedBusinessEventContract), "AndVisitScheduleTest: New visit schedule added", "A new And. visit schedule record added", ModuleAxapta::Basic)]
public final class AndVisitScheduleAddedBusinessEvent extends BusinessEventsBase
{
    private AndVisitSchedule andVisitSchedule;

    private AndVisitSchedule parmAndVisitSchedule(AndVisitSchedule _andVisitSchedule = andVisitSchedule)
    {
        andVisitSchedule = _andVisitSchedule;

        return andVisitSchedule;
    }

    protected void new()
    {
        super();
    }

    public static AndVisitScheduleAddedBusinessEvent construct()
    {
        AndVisitScheduleAddedBusinessEvent         retVal = new AndVisitScheduleAddedBusinessEvent();

        return retVal;
    }

    [Wrappable(true), Replaceable(true)]
    public BusinessEventsContract buildContract()
    {
        return AndVisitScheduleAddedBusinessEventContract::newFromAndVisitSchedule(andVisitSchedule);
    }

    public static AndVisitScheduleAddedBusinessEvent newFromAndVisitSchedule(AndVisitSchedule _andVisitSchedule)
    {
        AndVisitScheduleAddedBusinessEvent	andEvent = AndVisitScheduleAddedBusinessEvent::construct();
        andEvent.parmAndVisitSchedule(_andVisitSchedule);

        return andEvent;
    }

}

The BusinessEvents attribute is the place that contains your business event description and the module you want to put it in. Here you should use labels and have a clear description for your event which will be visible in the setup form and event trigger setup in Flow. The code that is executed when your event is send is the “buildContract” method. This method should return the related record via the data contract that is associated with your trigger.

To trigger the event, use the following code in a place you would like the event to triggered. Here I will use the insert method of my visit schedule table :

    public void insert()
    {
        super();

        if (BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(AndVisitScheduleAddedBusinessEvent)))
        {
            AndVisitScheduleAddedBusinessEvent::newFromAndVisitSchedule(this).send();
        }
    }

Now build your project, and go to the Business events setup form. Click on Manage>Rebuild business event catalog and you should see your new business event added to the list :

Testing your new business event

Go to Microsoft Flow and create a new blank flow. From the triggers find the new D365FO “When a Business Event occurs” trigger. Enter your environment name, select the module you set in your business event’s attribute(here in this example, ‘Basic’). And in the list you should see your new business event. Select the company you want to test your event from and that’s it. Now add a new flow step to send a basic e-mail notification to test our event is running and press Save:

As soon as you save your flow in flows editor, D365FO business events should create a new endpoint targeting to that flow and Activate your flow automatically to that endpoint. This function, in the time of writing, do not work very well but in my second tryout I was able to get an automatically created endpoint and activation record :

Now let’s test our flow, I add a new record to my visit schedule table:

And my flow gets successfully executed :

And I get my e-mail from The Microsoft Flow :

How to get data from the flow business event trigger

We have mentioned that in the time of writing this functionality is still in preview. So if I check the Dynamic Content associated with the trigger, I see nothing…
However I was able to access the data of the record that has triggered the event using the Flow’s triggerBody() function.
Go to the business event setup page of your trigger and check the field names there. You can also download a JSON schema here and see the actual JSON field names that will be sent in the body of the trigger payload :

You can directly add those fields to parts of your message as shown below, using custom Flow expressions to inquiry the fields in the trigger body. To do so, select the Expression tab in the flow editor and enter an expression as “triggerBody()?[‘your_field_name’]” :

Update the flow and let’s run another test to see if the fields are coming OK:

Looks just fine..

The only problem I had here is the date time fields. At the time of writing they are being sent in a weird format (like ” /Date(1558692174000)/ “) and not as an ISO standard datetime string. I think this will improve in time but for now a workaround could be converting the datetime field to a ISO string in your data contract and send it as a string.

Hope you find this article useful and enjoy this fresh feature of D365FO.

Comment List
Anonymous
Related
Recommended