April 09, 2025

How to trigger Business event using x++ code

Hi Folks, 

I recently faced issue where PO confirmation business event was not triggering and failing my interface. Issue was whenever after first PO confirmation if user make change to PO header delivery date or cancellation date  and reconfirm the PO, it wont trigger the respective Business event. 

[Although there are different reason why business event is not considering this change, while if I make any financial changes like qty, line addition, tax etc, it works fine]

Ok lets see now how I can call a business event from code, 

To trigger a business event in X++ code, you need to create a business event contract, an event handler class, and then trigger the event from your X++ code by using the BusinessEvent::newFromTable() and businessEvent.send() methods. (Also,  configure the event in the business event catalog if its not configured)

1. Create a Business Event Contract:
Purpose: Defines the data that will be sent with the business event. For reference check  CustFreeTextInvoicePostedBusinessEventContract.


 2. Create an Event Handler Class:
Purpose: Handles the event when it's triggered, allowing you to perform actions based on the event.
For reference check CustTable_BusinessEvent_EventHandler

3. Trigger the Business Event from X++ Code:
Purpose: Use the BusinessEvent::newFromTable() and businessEvent.send() methods to trigger the event.


here is complete code sample, 





-Harry Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

March 17, 2025

Update admin user in Dev box

Old is gold,


MS removed admin user provising tool, but there is an old way where you can still add your user as admin, 

Go to the VM and open SQL management Studio, 

Step 1: Find admin user rec id in USERINFO table, 

select  * from USERINFO

Step 2: Get SID from earlier Database for your user

select  * from USERINFO
where RECID = 53755554576


Step 3: Update new Database with below query 

update USERINFO
set NETWORKALIAS = 'deepak.agarwal@theaxapta.com',
sid = 'S-1-19-18-####-####-####5192'
where RECID = 53755554576


Make sur eof choosing right Database of each query and use the right recid and other values. 


-Harry Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

January 24, 2025

Custom web service in D365FO - Part-I

Introduction

Custom services in Dynamics 365 Finance and Operations (D365FO) allow you to expose custom business logic and data to external systems. This first part of the blog post will walk you through the basics of creating and consuming custom services in D365FO. Custom services are used to expose X++ business logic to external systems via SOAP or RESTful endpoints. They are ideal for scenarios where you need to implement complex business processes that are not covered by standard services.

In later posts, we will discuss some complex scenarios and best practices around web services.

Architecture

Service Request Contract

The service contract defines the operations that the service will expose. This is done by creating a new class with the [DataContractAttribute] and [DataMemberAttribute] attributes. There must be two contract classes: one for the request message and another for the response message. (We will cover this in detail in future posts).

Example:

[DataContractAttribute]
public class TheAxaptaRequestContract
{
    private boolean isShipped;
    private String255 dataAreaId;
    private String255 storeNumber;
    private String255 trackingNumber1;

    [DataMember("TrackingNumber1")]
    public String255 parmTrackingNumber1(String255 _trackingNumber1 = trackingNumber1)
    {
        trackingNumber1 = _trackingNumber1;
        return trackingNumber1;
    }

    [DataMember("IsShipped")]
    public boolean parmIsShipped(boolean _isShipped = isShipped)
    {
        isShipped = _isShipped;
        return isShipped;
    }

    [DataMember("DataareaId")]
    public String255 parmdataAreaId(String255 _dataAreaId = dataAreaId)
    {
        dataAreaId = _dataAreaId;
        return dataAreaId;
    }

    [DataMember("StoreId")]
    public String255 parmStoreNumber(String255 _storeNumber = storeNumber)
    {
        storeNumber = _storeNumber;
        return storeNumber;
    }
}

Service Response Contract

Example:

[DataContractAttribute]
public class TheAxaptaResponseContract
{
    private boolean success;
    private str errorMessage;
    private str debugMessage;
    private System.String salesOrder;

    [DataMember("Message")]
    public str parmMessage(str _value = errorMessage)
    {
        if (!prmIsDefault(_value))
        {
            errorMessage = _value;
        }

        return errorMessage;
    }

    [DataMember("Success")]
    public Boolean parmSuccess(Boolean _value = success)
    {
        if (!prmIsDefault(_value))
        {
            success = _value;
        }

        return success;
    }

    [DataMember("DebugMessage")]
    public str parmDebugMessage(str _value = debugMessage)
    {
        if (!prmIsDefault(_value))
        {
            debugMessage = _value;
        }

        return debugMessage;
    }
}

Service Class

This is the class where the actual business operation executes. It takes the request message from the respective contract class and processes it to create a response message. Create a new class to implement the service. This class should extend the SysOperationServiceBase class and include the business logic for the service operations.

Example:

public class TheAxaptaService extends SysOperationServiceBase
{
    TheAxaptaResponseContract response = new TheAxaptaResponseContract ();
[AifCollectionType('salesOrder', Types::Class, classStr(TheAxaptaRequestContract)),
AifCollectionType('return', Types::Class, classStr(TheAxaptaResponseContract ))]
public processMsg() { TheAxaptaRequestContract request;
// Now you can access the parm methods of the request class to get different values from the request Str StoreId = request.paramStoreNumber(); response.parmSuccess(True); response.parmMessage("Message read"); } }

Register the Service

Register the service in the AOT (Application Object Tree) by creating a new service node. Set the class and method properties to point to your service implementation.

  1. In the AOT, right-click Services and select New Service. (e.g. TheAxaptaInterface)
  2. Set the Class property to your service class (e.g., TheAxaptaService).
  3. Set the Method property to the service method (e.g., processMsg).

Deploy the Service

Deploy the service to make it available for consumption. This can be done by right-clicking the service node in the AOT and selecting Deploy Service Group.

Consume the Service

A third part can consume this service using the below syntax

<EnvironmentURL>/API/services/TheAxaptaInterface/TheAxaptaService/processMsg

and send the request message in body.

If you want to setup postman to test your services by yourself, I would recommend to checkout this blog post, 

Here is complete code uploaded on Git Repository