May 30, 2023

Get the List of fields and methods available on table through x++ - D365 FO

 We might get some scenarios to get the list of objects or a list of elements available in a particular object in X++. Here is a sample piece of code to retrieve the details about the table object.

Whenever we try to get the metadata of an object (Tables, Table fields, table methods) we should keep in mind to use the below namespace in our code

using Microsoft.Dynamics.AX.Metadata.MetaModel;

To get list of tables

using Microsoft.Dynamics.AX.Metadata.MetaModel;
public class TableNamesList
{
    public static void getTableNames()
    {
       var tables = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetAllTables();
        var tablesEnumr = tables.GetEnumerator();
        while (tablesEnumr.MoveNext())
        {
            info(strfmt("%1", axTable.Name));
        }
    }
}


To get list of Fields from a table

public static void getFieldNames()
    {
        AxTable table =     Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetTable(tableId2Name(tablenum(SalesTable)));
       var fields = table.Fields;
        var fieldEnumerator = fields.GetEnumerator();
        while (fieldEnumerator.MoveNext())
        {
            info(strfmt("%1", field.Name));
        }
    }


To get list of methods available on a table

public static void getMethodNames()
    {
        AxTable table = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetTable(tableId2Name(tablenum(SalesTable)));
        var methods = table.Methods;
        var methodEnumerator = methods.GetEnumerator();
        while (methodEnumerator.MoveNext())
        {
            AxMethod method = methodEnumerator.Current;
            if(method.IsDisplay)
            {
                info(strfmt("Display method : %1", method.Name));
            }
            else
            {
                info(strfmt("Normal method : %1", method.Name));
            }
        }
    }

Similar to the above code, we can use the metadata .dll in X++ to get all the objects and its related details available in AOT 

May 21, 2023

Changing Company Id in D365 FO

Changing the company id in D365 FO is not directly possible and also not a recommended approach. But there still is a way through which we can change the Id in rare cases. Below are the list of technical steps to be followed for changing the company id (DataAreaId).


Note: Please take the database back up before any changes to revert back in case of any issues during the process.

There are three scenarios of tables where the company Id is present.  They all need to be updated in order to bring the new Id all over the application.

1. Company Specific tables where there is a DataAreaId filed available.
  • Use the below stored procedure command in SQL to update the field in all tables with the values required.
  • Use the below SQL query to update the table "DataArea"
  • Get the list of tables using the below query

        EXEC sp_MSforeachtable 'update ? set DataAreaID = "XNEW" where ?.DataAreaID = "XOLD"

2. DataArea Table
        UPDATE DataArea SET ID = 'XNEW' WHERE DataArea.ID = 'XOLD'

3. Global tables which do not have a default framework maintained "DataAreaId" field but has a physical ordinary field called "DataArea".

  • Use the below SQL query to get the list of table having the field as DataArea

        SELECT DISTINCT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
            WHERE TABLE_TYPE = 'BASE TABLE' 
            AND TABLE_NAME NOT IN (SELECT DISTINCT TABLE_NAME    
            FROM INFORMATION_SCHEMA.COLUMNS 
            WHERE COLUMN_NAME = 'DataArea');
  • Update the list of tables with the new companyId value in the fields.
        UPDATE TableName SET DataArea = 'XNEW' WHERE DataArea.ID = 'XOLD'

May 04, 2023

Direct delivery Purchase Order creation from Sales order through X++ - D365 FO

 In Some scenarios, we might have to create a direct delivery Purchase order related to the available sales orders. The below code will help us in doing it.

public void creaeDirectDeliveryPO()

