Enable Business Events using Power Automate in Microsoft Dynamics 365 for Finance and Operations - Part 2/2 Series

Visit Website View Our Posts

Approval for Free Text Invoice using Business Events

In this section, we will discuss a use case scenario and how we can achieve it using Business events. The use case is whenever a customer free text invoice is generated, it will be sent to the manager for approval. The workflow used in this section is out-of-the-box Customer free text invoice workflow, which is used with Business events for approval. By using Business events, the manager can directly approve or reject the workflow from his/her email or from Microsoft teams. The manager can also add comments which will be brought to D365 F&O.

To begin, we will first configure the workflow for customer free text invoices, configure business events, and then use Power Automate to achieve our requirement.

Configure New Workflow for Customer Free Text Invoice

  • Go to Accounts receivable -> Setup -> Accounts receivable workflows and click New to create a new workflow.
  • You will see the list of workflow options available. Click on Customer free text invoice workflow.

  • The system will notify you about opening a file. Click OK. This will open the workflow designer form. If you are doing this for the first time, it will ask you to download the workflow designer application first.

  • It will ask for credentials. Enter your credentials.

  • Once the designer is loaded. Drag Approval free text invoice to the right pane and connect Start and End nodes with it.

  • Double click on the Approval free text invoice element and click on Click on properties to open the required configuration.

  • Go to the Assignment tab and select User on the Assignment type tab. On the User tab, add the required user to the Selected user list. This user will be the Approver for your workflow approvals.

  • Close properties screen and Click on the Save and close button on the bottom right corner. Provide version comments and click Ok.
  • You will see the new workflow created on the screen.

Configure Business Event for Customer Free Text Workflow

  • Go to System administration -> Setup -> Business events -> Business events catalog. You will see the list of business events here.

  • Filter for Workflow_CustFreeTextInvoiceTemplate_000299_CustFreeTextApproval_WorkItem Business event ID.

  • On the right side, you will see the fields that are passed when this business event is triggered. You need to parse these fields with JSON payload. Click on Download schema on the right side to download JSON sample file.

  • Keep the JSON file that is downloaded. We will use it later.

