Home / Questions / Custom Data Entity OData Action in D365 FO – Explained with Example
Explanatory Question

Custom Data Entity OData Action in D365 FO – Explained with Example

👁 57 Views
📘 Detailed Answer
🕒 Easy to Read
Read the answer carefully and go through the related questions on the right side to improve your understanding of this topic.

Answer with Explanation

In Dynamics 365 Finance & Operations (D365 FO), data integration is a critical requirement for organizations that rely on external systems such as Master Data Management (MDM) tools. A common scenario is when you want to create or update product master data in D365 FO automatically instead of manual entry or file upload.

This is where Custom Data Entity OData Actions come in.


🔹 What is a Custom Data Entity OData Action?

  • A data entity in D365 FO is an abstraction that represents a business object (for example, Customer, Vendor, Item).

  • By default, data entities support CRUD operations via OData (Create, Read, Update, Delete).

  • But sometimes, we need to perform custom business logic during integration that goes beyond standard CRUD.

👉 That’s where a custom OData Action comes in:

  • It is a method (defined in X++) that can be exposed as an API endpoint.

  • You can pass multiple parameters, execute your own logic, and return a result.

Think of it like:
🛠️ “An API hook into your business logic inside D365 FO, built on top of data entities.”



🔹 Example: Finished Goods Integration (PiLog Scenario)

Here’s a simplified view of a custom OData action class:


public class ANSARIPilogFinishedGoodsIntSingleDataEntity extends common
{
    [SysODataAction("processPilog", false), 
     SysODataCollectionAttribute("return", Types::String)]
    public static str processPilog(
        ItemId ITEM,
        Name PRODUCTNAME,
        InventSiteId SITEID,
        InventLocationId WAREHOUSEID,
        EcoResProductDisplayProductNumber PRODUCTNUMBER,
        ItemGroupId PRODUCTGROUPID,
        UnitOfMeasureSymbol PURCHASEUNITSYMBOL,
        UnitOfMeasureSymbol SALESUNITSYMBOL,
        ItemNetWeight NETPRODUCTWEIGHT,
        ItemVolume PRODUCTVOLUME,
        LanguageIdAll LANGUAGE,
        DataAreaId DATAAREAID
    )
    {
        str ret;

        changecompany(DATAAREAID)
        {
            ANSARIPilogFinishedGoodsManager manager = ANSARIPilogFinishedGoodsManager::construct();

            ret = manager.process(
                ITEM,
                PRODUCTNAME,
                SITEID,
                WAREHOUSEID,
                PRODUCTNUMBER,
                PRODUCTGROUPID,
                PURCHASEUNITSYMBOL,
                SALESUNITSYMBOL,
                NETPRODUCTWEIGHT,
                PRODUCTVOLUME,
                LANGUAGE
            );
        }

        return ret;
    }
}


Explanation:


[SysODataAction("processPilog", false), SysODataCollectionAttribute("return", Types::String)]

This is called an attribute declaration. Attributes in X++ are metadata that describe how the class or method should behave, especially in the context of OData services.


1️⃣ SysODataAction("processPilog", false)

This attribute is used to expose a method as a custom OData action.

  • "processPilog" → This is the name of the OData action that external clients (like Power Automate, Power BI, or Postman) can call.

  • false → Indicates whether this action is bound or unbound:

    • true → The action is bound to a specific entity (you call it on a specific record).

    • false → The action is unbound, meaning it can be called independently, not tied to a particular record.

In simple terms:
This method can be invoked via OData using the name processPilog, and it is unbound, so it can run without referencing a specific record.


2️⃣ SysODataCollectionAttribute("return", Types::String)

This attribute specifies what the method returns for OData clients.

  • "return" → Indicates the output property of the OData action.

  • Types::String → The data type of the return value, in this case, a string.

  • Essentially, this tells OData that this action returns a collection of strings (or a string type in the response).