{    

    TmpPurchLinePrice                  tmpPurchLinePrice;

    PurchCreateFromSalesOrder    purchCreateFromSalesOrder;

    PurchAutoCreate                       purchAutoCreate;

    VendTable                            vendTable;

    SalesLine                                   salesLinePOCreation;

    SalesTable                                 salesTablePOCreation;

    AccountNum                 vendAccountNum;

    LineNum                                   lineNumber;

    boolean                                      createDirectDelivery;

       

    vendAccountNum = "XYZ"; // Use the vendor account for which the PO should be created

    //Loop through the sales order lines for which the direct delivery Po lines to be created

    while select salesLinePOCreation

        join salesTablePOCreation

        where salesTablePOCreation.SalesId == "ABC" // Sales order number

        && salesLinePOCreation.SalesId == salesTablePOCreation.SalesId

    {

        if(!salesLinePOCreation.referencedPurchLine().RecId && vendAccountNum)

        {

            tmpPurchLinePrice.SalesId                      = salesLinePOCreation.SalesId;

            tmpPurchLinePrice.LineNum                  = lineNumber + 1;

            tmpPurchLinePrice.SalesLineRefRecId   = salesLinePOCreation.RecId;

            tmpPurchLinePrice.AccountNum            = vendAccountNum;

            tmpPurchLinePrice.ItemId                       = salesLinePOCreation.ItemId;

            tmpPurchLinePrice.InventDimId             = salesLinePOCreation.InventDimId;

            tmpPurchLinePrice.PurchQty                  = salesLinePOCreation.SalesQty;

            tmpPurchLinePrice.QtyOrdered              = salesLinePOCreation.SalesQty;

            tmpPurchLinePrice.PurchUnit                = salesLinePOCreation.SalesUnit;

            tmpPurchLinePrice.LineAmount            = salesLinePOCreation.LineAmount;

            tmpPurchLinePrice.Price                        = salesLinePOCreation.PriceUnit;

            tmpPurchLinePrice.CurrencyCode         = salesLinePOCreation.CurrencyCode;


            if(tmpPurchLinePrice.validateWrite())

            {

                tmpPurchLinePrice.insert();

                createDirectDelivery = true;

                lineNumber++;

            }

        }

    }


    if (createDirectDelivery)

    {

        ttsbegin;

        purchCreateFromSalesOrder   = PurchCreateFromSalesOrder::construct();

    

        purchCreateFromSalesOrder.parmCallerRecord(salesTablePOCreation);

        purchCreateFromSalesOrder.parmSalesTable(salesTablePOCreation);

        purchCreateFromSalesOrder.tradeLineDlvType(TradeLineDlvType::DropShip);

        purchCreateFromSalesOrder.parmTransferAddress(true);

        purchCreateFromSalesOrder.mcrDropShipment(true);


        purchAutoCreate = PurchAutoCreate::construct(tmpPurchLinePrice, purchCreateFromSalesOrder);

        purchAutoCreate.create();

        ttscommit;


        Info(strfmt("Direct delivery PO created is  %1", purchAutoCreate.purchId()));

    }

}

May 01, 2023

Use temporary Blob storage for accessing files during runtime.

 We can learn about how to store a file in the temporary blob storage, so that the file can be used during runtime process for our scenarios. I have a scenario, where I need to get the company image and use it in my process.

In order to do this, we can get the image file from DB and upload it to the temporary Blob storage. Further we can get the URL for the uploaded file and that can be used to send or download the image as required in our process.

Below code sample help us for the scenario.

Image                             logoImage;
Binary                             binary;
System.IO.Stream        imageStream;
str                                   downloadUrl;
       
logoImage = new Image();
logoImage.setData(CompanyImage::findByRecord(CompanyInfo::find()).Image);
 
binary = Binary::constructFromContainer(logoImage.getData());
 
imageStream = binary.getMemoryStream();
 
if (imageStream)
{
    str fileName        = 'Your file name'; //Fixed name or GUID can be created for dynamic name
    str contentType  = 'image/png'; // Change according to your file type
    str fileExtension = enum2Str(ImageType::PNG); // Change according to your file type
 
    FileUploadTemporaryStorageStrategy fileUploadStrategy = new FileUploadTemporaryStorageStrategy();
    FileUploadTemporaryStorageResult fileUploadResult = fileUploadStrategy.uploadFile(imageStream, fileName + fileExtension, contentType, fileExtension);
 
    if (fileUploadResult == null || !fileUploadResult.getUploadStatus())
    {
        warning("@ApplicationPlatform:FileUploadFailed");
    }
    else
    {
        downloadUrl = fileUploadResult.getDownloadUrl();
        if (downloadUrl == "")
        {
            throw Exception::Error;
        }
    }
}

The downloadUrl hold the link for the temporarily stored file path. We can use this in our next process as required.