Create New Flow in Power Automate

  • Click on My flows. On the My Flows screen, click on New flow and select Automated cloud flow from the list.

  • Enter a name for the flow and Choose your flow’s trigger, select When a Business Event occurs (you can find this by typing “fin” in the search box), and click Create button below.

  • On flow editor, follow the below steps to configure it for approval.
    • When a business event occurs
      • Instance: Enter the target environment name. You will see a list of D36 F&O instances here
      • Category: Workflow workitem
      • Business event: Customer free text invoice workflow (000299) – Approve free text invoice
      • Legal entity: Legal entity you need to perform an action

  • Click on the +New step to add a new step to the flow. On Choose an operation, type “Parse JSON” in the search text and click on Parse JSON.

  • Select body in the content text box and click on Generate from Sample. Copy the text from the JSON file that you downloaded in the previous step here and click Done. You will see the JSON schema generated based on sample data.

  • Similarly, add a new step by clicking +New step and type and select “Start and wait for an approval” and add the below details.
    • Start and wait for an approval
      • Approval type: Approve/Reject – First to respond
      • Title: WorkflowWorkitemSubject (Select from Dynamic content)
      • Assigned to: WorkflowUserEmail (Select from Dynamic content)
      • Details: WorkflowWorkItemSubject (Select from Dynamic content)

  • Now add Apply to each step by clicking on New step, add Execute an action step inside the Apply to each step, and add below details.
    • Apply to each
      • Select an output from previous steps: Responses (Select from Dynamic content)
    • Execute an action:
      • Instance: Select instance name
      • Action: WorkflowWorkItem-Complete
      • WorkflowWorkItemInstanceId: WorkflowWorkItemInstanceId (Select from Dynamic content)
      • Outcome: Outcome ((Select from Dynamic content)
      • Comment: Responses comments (Select from Dynamic content)
      • TargetUser: WorkItemOwner (Select from Dynamic content)
      • RunAsUser: WorkItemOwner (Select from Dynamic content)

The flow configuration is completed, and it is ready for testing.

Custom Business Events

Overview

In this section, we will discuss a custom business event. As a use case scenario, we have considered the Customer credit limit which will go for approval, if there is any change. The requirement is when a customer's credit limit is changed, the customer will go On Hold until the new credit limit gets approved by the approver. We will use a similar kind of approach as we used previously, and we will create a custom business event to trigger it on credit limit change.

To create a custom business event, we need to create two classes: one is an actual business event, and another is a contract class that will pass fields data while triggering the event.

Let’s create two classes for custom business events.

Contract Class for Business Event

Contract class should extend BusinessEventContract class and has [DataContract] attribute on class and [DataMember] and [BusinessEventDataMember] attribute on each method.

Below is the code for contract class

[DataContract]
class CustomerCreditLimitBusinessEventContract extends BusinessEventsContract
{
private CustAccount         custAccount;
private CustName            custName;
private CreditMaxCur        prevCreditLimit, newCreditLimit;
private CustGroupId         custGroupId;
private CustCurrencyCode    currencyCode;
public static CustomerCreditLimitBusinessEventContract construct()
{
var contract = new CustomerCreditLimitBusinessEventContract();
return contract;
}
[DataMember('CustAccount'), BusinessEventsDataMember("@SYS7149")]
public LegalEntityDataAreaId parmCustAccount(CustAccount _custAccount = custAccount)
{
custAccount = _custAccount;
return custAccount;
}
[DataMember('CustName'), BusinessEventsDataMember("Customer name")]
public CustName parmCustName(CustName _custName = custName)
{
custName = _custName;
return custName;
}
[DataMember('PrevCreditLimit'), BusinessEventsDataMember("Previous credit limit")]
public CreditMaxCur parmPrevCreditLimit(CreditMaxCur _prevCreditLimit = prevCreditLimit)
{
prevCreditLimit = _prevCreditLimit;
return prevCreditLimit;
}
[DataMember('NewCreditLimit'), BusinessEventsDataMember("New credit limit")]
public CreditMaxCur parmNewCreditLimit(CreditMaxCur _newCreditLimit = newCreditLimit)
{
newCreditLimit = _newCreditLimit;
return newCreditLimit;
}
[DataMember('CustGroupId'), BusinessEventsDataMember("@SYS11904")]
public CustGroupId parmCustGroupId(CustGroupId _custGroupId = custGroupId)
{
custGroupId = _custGroupId;
return custGroupId;
}
[DataMember('CurrencyCode'), BusinessEventsDataMember("@SYS7572")]
public CustCurrencyCode parmCurrencyCode(CustCurrencyCode _currencyCode = currencyCode)
{
currencyCode = _currencyCode;
return currencyCode;
}

}

Main Class for Business Event

The main class should extend BusinessEventsBase class and should have the [BusinessEvents] attribute. There are four parameters passed in these attribute classes:

  1. Contract class name for business event
  2. Label for business event
  3. Description for business event
  4. Module for business event

The class should also override buildContract method as this is abstract and will use this method to build contract data.

Below is the code for the main business event class

[
BusinessEvents(classStr(SI_CustomerCreditLimitBusinessEventContract), 'SI:EventLabel', 'SI:EventDescription', ModuleAxapta::SalesAndMarketing)
]
class SI_CustomerCreditLimitBusinessEvent extends BusinessEventsBase
{
private CustTable       custTable;
private CreditMaxCur    prevCreditMax;
public static SI_CustomerCreditLimitBusinessEvent construct(CustTable _custTable, CreditMaxCur _prevCreditMax)
{
var event = new SI_CustomerCreditLimitBusinessEvent();
event.parmCustTable(_custTable);
event.parmPrevCreditLimit(_prevCreditMax);
return event;
}
public BusinessEventsContract buildContract()
{
var contract = SI_CustomerCreditLimitBusinessEventContract::construct();
contract.parmCustAccount(custTable.AccountNum);
contract.parmCustName(custTable.name());
contract.parmPrevCreditLimit(prevCreditMax);
contract.parmNewCreditLimit(custTable.CreditMax);
contract.parmCustGroupId(custTable.CustGroup);
contract.parmCurrencyCode(custTable.Currency);
return contract;
}
public CustTable parmCustTable(CustTable _custTable = custTable)
{
custTable = _custTable;
return custTable;
}
public CreditMaxCur parmPrevCreditLimit(CreditMaxCur _prevCreditMax = prevCreditMax)
{
prevCreditMax = _prevCreditMax;
return prevCreditMax;
}
private void new()
{
}
}

Trigger Point for Business Event

Once the contract and main class are developed, we need to add a trigger point. Based on our requirement, this event should trigger when a credit limit for the customer is changed. Hence, we will add this code for customer update and check if the credit limit is changed and the business event is enabled.

Below is the code developed using COC of CustTable table.

[ExtensionOf(tableStr(CustTable))]
final class SICustTable_Extension
{
public void update(boolean _updateSmmBusRelTable, boolean _updateParty)
{
CustTable   custTable_orig = this.orig();
boolean     triggerBusinessEvent;
if (this.CreditMax != custTable_orig.CreditMax
&& BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(SI_CustomerCreditLimitBusinessEvent)))
{
this.Blocked = CustVendorBlocked::All;
Info("Customer is on hold due to credit limit changes. Please ask sales manager for approval to remove customer hold.");
triggerBusinessEvent = true;
}
next update(_updateSmmBusRelTable, _updateParty);
if (triggerBusinessEvent)
{
SI_CustomerCreditLimitBusinessEvent::construct(this, custTable_orig.CreditMax).send();
}
}
}

