Monday, November 2, 2026

Custom services in d365fo

 In this blog we see how to develop custom services in d365fo

Mainly we need to develop

1) Request class

2) Response class 

3) service class 

4) service object

5) servicegroup object

Note:-Its not mandatory to have every time request class or response class it depends on the requirement, Sometimes we create multiple Request classes and multiple Response class if we have line to loop then we pass in a list with class attribute.

Here we see a scenario with Request class , Response class

I  am here considering Purchase order information when we pass a purchid and dataareaid

classes:-

PurchaseorderHeaderResponseContract

PurchaseorderLineResponseContract

PurchaseorderRequestContract

PurchaseorderService

Objects

1) Service

2) service group

Code:-

1) PurchaseorderRequestContract

[DataContractAttribute]

 class PurchaseorderRequestContract

{

    public str purchid;

    public str dataAreaId;


    [DataMember("PurchId")]

    public str parmPurchId(str _purchid = purchid)

    { 

        purchid = _purchid;

        return purchid;

    }


    [DataMember("DataAreaId")]

    public str parmDataAreaId(str _dataAreaId = dataAreaId)

    {

        dataAreaId = _dataAreaId;

        return dataAreaId;

    }


}

2) PurchaseorderHeaderResponseContract


[DataContractAttribute]

class PurchaseorderHeaderResponseContract

{

    public str purchid;

    public str vendoraccount;

    public str vendorname;

    List purchlines;


    [DataMember("PurchId")]

    public str parmPurchId(str _purchid = purchid)

    {

        purchid = _purchid;

        return purchid;

    }


    [DataMember("Vendoraccount")]

    public str parmVendoraccount(str _vendoraccount = vendoraccount)

    {

        vendoraccount = _vendoraccount;

        return vendoraccount;

    }


    [DataMember("Vendorname")]

    public str parmVendorname(str _vendorname = vendorname)

    {

        vendorname = _vendorname;

        return vendorname;

    }


    [DataMemberAttribute('Purchlines'),

     AifCollectionTypeAttribute(

        '_purchlines',

        Types::Class,

        classStr(PurchaseorderLineResponseContract)),

     AifCollectionTypeAttribute(

        'return',

        Types::Class,

        classStr(PurchaseorderLineResponseContract))]

    public List parmPurchlines(List _purchlines = purchlines)

    {

        purchlines = _purchlines;

        return purchlines;

    }


}

3)PurchaseorderLineResponseContract

[DataContractAttribute]

 class PurchaseorderLineResponseContract

{

    public str purchid;

    public str lineNumber;

    public str itemId;

    public str lineAmount;

   


    [DataMember("PurchId")]

    public str parmPurchId(str _purchid = purchid)

    {

        purchid = _purchid;

        return purchid;

    }


    [DataMember("LineNumber")]

    public str parmLineNumber(str _lineNumber = lineNumber)

    {

        lineNumber = _lineNumber;

        return lineNumber;

    }


    [DataMember("ItemId")]

    public str parmItemId(str _itemId = itemId)

    {

        itemId = _itemId;

        return itemId;

    }


    [DataMember("LineAmount")]

    public str parmLineAmount(str _lineAmount = lineAmount)

    {

        lineAmount = _lineAmount;

        return lineAmount;

    }


}

4) PurchaseorderService

class PurchaseorderService

{

    public PurchaseorderHeaderResponseContract purchaseorderinfo(PurchaseorderRequestContract _purchaseorderRequestContract)

    {

        PurchaseorderHeaderResponseContract purchaseorderHeaderResponseContract=new PurchaseorderHeaderResponseContract();

        PurchaseorderLineResponseContract purchaseorderLineResponseContract;


        str                    purchid = _purchaseorderRequestContract.parmPurchId();

        str                    dataareaid = _purchaseorderRequestContract.parmDataAreaId();

        PurchTable             purchTable;

        PurchLine              purchLine;

        List                   purchlines=new List(Types::Class);


        select  firstonly crosscompany purchTable

            where purchTable.PurchId == purchid

            && purchTable.DataAreaId == dataareaid;


        purchaseorderHeaderResponseContract.parmPurchId(purchTable.PurchId);

        purchaseorderHeaderResponseContract.parmVendoraccount(purchTable.OrderAccount);

        purchaseorderHeaderResponseContract.parmVendorname(purchTable.PurchName);

        

        while select crosscompany purchLine

            where purchLine.PurchId == purchid

            && purchLine.DataAreaId == dataareaid

        {

            purchaseorderLineResponseContract=new PurchaseorderLineResponseContract();

            purchaseorderLineResponseContract.parmPurchId(purchLine.PurchId);

            purchaseorderLineResponseContract.parmLineNumber(any2Str(purchLine.LineNumber));

            purchaseorderLineResponseContract.parmItemId(purchLine.ItemId);

            purchaseorderLineResponseContract.parmLineAmount(any2Str(purchLine.LineAmount));

           


            purchlines.addEnd(purchaseorderLineResponseContract);

        }

        purchaseorderHeaderResponseContract.parmPurchlines(purchlines);


        return purchaseorderHeaderResponseContract;

    }


}

