hljs.configure({cssSelector: "code"}); hljs.highlightAll();

Tuesday, November 28, 2023

Upload image file in form grid using X++ in D365FO

  In this blog we are going to Learn how to add a simple button for users to upload signature images to specific records in a grid.

Form design:





Design details:

Data model changes:

1. Add container field with EDT as BitMap in table.

User interface changes:

Form design:

1. Added my table into form data source.

2. We cant directly add table container field into grid, so add new field in grid then map data source and field.


3.Added two Action menu items on action pane as "Change and  Remove".(for the best practice written code in classes, not in clicked methods, it reduces the client server side load.)

4. change button is for user to select image from local disc and Remove button is to remove the image file from record.

Class Architecture:

1. Created two classes for upload and remove.

Upload image: 

internal final class uploadImage
{
    public void uploadImageFile(formRun _fromRun)
    {
       FormRun         visualForm;
       FileUpload      fileUploadControl;
       str             imageFilePathName;

       visualForm = classFactory::formRunClassOnClient(new Args(formstr(SysGetFileFromUser)));
       visualForm.init();
       visualForm.design().caption("@ApplicationPlatform:GetFileImageCaption");
       fileUploadControl = visualForm.design().controlName('FileUpload1');
       visualForm.run();
       visualForm.wait();
       FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult();
       if (fileUploadResult != null && fileUploadResult.getUploadStatus())
       {
           imageFilePathName = fileUploadResult.getDownloadUrl();
       }
       if(imageFilePathName)
       {
	      formDataSource  signaturetable_dss =  _fromRun().dataSource(1) as FormDataSource;
	      Signaturetable     signaturetableLoc = signaturetable_dss.cursor() as Signaturetable;  
	      ttsbegin;
	      signaturetableLoc.selectForUpdate(true);
	      signaturetableLoc.Image =ImageReference::GetPackedBinaryData(imageFilePathName);
	      signaturetableLoc.update();
	      ttscommit;
       }
    }

    public static void main(Args _args)
    {
       FromRun formRun = _args.formRun();
       uploadImage object = new uploadImage();
       object.uploadImageFile(formRun);
    }
}

Remove image:

internal final class removeImage
{
    public static void main(Args _args)
    {
	FormRun formRun = _args.formrun();
	formDataSource  signaturetable_dss =  formRun().dataSource(1) as FormDataSource;
	Signaturetable     signaturetableLoc = signaturetable_dss.cursor() as Signaturetable;

	ttsbgein;
	signaturetableLoc.selectForUpdate(true);
	signaturetableLoc.Image = conNull();
	signaturetableLoc.update();
	ttscommit;
    }
}
Thanks for reading!!

Thursday, November 23, 2023

How to create OData action in D365FO and use it in Logic Apps

OData Action in D365FO and Using it in logic apps


Step 1: Create a OData action method in data entity as below and compile the code to see the method in logic app or postman.

With input parameter:
[SysODataActionAttribute("SalesOrderConfirm", false)] --If your method is Static then it should be false else True
public static void salesOrderConfirm(str    _salesId, DataAreaId _company)
{
    SalesTable      salesTable;
    SalesFormLetter salesFormLetter;

    salesTable = SalesTable::find(_salesId);

    salesFormLetter = SalesFormLetter::construct(DocumentStatus::Confirmation);
    salesFormLetter.update(salesTable, DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()), SalesUpdate::All);
}

With List as Response:
[SysODataActionAttribute("GetSalesOrders", False),
SysODataCollectionAttribute("return", Types::Record, "SalesOrder")]
public static List GetSalesOrders(str custAccount, DataAreaId company)
{
  List returnList = new List(Types::Record);

  changecompany(company)
  {
     SalesTable  SalesTable;

     while select SalesTable
	where SalesTable.CustAccount == custAccount
    {
	returnList.addend(SalesTable);
    }
  }
  return returnList;
}

With input and ouput:
[SysODataActionAttribute("GetSalesStatus", False)]

public static str getStatus(str    salesId, DataAreaId company)
{
   str  status;
   changecompany (company)
   {
      status = enum2Str(SalesTable::find(salesId).SalesStatus);
   }
   return  status;
}

With Instance method(Action atrribute to True):

[SysODataActionAttribute("GetLineCount", true)]
public int GetLineCount()
{
  int  lineCount;
  changecompany (this.DataAreaID)
  {
     Salesline  salesline;
  
     select count(RecId) from salesline
  	where salesline.SalesId== this.SalesId;
  
     lineCount = salesline.RecId;
  }
  return  lineCount;
}

Step 2: Create a logic app to trigger the odata action method

                1. Search HTTP  and select When http request is received.
                2. Prepare JSON format your input values in my case Sales id, DataareaId.
                        {
                            "SalesId":"",
                            "Company":""
                        }
                3. Search fin & apps and select Execute action trigger.
      •   Specify Instance,
      •   Action(Your method Name. In this case SalesOrderConfirm) 
      •  Set input parameters(SalesId, Company).

Logic App Flow:
 


Test the flow with LA and Postman:


 Create POST request in Postman :

  •     For Non instance method output and URL
                POST: https://D365URL/data/MyEntity/Microsoft.Dynamics.DataEntities.SalesOrderConfirm


  •    Instance method output and URL
                 POST:
 D365URL/data/SalesOrder(dataAreaId='USMF',SalesId='1235')/Microsoft.Dynamics.DataEntities.GetLineCount




Thanks for reading!!