Tuesday, June 21, 2022

How to get messages from Infolog through x++ in Dynamics 365 FO


Error Handling is one of the very good practices to used especially when we are using integration of Dynamics 365 Fin Ops with other applications.


When we encounter these errors in an infolog the best way to get those error messages is through two most important classes : - 


SysInfologEnumerator  

SysInfoLogMessageStruct


Lets see throw below code snippet how these classes help us to achieve our goal : - 



class GetInfologMessages
{
    public static str getErrorStr()
    {
        SysInfologEnumerator         enumerator;

        SysInfologMessageStruct     msgStruct;

        Exception                              exception;

        str                                          error;   

        enumerator      =   SysInfologEnumerator::newData(infolog.copy(1,infolog.num()));

        while(enumerator.moveNext())
        {
            msgStruct   =   new SysInfologMessageStruct(enumerator.currentMessage());

            exception   =   enumerator.currentException();

            error       =   strfmt("%1 %2", error, msgStruct.message());
        }

        return error;
    }

    public static utcdatetime getErrorDatetime()
    {

        SysInfologEnumerator        enumerator;

        SysInfologMessageStruct     msgStruct;

        Exception                   exception;

        str                         errormsg;

        utcdatetime                 errordatetime;

        enumerator      =   SysInfologEnumerator::newData(infolog.copy(1,infolog.num()));

        while (enumerator.moveNext())
        {
            msgStruct   =   new SysInfologMessageStruct(enumerator.currentMessage());

            exception   =   enumerator.currentException();

            errormsg       =   strfmt("%1 %2", errormsg, msgStruct.message());
        }

        if(errormsg!='')
        {
            errordatetime = DateTimeUtil::getSystemDateTime();
        }

        return errordatetime;
    }
}


That's all for now. Please let us know your questions or feedback in comments section !!!!

Monday, June 6, 2022

How to call an external web link through x++ in Dynamics 365 Fin Ops

 

Calling an external web link is very easy to implement. Sometimes we get this requirement to redirect user to a website based on customer's requirements.

We can easily do that using Browser class.


Here is the code mentioned below : - 


public static void main(Args _args)
{
    Browser browser = new Browser();

    browser.navigate('www.google.com', true, false);
}


That's all for now. Please let us know your questions or feedback in comments section !!!!

How to calculate total discount for a purchase order through X++ in Dynamics 365 Fin Ops

 

Most of the times consultants get a requirement to calculate the discount for the supply chain documents such as Purchase Orders and Sales Orders.

The key to do this calculation is to use PurchTotals class.

Here is the code mentioned below where we are calculating the discount for a purchase order : - 



class CalculateTotalsOfPurchaseOrder
{
    public static void main(Args _args)
    {
        PurchTotals purchTotals;

        PurchTable  purchTable  = PurchTable::find('PO012345');

        AmountCur   totalAmount;

        purchTotals = PurchTotals::newPurchTable(purchTable);

        purchTotals.calc();

        totalAmount = purchTotals.purchTotalAmount();

        info(strFmt('Purchase order: %1 - Total value: %2', purchTable.PurchId, totalAmount));
    }
}


That's all for now. Please let us know your questions or feedback in comments section !!!!

Monday, May 30, 2022

How to Call Json Api with POST/GET through X++ using D365 Fin Ops

 Hi  folks, 


Developers most of the time get the requirement of executing POST or GET operations for the JSON API calls in Fin Ops.

A simple X++ code mentioned below can do the work for us : -




class CallJSONAPI
{
    public static str  post(str  _url,str  _jsonstr)
    {
        str     returnresponse;
        
        str							requestJSON, responseJSON, token, tokenJSON, byteStr;

        System.Net.HttpWebRequest		request, requestApi;

        System.Net.HttpWebResponse	response, responseApi;

        System.Byte[]					bytes, bytesApi;

        System.Text.Encoding			utf8, utf8Api;

        System.IO.Stream				requestStream, responseStream, requestStreamApi, responseStreamApi;

        System.IO.StreamReader		streamReader, streamReaderApi;

        System.IO.StreamWriter                 streamWriter;

        System.Exception				ex;

        System.Net.WebHeaderCollection	httpHeader, httpHeaderApi;

        System.IO.Stream				stream;

        new InteropPermission(InteropKind::ClrInterop).assert();

        requestJSON	=_jsonstr;            

        if(requestJSON == '')
        {
            return 'Input JSON is null' ;
        }

        System.Uri uri	                =   new System.Uri(strFmt('%1',_url));

        System.Net.ServicePointManager::Expect100Continue	=   true;

        System.Net.ServicePointManager::set_SecurityProtocol(System.Net.SecurityProtocolType::Tls12);


        httpHeaderApi	    =   new System.Net.WebHeaderCollection();

        requestApi		    =   System.Net.WebRequest::Create(uri);

        requestApi.set_Method("POST"); // You can POST/GET here

        requestApi.set_ContentType("application/json;charset='utf-8'");

        utf8Api		        =   System.Text.Encoding::get_UTF8();

        requestJSON         =   strRem(requestJSON,"'\'");

        bytesApi		    =   utf8Api.GetBytes(requestJSON);

        requestApi.set_Headers(httpHeaderApi);

        requestApi.set_ContentLength(bytesApi.get_Length());

        requestApi.set_ContentType("application/json");

        requestStreamApi	=   requestApi.GetRequestStream();

        requestStreamApi.Write(bytesApi, 0, bytesApi.get_Length());

        responseApi		    =   requestApi.GetResponse();

        responseStreamApi	=   responseApi.GetResponseStream();

        streamReaderApi	    =   new System.IO.StreamReader(responseStreamApi);

        responseJSON	    =   streamReaderApi.ReadToEnd();

        responseStreamApi.Close();

        streamReaderApi.Close();

        responseApi.Close();

        returnresponse  =   responseJSON;

        return  returnresponse;
    }
}