Now create a service object and service group and give classname, methodname 

To test generally go with Postman

and API link will be:-

generally 

D365url/api/services/ServiceGroup/Service/method


sample:-

https://usnconeboxax1aos.cloud.onebox.dynamics.com/api/services/PruchaseorderServiceGroup/PurchaseorderService/purchaseorderinfo


Note to test in postman one need appregistration that you can follow as below

Inside D365FO with Mani: Odata

Add a attchment for docuref

 Scenario :-

I have case where I need to attach base64(huge string which is convert from file) through custom services

>>So in the pam methods I will receive the string .

>> And code to attachment in below

Code:-

Docuref docuref;

 str fileName="test.pdf";

str notes="tesing";

str base64="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

using (System.IO.MemoryStream Stream = new System.IO.MemoryStream(System.Convert::FromBase64String(base64)))

{ 

   docuref=DocumentManagement::attachFile(tableNum(Tablename),Table.RecId,Table.DataAreaId,DocuType::typeFile(),Stream, System.IO.Path::GetFileName(fileName),System.Web.MimeMapping::GetMimeMapping(fileName), System.IO.Path::GetFileNameWithoutExtension(fileName),notes);

}

If you stream file we can directly pass in the above logic.

Friday, October 30, 2026

get workflow message through code

 WorkflowTrackingStatusTable wfTrackingTable;

 WorkflowTrackingTable       wfTracking;


 select firstonly wfTrackingTable

     order by wfTrackingTable.CreatedDateTime desc

             where wfTrackingTable.ContextTableId == tablenum(tablename)

             && wfTrackingTable.ContextRecId   == _purchTable.RecId;


 select firstonly   wfTracking

         order by wfTracking.CreatedDateTime asc

         where wfTracking.WorkflowTrackingStatusTable == wfTrackingTable.RecId

            && wfTracking.TrackingType == WorkflowTrackingType::Approval

             && wfTracking.TrackingContext==WorkflowTrackingContext::WorkItem


info(wfTracking.commentTable().getLocalizeTrackingMessage());

Monday, September 21, 2026

computed column in Dataentity

synatx:-  

public static server str methodname()

  {
      str purchid=SysComputedColumn::returnField(dataentityviewstr(Dataentityname),dataEntityDataSourceStr(Dataentityname,Datasourcename),fieldStr(Datasourcename,fieldname));

      return strFmt(@'SELECT TOP 1 from tablename where tablename.fieldname=%1',purchid);


Note:-For lengthy sql stmts dont write direclty here it will show huge errors so pls write first huge sql stmts in SSMS then confirm data correctly then paste in above return statement
--------------------------------------------------------
     To declare a string use SysComputedColumn::returnLiteral('string value');

Wednesday, August 5, 2026

Get enumvalues through sql

 Generally in AOT sometimes we can not see tthe basenum values in properties so here is the query which helps 

SELECT
    EIT.NAME AS EnumName,
    EVT.ENUMVALUE,
    EVT.NAME AS EnumElement
FROM ENUMIDTABLE EIT
INNER JOIN ENUMVALUETABLE EVT
    ON EVT.ENUMID = EIT.ID
WHERE EIT.NAME = 'YourBaseenum'
ORDER BY EVT.ENUMVALUE;

Thursday, July 30, 2026

Get workflow firstApprover and firstapproval datetime through code

  WorkflowTrackingStatusTable wfTrackingTable;

 WorkflowTrackingTable       wfTracking;


 select firstonly wfTrackingTable

     order by wfTrackingTable.CreatedDateTime desc

             where wfTrackingTable.ContextTableId == tablenum(tablename)

             && wfTrackingTable.ContextRecId   == _purchTable.RecId;


 select firstonly   wfTracking

         order by wfTracking.CreatedDateTime asc

         where wfTracking.WorkflowTrackingStatusTable == wfTrackingTable.RecId

            && wfTracking.TrackingType == WorkflowTrackingType::Approval

             && wfTracking.TrackingContext==WorkflowTrackingContext::WorkItem;


 Date POApprovalDate = DateTimeUtil::date(wfTracking.CreatedDateTime);

 str POApprovedBy   = HcmWorker::find(HcmWorker::userId2Worker(wfTracking.user)).name();

Sunday, July 19, 2026

Get base enum lables insted enum ids in SSRS report

Generally in ssrs report to get baseenum labels instead basenum element id , we can do that in two ways

Way1) Take a  string field in Tmp table and make enum2str and assign.

Way2) In expressions generally we get for basenums =Fields!BaseenumName.Value now change it to 
Fields!BaseenumLabel.Value 
==> build it and check it.

Custom services in d365fo

 In this blog we see how to develop custom services in d365fo Mainly we need to develop 1) Request class 2) Response class  3) service class...