We have checked if the credit limit is changed, and the business event is enabled. We are also putting a customer block, so no one can use this until approval.

Action to Remove Hold from Customer

The OData action is only accessible in Power Automate if it is written inside the Data entity. To add new OData action, you need to create a new data entity, so you can add our OData action. You can also use the out-of-the-box CustomersV3 data entity to update the Blocked field data.

The OData action should have the [SysODataAction] attribute and you need to pass the name of the OData action. This name will be available on Power Automate.

Create new data entity and add below code for OData action.

[SysODataAction('removeCustomerHold', false)]
public static void removeCustomerHold(CustAccount _custAccount, DataAreaId _dataAreaId)
{
CustTable   custTable;
changecompany (_dataAreaId)
{
custTable = CustTable::find(_custAccount, true);
ttsbegin;
custTable.Blocked = CustVendorBlocked::No;
custTable.update();
ttscommit;
}
}

Check Custom Business Event

After building and syncing, the custom business event should have been added to the business catalog. You can verify the same by navigating the below path

System administration -> Setup -> Business events -> Business catalog

Filter business event that we have created. You can see the Fields passed to the event section will have all the parameters that we have added on contract data members.

Note: The business event catalog is built during database synchronization at the time of deployment. Therefore, users should see the complete list of business events in the catalog. However, if an explicit update of the catalog is required, you can select Manage > Rebuild business events catalog. The category of a business event identifies its source. Business events that originate from the workflow system are assigned to the Workflow category. For business events that originate from other modules, the module name is used as the category name.

Download the payload file by clicking the Download Schema button.

Create Flow to use Custom Business Event

Follow the same step to create an automated flow that we did earlier. We have created a new flow named Customer credit limit change. Follow the below steps to configure.

  • Enter the following details on When a Business event occurs
    • When Business Event occurs
      • Instance: Select instance name
      • Category: Sales and marketing (We have assigned this category to our business event in Business Events to attribute while building the main class.
      • Business event: Name of custom business event (If you can’t see it in list, type the full name, and check if works)
      • Legal entity: Target legal entity

  • Add a new step to parse the JSON, like you did in the previous flow to retrieve data from JSON. Select body from Dynamic content and click on Generate from file to generate JSON schema. Copy sample JSON that you have generated previously for custom business events.

  • Add Start and wait for an approval step and add the below steps.
    • Start and wait for an approval
      • Approval type: Approve/Reject – First to respond
      • Title: Title that should be shown on the approval screen
      • Assigned to: Email id of the approver
      • Details: Details that you need to show to the approver

  • Add new step for Execute an action and pass required customer Id and company to remove the hold. We will select the Action that we created to remove the hold from the customer. When you select Action, you will see new fields are added below to pass values to perform the action.
    • Execute action
      • Instance: Select instance name
      • Action: Select action that we have generated to remove the hold from the customer
      • _custAccount: CustomerAccount (Select from Dynamic content)
      • _dataAreaId: Target Legal entity

The flow is complete, and the functionality is ready for testing.

About Synoptek

Synoptek is a business and technology consulting firm that helps organizations envision, transform, and evolve. As a global systems integrator and managed technology services provider, we partner with organizations worldwide to help them navigate the ever-changing technology landscape and build solid foundations for their business.

 

About the Author - Nilesh Rajput

Nilesh Rajput is a Senior Software Engineer, Microsoft Dynamics AX/D365 F&O at Synoptek with over 5 years of experience. He has expertise in Core level customizations, SSRS reports, and Third-party integrations. He has majorly worked in Finance and Supply chain management.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Show Buttons
Hide Buttons