Thursday, October 9, 2025

Capturing Infolog messages in D365FO using X++.

 


    Capturing info log messages in D365FO. We can get it in multiple ways.

    
  • Way 1.      
public static str getError()
{
    SysInfologEnumerator    sysInfologEnumerator;
    SysInfologMessageStruct infoMessageStruct;
    str                     logMessage;
    str                           logString;
    str                          ret;
    int                          i;
    #Define.NewLine('\n')

    sysInfologEnumerator = SysInfologEnumerator::newData(infolog.infologData());

    while (sysInfologEnumerator.moveNext())
    {
	i = 1;

	if (logMessage)
	{
	    logMessage += #Newline;
	}

	infoMessageStruct = SysInfologMessageStruct::construct(sysInfologEnumerator.currentMessage());

	while (i <= infoMessageStruct.prefixDepth())
	{
	    logString = logString + infoMessageStruct.preFixTextElement(i) + '. ';
	    i++;
	}

	logString = logString + infoMessageStruct.message();
	logMessage = logMessage + infoMessageStruct.message();
    }

    return logMessage;
}
      
  • Way 2
public void method()
{
    System.Exception        ex;
	
    try
    {
	
    }         
    catch
    {
        ex = CLRInterop::getLastException().GetBaseException();
	error(ex.get_Message());

        --- or----

        System.Exception e = ex;
	while (e != null)
	{
	    errorMessage += e.Message;
	    e = e.InnerException;
	}
    }
}


  • Way 3  (It fill fetch only messages from our process)
    public static void main(Args _args)
    {
	Counter  infoLogStartPos;
	try
	{ 
	    infoLogStartPos = infologLine();

	    // Your code
	}
	catch
	{
	    Counter infoLogEndPos = infologLine();
	    str logText           = Info::infoCon2Str(infolog.copy(infoLogStartPos, infoLogEndPos));

	    warning(logText);// You can save this log text into your table.
		
	    infoLogStartPos       = infoLogEndPos + 1;
	}
    }


  • Way 4  (Get the type of exception using the below code.)
    container infologContents = infolog.cut(); 

    for (int i = 1; i <= conLen(infologContents); i++)
    {
	container infologLine = conPeek(infologContents, i);

	Exception errorLevel = conPeek(infologLine, 1);
	str logMessage = conPeek(infologLine, 2);
				
	if (logMessage)
	{
	    switch (errorLevel)
	    {
		case Exception::Error :
		    errors.add(logMessage);
		    break;

		case Exception::Warning :
		    warnings.add(logMessage);
		    break;

		case Exception::Info :
		    infos.add(logMessage);
		    break;

		default:
		    Debug::assert(false);
		    warnings.add(logMessage);
		    break;
	    }
        }
    }

  • Way 5
SysInfologEnumerator 	enumerator;
SysInfologMessageStruct msgStruct;
Exception 		exception;
str 			error;

enumerator = SysInfologEnumerator::newData(infolog.cut());

while (enumerator.moveNext())
{
    msgStruct = new SysInfologMessageStruct(enumerator.currentMessage());
    exception = enumerator.currentException();
    error = strfmt("%1 %2", error, msgStruct.message()) + "\n";
}

  • Way 6 (Return only error messages from info log)
    SysInfologEnumerator sysInfologEnumerator = SysInfologEnumerator::newData(infolog.infologData());
    while (sysInfologEnumerator.moveNext())     { switch (sysInfologEnumerator.currentException()) {     case Exception::Error:     retvalue = strFmt("%1", sysInfologEnumerator.currentMessage());     break; }     }

  • Way 7
    infolog.text(infologLine());   
  • Way 8
 	str errormessage;
	errormessage = infolog.text(infologLine());
	errormessage = infolog.text(infologLine()-1);
	errormessage = errormessage + " "+ infolog.text(infologLine());
	Error(errormessage);
Reference

On-hand Quantity

  public Qty checkOnHand(InventSiteId site,InventLocationId warehouse,ItemId itemId)

    {

        InventDimParm    inventDimParm;

        InventDIm        inventDim;

        InventOnHand     inventOnHand = InventOnHand::construct();

        Qty              availQty = 0;


        inventDim.InventSiteId = site;

        inventDim.InventLocationId = warehouse;

        inventDim = InventDim::findOrCreate(inventDim);

        inventDimParm.initFromInventDim(inventDim);//InventDim::findOrCreateBlank());

        inventOnHand = inventOnHand::newParameters(itemId,inventDim,inventDimParm);

        availQty = inventOnHand.availPhysical();

        

        return availQty;

    }

Tuesday, May 13, 2025

Delete TFS Workspace Through command prompt D365 FO