That's all for now. Please let us know your questions or feedback in comments section !!!!

Thursday, September 2, 2021

How to enable Maintenance Mode in Tier 1 Environments / VMs in D365 FO


Maintenance mode is helpful for us in lot of scenarios where we need some environmental changes in our D365 Finance and Operations platform.

Any kind of change in Financial dimensions and configuration keys are only allowed if the environment is in Maintenance Mode.

In Tier2 or Sandbox environments we get this option very easily in the Maintain Menu in LCS

Environment Page but if the same activity needs to be done Tier 1 environments which we access through  RDP then there is a different approach altogether.


Let's take a look step by step : - 


1) Stop the following services : - 


    a) Microsoft Dynamics Batch Management Service


    b) Microsoft Dynamics Data Import and Export Service


    c) World Wide Web Service


2) In the environment open Sql Server Management Studio and sign in to Sql Server using axdbdmin login

3) Click on New Query option

4) Run the below SQL script : -


    USE AXDB;


    update SQLSYSTEMVARIABLES SET VALUE = 1 where PARM = 'CONFIGURATIONMODE'


5) Once done turn on the services mentioned in Step 1


6) Now the environment should be in Maintenance Mode and you can perform various actions such as

       activate Financial Dimensions and Enable/Disable Configuration keys.


Once the work is done in the SQL statement in step 4 instead of SET VALUE = 1 make it 0 which will turn off the maintenance mode.


Note : - You might need to restart the environment if after the above steps the maintenance mode is not enabling or disabling.



********* Please mention your queries if any in the comments area ***************


How to get the details of the selected records through x++ in D365 FO

 

Sometimes we come across a scenario where we need to get the data from the selected records in a form contained in a grid.

For these kind of scenarios MultiSelectionHelper class has always been useful to achieve the same.


Let us look at an example mentioned below : -



MultiSelectionHelper          selectionHelper = MultiSelectionHelper::construct();
Set                           selectedRecords = new Set(Types::Record);
ABCTable                  abcTable;

selectionHelper.parmDataSource(ABCTable_DS); 

abcTable  = selectionHelper.getFirst();  

if (abcTable.RecId)
{
    while(abcTable)
    {
        selectedRecords.add(abcTable);
        
        info(strFmt('Selected record.. %1',abcTable.myField));
        
        abcTable = selectionHelper.getNext();
    }
}




That's all for now. Please let us know your questions or feedback in comments section !!!!

How to export data from table to excel through x++ in D365 FO


 Exporting data to excel might be required in most of the scenarios where Data Integration is involved.

Excel can be proved as one of the most significant applications for Data Transformation and manipulations.

Let us see how can achieve the data export using x++ coding standards :-
u



DocuFileSaveResult           saveResult;

Table1                       table1details , table1datasource , table1update;

PurchAgreementHeader         purchAgreementHeader;

TransDate                    delDate;

FormDataSource               fdsTable1det = sender.formRun().dataSource('Table1');


table1datasource = fdsTable1det.cursor();

select firstonly purchAgreementHeader where purchAgreementHeader.RecId ==                                                                                                            table1datasource.AgreementHeaderRefRecId;

while select forupdate table1update where                                                                                                                         table1update.AgreementHeaderRefRecId ==                                                                                                                table1datasource.AgreementHeaderRefRecId
{
     if(table1update)
     {
           ttsbegin;

           if(InventItemPurchSetup::findDefault(table1update.ItemId).LeadTime != 0)
           {
                delDate =  DateTimeUtil::getToday(DateTimeUtil::getUserPreferredTimeZone()) +     InventItemPurchSetup::findDefault(table1update.ItemId).LeadTime;
                
                table1update.RequestedDeliveryDate = delDate;
           }

          table1update.PurchQty = 0;

          table1update.RemarksComments = "Enter your comments here";

          table1update.update();

          ttscommit;

     }

}