🔹 How It Works

  1. External System (PiLog or any MDM tool) sends product details using API call.

  2. The API hits the OData action processPilog.

  3. The method switches to the correct company (legal entity) using changecompany(DATAAREAID).

  4. Calls a manager class (ANSARIPilogFinishedGoodsManager) that:

    • Validates data.

    • Creates or updates product in EcoResProduct, InventTable, etc.

    • Applies business rules.

  5. Returns a status message like “SUCCESS: Item created” or “ERROR: Missing dimension group”.


🔹 Why Do We Need This?

  • Standard DMF entities only handle raw insert/update.

  • They don’t apply all your company-specific business rules.

  • For example:

    • Validate whether warehouse and site combination is valid.

    • Ensure a specific product group is assigned.

    • Apply default planning parameters.

👉 That’s why a custom OData action is required — it ensures real-time integration while keeping business rules intact.


🔹 Real-Life Example: API Call

Request (JSON):


{
  "ITEM": "FG-1001",
  "PRODUCTNAME": "Ansari Tea Pack",
  "SITEID": "USMF",
  "WAREHOUSEID": "MAIN",
  "PRODUCTNUMBER": "TEA001",
  "PRODUCTGROUPID": "TEA",
  "PURCHASEUNITSYMBOL": "EA",
  "SALESUNITSYMBOL": "EA",
  "NETPRODUCTWEIGHT": 1.2,
  "PRODUCTVOLUME": 0.5,
  "LANGUAGE": "en-us",
  "DATAAREAID": "USMF"
}

Response:


{
  "value": "SUCCESS: Item FG-1001 created in USMF"
}


OData action from Postman

Let’s go step by step to call your processPilog OData action from Postman. I’ll explain it clearly so you can try it directly.


1️⃣ OData Action Endpoint

Since your class is:

public class ANSARIPilogFinishedGoodsIntSingleDataEntity extends common

and your method is:

[SysODataAction("processPilog", false)]

The OData URL to call the action will be:

POST https:///data/ANSARIPilogFinishedGoodsIntSingleDataEntity/processPilog
  • Replace with your environment URL, e.g.:

https://mycompany.operations.dynamics.com/data/ANSARIPilogFinishedGoodsIntSingleDataEntity/processPilog
  • POST method is used because OData actions are executed with POST.

2️⃣ Headers

In Postman, add the following headers:

Key Value
Authorization Basic or OAuth token
Content-Type application/json
Accept application/json

Note: In D365 F&O, authentication can be OAuth2 (Azure AD app) or Basic auth (username/password for testing).


3️⃣ Body

Set Postman to raw JSON and use POST body like this:

 

{
  "ITEM": "FG001",
  "PRODUCTNAME": "Product A",
  "SITEID": "NY",
  "WAREHOUSEID": "WH1",
  "PRODUCTNUMBER": "P123",
  "PRODUCTGROUPID": "Group1",
  "PURCHASEUNITSYMBOL": "PCS",
  "SALESUNITSYMBOL": "PCS",
  "NETPRODUCTWEIGHT": 2.5,
  "PRODUCTVOLUME": 1.2,
  "LANGUAGE": "en-us",
  "DATAAREAID": "USMF"
}

  • Each key matches your method parameters.

  • Make sure the data types match: strings for IDs/names, numbers for weight/volume.


4️⃣ Send Request

  1. Click Send in Postman.

  2. If everything is correct, you should see a response like:


{
  "return": "Processed successfully"
}
or


{
  "value": "SUCCESS: Item FG-1001 created in USMF"
}
  • This string comes from your manager.process(...) method in the class.


5️⃣ Common Errors

Error Cause Solution
401 Unauthorized Wrong auth Check OAuth token or username/password
404 Not Found Wrong URL Check class name & environment URL
400 Bad Request JSON mismatch Make sure body keys exactly match method parameters
500 Server Error Logic issue Check ANSARIPilogFinishedGoodsManager.process method

Summary Flow in Postman

  1. URL: POST /data/ANSARIPilogFinishedGoodsIntSingleDataEntity/processPilog

  2. Headers: Authorization, Content-Type, Accept

  3. Body: JSON with all parameters

  4. Send → Get the string result