Requirement: where I have situation need to configure the TFS in my Development machine but getting error when we map metadata.

 cause of the issue earlier in same Development machine another developer configures TFS with Private permission. so, system not allowing us to configure TFS.





solution

1) Open Developer command prompt visualstudio2022 

2)just enter tf workspaces. will get the list of users and workspaces



3) deleting workspace name

Follow the syntax
tf workspace /delete "WORKSPACENAME;PREVIOUSUSERACCOUNT”


copy and paste in the command prompt and hit enter, then select "Y".

tf workspace /delete "Test_venkates_1;venkatesh"  

after entering it will ask for confirmation enter yes .it will be deleted 


 


Monday, May 12, 2025

purchase order confirmation, product receipt, Invoice classes and methods

 Purchase order confirmation, product receipt, Invoice, cancel  classes and methods

Let's assume that we have the requirement to send business events after purchase order confirmation, cancel, product receipt and invoice Fully (header level)


1) purchase order cancel 

=================

[ExtensionOf(classstr(PurchCancel))]

public final class TestPurchCancel_Extension

{

public void run()

{   

PurchTable  purchTableOrig, purhtableLoc;

next run();

purchTableOrig = this.parmPurchTable();

                select firstonly purhtableLoc

where purhtableLoc.PurchId         == purchTableOrig.PurchId

&& purhtableLoc.PurchStatus == PurchStatus::Canceled;


    if(purhtableLoc.RecId)

{

//Write your logic

}

}

}



2) product receipt and invoice 
=====================

[ExtensionOf(classstr(PurchFormletter))]

public final class TestPurchFormLetter_Extension

{

    public void run()

    {

        PurchTable          purchTableOrig, purhtableLoc;

        next run();


        purchTableOrig = purchFormLetterContract.parmPurchTable();


        select firstonly purhtableLoc

            where purhtableLoc.PurchId      == purchTableOrig.PurchId

               &&(purhtableLoc.PurchStatus  == PurchStatus::Received||

                  purhtableLoc.PurchStatus  == PurchStatus::Invoiced);

        

        if(purhtableLoc.RecId)

        {

            //Write your logic 

        }

        

    }

}


3) purchase order confirmation

===========================

[ExtensionOf(classstr(SourceDocumentStateInProcess))]

public final class TestSourceDocumentStateInProcess_Extension

{

    protected boolean doTransition()

    {

        next doTransition();

        

        if (targetSourceDocumentAccountingStatus == SourceDocumentAccountingStatus::Completed)

        {

            PurchTable purchTable =                                PurchTable::findSourceDocumentHeader(sourceDocumentHeader.RecId);

            VendPurchOrderJour vendPurchOrderJour = VendPurchOrderJour::findByPurchId(purchTable.PurchId);

            if(vendPurchOrderJour.RecId)

            {

              //Write your logic

            }

        }

        return true.

    }

}


while doing purchase order confirmation, product receipt and invoice system will create journals and post and update the status in PurchTable  .after updating status or creating journal if we want any customizations we can do in below method  


[ExtensionOf(classstr(FormletterService))]
public  final class TestFormLetterService_Extension
{
    protected void processJournal(Printout _printout)
    {
       
        VendPurchOrderJour  vendPurchOrderJourloc;
        PurchTable          purchTableLoc;
vendinvoicejour     vendinvoicejour     
VendPackingSlipJour VendPackingSlipJour;

        next processJournal(_printout);

        purchTableLoc= formLetterContract.parmsourceTable() as PurchTable;

//purchase order confirmation
            select  firstonly vendPurchOrderJourloc
            where vendPurchOrderJourloc.PurchId         == purchTableLoc.PurchId
                && vendPurchOrderJourloc.DataAreaId == purchTableLoc.DataAreaId;
            if(vendPurchOrderJourloc.recid)
            {
            //write your logic 
    }
//for packingslip post
select  firstonly VendPackingSlipJour
            where VendPackingSlipJour.PurchId         == purchTableLoc.PurchId
                && VendPackingSlipJour.DataAreaId == purchTableLoc.DataAreaId;
            if(VendPackingSlipJour.recid)
            {
            //write your logic 
    }

//for invoice post
select  firstonly vendinvoicejour     
            where vendinvoicejour.PurchId         == purchTableLoc.PurchId
                && vendinvoicejour.DataAreaId == purchTableLoc.DataAreaId;
            if(vendinvoicejour.recid)
            {
            //write your logic 
    }
        
    }

}

Tuesday, March 18, 2025

Getting error while exporting data using Data Management

 