saveResult = DocuFileSave::promptForSaveLocation("Table1", "xlsx", null, "Table1 Details");

if (saveResult && saveResult.parmAction() != DocuFileSaveAction::Cancel)
{
    saveResult.parmOpenParameters('web=1');

    saveResult.parmOpenInNewWindow(false);

    System.IO.Stream workbookStream = new System.IO.MemoryStream();

    System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();

    using (var package = new ExcelPackage(memoryStream))
    {
        var currentRow = 1;
        
        var worksheets = package.get_Workbook().get_Worksheets();

        var Table1Worksheet = worksheets.Add("Export");

        var cells = Table1Worksheet.get_Cells();

        OfficeOpenXml.ExcelRange cell = cells.get_Item(currentRow, 1);

        System.String value = "Item Number";

        cell.set_Value(value);

        cell = null;

        value = "Unit of Measure";

        cell = cells.get_Item(currentRow, 2);

        cell.set_Value(value);

        cell = null;

        value = "Requested Delivery Date";

        cell = cells.get_Item(currentRow, 3);

        cell.set_Value(value);

        cell = null;

        value = "Remarks and Comments";

        cell = cells.get_Item(currentRow, 4);

        cell.set_Value(value);

        cell = null;

        value = "Purchase Quantity";

        cell = cells.get_Item(currentRow, 5);

        cell.set_Value(value);

        cell = null;

        value = "Agreement Quantity";

        cell = cells.get_Item(currentRow, 6);

        cell.set_Value(value);

        cell = null;

        value = "Remaining Quantity";

        cell = cells.get_Item(currentRow, 7);

        cell.set_Value(value);

        cell = null;

        value = "Released Quantity";

        cell = cells.get_Item(currentRow, 8);

        cell.set_Value(value);

        cell = null;

        value = "Received Quantity";

        cell = cells.get_Item(currentRow, 9);

        cell.set_Value(value);

        cell = null;

        value = "Invoiced Quantity";

        cell = cells.get_Item(currentRow, 10);

        cell.set_Value(value);

        cell = null;            

        value = "Agreement Line Record Id";

        cell = cells.get_Item(currentRow, 11);

        cell.set_Value(value);

        cell = null;

        value = "Agreement Header Record Id";

        cell = cells.get_Item(currentRow, 12);

        cell.set_Value(value);



        while select table1details where table1details.AgreementHeaderRefRecId ==                                                                       purchAgreementHeader.RecId
        {

              currentRow ++;

              cell = null;

              cell = cells.get_Item(currentRow, 1);

              cell.set_Value(table1.ItemId);

              
              cell = null;

              cell = cells.get_Item(currentRow, 2);

              cell.set_Value(table1.ProductUnitOfMeasure);

              
              cell = null;
              
              cell = cells.get_Item(currentRow, 3);

              cell.set_Value(any2Str(table1.RequestedDeliveryDate));


              cell = null;

              cell = cells.get_Item(currentRow, 4);

              cell.set_Value(any2Str(table1.RemarksComments));

              cell = null;


               cell = cells.get_Item(currentRow, 5);

               cell.set_Value(any2Str(table1.PurchQty));


               cell = null;

               cell = cells.get_Item(currentRow, 6);

               cell.set_Value(any2Str(table1.AgreementQty));

               
               cell = null;

               cell = cells.get_Item(currentRow, 7);

               cell.set_Value(any2Str(table1.RemainingQty));

           
               cell = null;

               cell = cells.get_Item(currentRow, 8);

               cell.set_Value(any2Str(table1.ReleasedQty));

               
               cell = null;

               cell = cells.get_Item(currentRow, 9);

               cell.set_Value(any2Str(table1.ReceivedQty));

               
               cell = null;

               cell = cells.get_Item(currentRow, 10);

               cell.set_Value(any2Str(table1.InvoicedQty));


               cell = null;          

               cell = cells.get_Item(currentRow, 11);

               cell.set_Value(any2Str(table1.AgreementLineRefRecId));

               
               cell = null;

               cell = cells.get_Item(currentRow, 12);

               cell.set_Value(any2Str(table1.AgreementHeaderRefRecId));
               
       }
       
       package.Save();

  }
       memoryStream.Seek(0, System.IO.SeekOrigin::Begin);

       DocuFileSave::processSaveResult(memoryStream, saveResult);

}


That's all for now. Please let us know your questions or feedback in comments section !!!!

Demystifying the SysOperation Framework in D365 F&O: Building Scalable and Maintainable Batch Jobs

 If you've been developing in Dynamics 365 Finance and Operations for a while, chances are you've either worked with or heard about ...