Implementing Custom Business Events in D365FO – Part 1 (Employee Termination Example)

  

What Are Business Events?



Business Events are notifications that Dynamics 365 Finance & Operations can send externally when specific conditions occur. They are part of Microsoft’s event-driven architecture and can be consumed by:

  • Azure Service Bus

  • Microsoft Power Automate

  • HTTPS endpoints

  • Logic Apps

  • And more


Why Use Business Events in D365FO?

Business Events are ideal for real-time, loosely-coupled integrations. Key advantages include:

✅ 1. Real-Time Notifications

Instead of relying on batch jobs or manual triggers, Business Events fire automatically when a business process occurs (e.g., sales order invoicing).

✅ 2. Low-Code / No-Code Integration

They can easily connect to:

  • Power Automate

  • Azure Logic Apps

  • HTTP endpoints

  • Azure Service Bus

This allows faster integration with minimal custom development.

✅ 3. Decoupled Architecture

The source system (D365FO) doesn’t need to know anything about the target system — it just emits the event. This reduces complexity and improves reliability.

✅ 4. Supported and Scalable

Microsoft provides native support with tools for monitoring, retrying, and managing failures. Business Events are ready for enterprise-scale scenarios.


Implementing a Business Event

The process for implementing and sending a business event is straightforward:

  1. Build the contract.

  2. Build the event.

  3. Add code to send the event.

Required Classes

  • Business Event Class – Extends BusinessEventsBase and defines metadata, payload building, and sending logic.

  • Business Event Contract Class – Extends BusinessEventsContract and defines the payload structure.

Example 
Scenario: Trigger a Business Event whenever an employee is terminated.

Step 1 – Build the Contract

[DataContract]
public final class DemoWorkerTerminateBusinessEventContract extends BusinessEventsContract
{
    private HcmPersonnelNumberId empID;
    private Name empName;

    public static DemoWorkerTerminateBusinessEventContract newFromHcmWorker(HcmWorker _hcmWorker)
    {
        var contract = new DemoWorkerTerminateBusinessEventContract();
        contract.initialize(_hcmWorker);
        return contract;
    }

    [DataMember('PersonnelNumber'), BusinessEventsDataMember("Employee ID")]
    public HcmPersonnelNumberId parmPersonnelNumber(HcmPersonnelNumberId _empID = empID)
    {
        empID = _empID;
        return empID;
    }

    [DataMember('EmpName'), BusinessEventsDataMember("Employee Name")]
    public Name parmEmpName(Name _empName = empName)
    {
        empName = _empName;
        return empName;
    }

    private void initialize(HcmWorker _hcmWorker)
    {
        empID   = _hcmWorker.PersonnelNumber;
        empName = _hcmWorker.name();
    }
}

Step 2 – Define the Business Event Class

[BusinessEvents(classStr(DemoWorkerTerminateBusinessEventContract),
    "Employee is terminated",
    "Triggered when an employee is terminated",
    ModuleAxapta::HumanResource)]
public class DemoWorkerTerminateBusinessEvent extends BusinessEventsBase
{
    private HcmWorker hcmWorker;

    public static DemoWorkerTerminateBusinessEvent newFromHcmWorker(HcmWorker _hcmWorker)
    {
        DemoWorkerTerminateBusinessEvent businessEvent = new DemoWorkerTerminateBusinessEvent();
        businessEvent.parmHcmWorker(_hcmWorker);
        return businessEvent;
    }

    private HcmWorker parmHcmWorker(HcmWorker _hcmWorker = hcmWorker)
    {
        hcmWorker = _hcmWorker;
        return hcmWorker;
    }

    public BusinessEventsContract buildContract()
    {
        return DemoWorkerTerminateBusinessEventContract::newFromHcmWorker(hcmWorker);
    }
}

Step 3 – Add Code to Send the Event

public class HcmWorkerTerminationEH
{
    [PostHandlerFor(classStr(HcmWorkerTerminationOffboardingEventHandler), 
        staticMethodStr(HcmWorkerTerminationOffboardingEventHandler, HcmWorkerTermination_workerTerminated))]
    public static void HcmWorkerTerminationOffboardingEH_Post_HcmWorkerTerminated(XppPrePostArgs args)
    {
        HcmWorkerRecId workerRecId = args.getArg(1); // first parameter from original method

        if (BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(DemoWorkerTerminateBusinessEvent)))
        {
            HcmWorker worker = HcmWorker::find(workerRecId);
            DemoWorkerTerminateBusinessEvent::newFromHcmWorker(worker).send();
        }
    }
}



Now go to the System administration > Setup > Business event > Business event catalog form and   rebuild the business event catalog button.

Once that is done we see our custom business event in the form

Example JSON Payload

{ "BusinessEventId": "", "BusinessEventLegalEntity": "", "ContextRecordSubject": "", "ControlNumber": 0, "EmpName": "", "EventId": "", "EventTime": "/Date(-2208988800000)/", "EventTimeIso8601": "1900-01-01T00:00:00Z", "InitiatingUserAADObjectId": "{00000000-0000-0000-0000-000000000000}", "MajorVersion": 0, "MinorVersion": 0, "ParentContextRecordSubjects": null, "PersonnelNumber": "" }

Next Steps

In Part 2, we’ll cover configuring the Business Event endpoint with Power Automate.
Since I’m using the Microsoft demo lab, I can’t configure this custom BE endpoint, but I’ll show an example using a standard Business Event.


Comments