Getting error while exporting data using Data Management

 
<?xml version=/1.0/?><Errors><Error><ErrorCode>0</ErrorCode><SubComponent>Copy Error Component</SubComponent><Description>Index was outside the bounds of the array.</Description></Error><Error><ErrorCode>0</ErrorCode><SubComponent>Copy Error Component</SubComponent><Description>   at Microsoft.Dynamics.AX.Framework.Tools.DMF.DMFErrorDescription.ErrorOutputDescription.ProcessInput(Int32 inputID, PipelineBuffer buffer)</Description></Error><Error><ErrorCode>-1073450910</ErrorCode><SubComponent>Copy Error Component [255]</SubComponent><Description>System.ApplicationException: Could Not Process Input
   at Microsoft.Dynamics.AX.Framework.Tools.DMF.DMFErrorDescription.ErrorOutputDescription.ProcessInput(Int32 inputID, PipelineBuffer buffer)
   at Microsoft.SqlServer.Dts.Pipeline.ManagedComponentHost.HostProcessInput(IDTSManagedComponentWrapper100 wrapper, Int32 inputID, IDTSBuffer100 pDTSBuffer, IntPtr bufferWirePacket)</Description></Error><Error><ErrorCode>-1073450974</ErrorCode><SubComponent>SSIS.Pipeline</SubComponent><Description>SSIS Error Code DTS_E_PROCESSINPUTFAILED.  The ProcessInput method on component /Copy Error Component/ (255) failed with error code 0x80131600 while processing input /Error Input 257/ (257). The identified component returned an error from the ProcessInput method. The error is specific to the component, but the error is fatal and will cause the Data Flow task to stop running.  There may be error messages posted before this with more information about the failure.
</Description></Error></Errors>
Package execution failed please check event log in DMF service box

1. It is a custom data entity, yes I have tried to do a full Sync.
 
2. This Error was encountered while exporting.
 
3. This error is now solved, the root cause for this error was one of the fields that i was trying to export contained data in below format:
   
"Sample String 示例字符串"
 
The Text in English was also translated to chinese and added in the field.

To Solve this Issue I removed the chinese text from the field and only  imported the Englist text and now import happens Successfully.





Monday, February 24, 2025

Posting methods in x++

while posting packing Slip

class/SalesPackingSlipJournalPost/method/endUpdate();


[ExtensionOf(classStr(SalesPackingSlipJournalPost))]

final class TestSalesPackingJournalPost_Extension

{

     protected void endUpdate()

    {

            next endUpdate();

        // write your logic

    }

}

How to search metadata in x++

Query stringWhat it does
TrvExpTableIf the token is by itself, it is assumed to be the name. So this will find everything in the application that has "TrvExpTable" in the name.
type:form ccountFinds all forms that have "ccount" in their names.
type:form property:formtemplate=listpageFinds all forms that contain the property "FormTemplate" equal to ‘ListPage’.
type:table,formDesign property:"WorkflowDataSource=TrvExpTable"Finds formDesign nodes under tables, nothing would be found.
type:form,formmenufunctionbuttoncontrol property:Text=@SYS311998Finds all menu function button controls with the Text property equal to (a label) ‘@SYS311998’.
type:table,method name:insertFinds tables with a method containing "insert" in the method name.
type:table,tableindex name:ExportFinds tables with an index name containing the word "Export".
type:table,tableindexfield name:xpNumFinds table indexes with "xpNum" in the index field name.
type:table,tablefieldgroup name:EPNewFinds FieldGroups (in tables) containing ‘EPNew’ in their names.
type:form,formgridcontrol property:allowedit=no,heightmode=columnFinds form grid controls, with properties allowedit equal to "no" and heightmode equal to "column".
type:form,formtabcontrol property:arrangeMethod=Vertical,ViewEditMode=view,WidthMode=AutoFinds form tab controls, with properties arrangeMethod equal to "Vertical" and ViewEditMode equal to "view" and WidthMode equal to "Auto".
type:form,formDesign property:"WorkflowDataSource=TrvExpTable"Finds all forms with the "WorkflowDataSource" property in the FormDesign node set to the value "TrvExpTable".
model:”Application Suite” type:formdesign property:style=simplelistdetailFind all forms in Application Suite model that has the style property set to simpleListDetail in the FormDesign node.
code:"return null"Finds all places in the source code that contains "return null".
code:"element.lock()" type:formFinds all places in the forms source code that contain the snippet "element.lock()".
code:"insert" type:table,formFinds all places in the source code of either forms or tables that contain "insert".
code:"public display" type:form,methodFinds all form methods that contain the code "public display".
type:formbuttoncontrol property:text=Finds all form Button Controls that have empty text properties.


Reference;  Metadata search

 

Capturing Infolog messages in D365FO using X++.

      Capturing info log messages in D365FO. We can get it in multiple ways.      Way 1.        public static str getError() {     SysInfol...