Friday, 10 September 2021

Create JSON file in AX 2009

 Today, I will share the code snippet which can be used to create a json file in AX 2009.

We will be using .NET Newtonsoft.Json.dll file to proceed with this work.

Download the Newtonsoft.Json.dll  and place it on this path : D:\Program Files (x86)\Microsoft Dynamics AX\50\Client\Bin.



Below is the code snippet to create JSON file.

static void DataExtractToJSON(Args _args)

{

    Dialog                  dialog;

    FilePath                filepath;

    DialogField             dialogFilePath;

    InventSum               inventSum;

    InventDim               inventDim;

    WMSLocation             wmsLocation;

    InventTable             inventTable;

    InventDimParm           invDimParm;

    Qty                     availPhys;

    str                     lpnnumber, lpnconstant, filename;

    int                     lpnCounter, lpnLen;

    date                    consumptionPriorityDate,expirationDate,manufacturedDate;


    TextIO                  file;

    FileIOPermission        fileIOPermission;

    container               line,header,header2;

    Newtonsoft.Json.Linq.JTokenWriter       writer;

    Newtonsoft.Json.Linq.JObject            jObject;

    ClrObject                               clrObject;

    str                                     jsonStr;

    ;


    #File


    dialog = new dialog();

    dialog.caption("Select the folder to save JSON file");

    dialogFilePath = dialog.addField(typeId(FilePath));

    dialogFilePath.label('FilePath');

    dialog.run();//execute dialog


    filepath = dialogFilePath.value();//return path file value


    if (filepath)

    {

        writer = new Newtonsoft.Json.Linq.JTokenWriter();

        writer.WriteStartObject();

        writer.WritePropertyName("Items");

        writer.WriteStartArray();

        fileName = FilePath+'\\test.json';

        new FileIOPermission(Filename,'w').assert();

        file = new TextIO(Filename,#io_write,1250);


        line = connull();


        while select inventLocationId, wmsLocationId,inventLocationId,locationType from wmsLocation

           join inventSum

           join inventDim

           join inventTable

           where inventDim.inventDimId == inventSUm.InventDimId

            && inventSum.ItemId == inventTable.ItemId

            && inventDim.InventLocationId == wmsLocation.inventLocationId

            && inventDim.wMSLocationId == wmsLocation.wMSLocationId

            && inventSum.Closed == NoYes::No

            && wmsLocation.checkText == ''

            && wmsLocation.locationType == WMSLocationType::Pick 

        {

               line = connull();


               availPhys = InventSum.availPhysical();


               if ( availPhys != 0)

               {

                    writer.WriteStartObject();


                    writer.WritePropertyName('testLocation');

                    writer.WriteValue(wmsLocation.wmsLocationId);


                    writer.WritePropertyName('TestType');

                    writer.WriteValue('LOCATION');


                    writer.WritePropertyName('TestTransactionType');

                    writer.WriteValue('INVENTORY_ADJUSTMENT');


                    writer.WritePropertyName('TestItemId');

                    writer.WriteValue(inventTable.ItemId);


                    writer.WritePropertyName('TestQty');

                    writer.WriteValue(availPhys);


                    writer.WriteEndObject();

               }

        }


        writer.WriteEndArray();

        writer.WriteEndObject();


        clrObject   = writer.get_Token();

        jObject     = clrObject;


        jsonStr = jObject.ToString();


        file.write(jsonStr);

        info(jObject.ToString());


        if(dialog.closedOk())

        {

            info(strfmt("Please check the JSON file on this path %1", filename));


        }


    }

}


Output :






Send an email with attachment in AX 2009 with batch processing

 Today, I will be sharing the code snippet which can utilized to send email along with attachment in a batch job in AX 2009. 

We will be using standard mail mechanism of the system and will utilize  SysOutgoingEmailTable and SysOutgoingEmailData tables.

Following are perquisites for the this process: 

  • Email parameters filled in : Administration > Administration Area > Setup > E-mail parameters.


  • Email distributor batch must be running : Administration > Administration Area > Periodic > E-mail processing > Batch.

  • A class which extends RunBaseBatch and add a method in it which will have below code snippet.
void sendEmail()
{
    SysOutgoingEmailTable       outgoingEmailTable;
    SysEmailItemId              nextEmailItemId;
    Map                         map;
    str                         SenderName, SenderEmail, To, Subject, Body;
    SysOutgoingEmailData        outgoingEmailData;
    FileIOPermission            fileIOPermission;
    InteropPermission           interopPermission;
    BinData                     binData;
    FileName                    attachmentFileName;
    SysEmailParameters          emailParams;
    int                         maxAttachmentSize;
    str                         tmpPath;
    str                         filePath;
    str                         fileName;
    str                         fileExtension;
    container                   attachmentData;
;

    try
    {

        SenderName    = "Tester";
        SenderEmail   = "test@gmail.com";
        To            = "test@gmail.com";
        Subject       = "Subject  for test ";
        Body          = "test email";
        
        //Email parameters
        emailParams       = SysEmailParameters::find();
        maxAttachmentSize = emailParams.MaxEmailAttachmentSize;
        
        ttsbegin;
        nextEmailItemId                  = EventInbox::nextEventId();
        outgoingEmailTable.EmailItemId   = nextEmailItemId;
        outgoingEmailTable.IsSystemEmail = NoYes::No;
        outgoingEmailTable.Sender        = SenderEmail;
        outgoingEmailTable.SenderName    = SenderName;
        outgoingEmailTable.Recipient     = To;
        outgoingEmailTable.Subject       = SysEmailMessage::stringExpand(Subject, map);
        outgoingEmailTable.Priority      = eMailPriority::Normal ;
        outgoingEmailTable.WithRetries   = false;
        outgoingEmailTable.RetryNum      = 0;
        outgoingEmailTable.UserId        = curUserId();
        outgoingEmailTable.Status        = SysEmailStatus::Unsent;
        outgoingEmailTable.Message       = Body;
        outgoingEmailTable.LatestStatusChangeDateTime = DateTimeUtil::getSystemDateTime();
        outgoingEmailTable.insert();

        attachmentFileName = 'D:\\test.xlsx';

        fileIOPermission = new FileIOPermission(attachmentfileName,'r');
                                    fileIOPermission.assert();

        if(WinAPIServer::fileExists(attachmentfileName) && (WinAPIServer::fileSize(attachmentfileName) < (maxAttachmentSize * 1000000)))
        {
            binData = new BinData();
            binData.loadFile(attachmentfileName);
            attachmentData = binData.getData();
        }

         CodeAccessPermission::revertAssert();
         
         //Add attachment record
         outgoingEmailData.EmailItemId       = nextEmailItemId;
         outgoingEmailData.DataId            = 1;
         outgoingEmailData.EmailDataType     = SysEmailDataType::Attachment;
         outgoingEmailData.Data              = attachmentData;
         [filePath, filename, fileExtension] = Global::fileNameSplit(attachmentfileName);
         outgoingEmailData.FileName          = filename;
         outgoingEmailData.FileExtension     = fileExtension;
         outgoingEmailData.insert();

         ttscommit;
     }
     catch
     {
        throw error("Failed to send email");
     }

}

Output :
Check your batch job status in the Basic > Basic Area > Common Forms > Batch job list- User.
Check your email status : Administration > Administration Area > Periodic > E-mail processing > E-mail sending status. 




Send email along with attachment in AX 2009 without batch processing

 Today, I will be sharing the code snippet which can utilized to send email along with attachment in a job in AX 2009. 

We will use System.Net.Mail framework and configured email parameters in the AX 2009.

To fill in parameters we will use the form available on this path : Administration > Administration Area > Setup > E-mail parameters.

Code snippet.

static void TestEmai1(Args _args)

{

    System.Net.Mail.MailMessage             mailMessage;

    System.Net.Mail.Attachment              attachment;

    System.Net.Mail.AttachmentCollection    attachementCollection;

    System.Net.Mail.SmtpClient              smtpClient;

    System.Net.Mail.MailAddress             mailAddressFrom;

    System.Net.Mail.MailAddress             mailAddressTo;

    str                                     Body;

    str                                     Subject;

    str                                     SMTPServer;

    str                                     FileName;

    FileIOPermission                        perm;

    ;


    mailAddressFrom = new System.Net.Mail.MailAddress("sender email","");

    mailAddressTo = new System.Net.Mail.MailAddress("recipient email","");

    Body = "<B>Body of the email</B>";

    Subject = "Subject line for the email";

    SMTPServer = SysEmailParameters::find(false).SMTPRelayServerName;


    mailMessage = new System.Net.Mail.MailMessage(mailAddressFrom, mailAddressTo);

    mailmessage.set_Subject(Subject);

    mailmessage.set_Body(Body);

    attachementCollection = mailMessage.get_Attachments();


    // Add attachemnts! use double slashes ("\") in the filename path.

    FileName = "D:\\test.xlsx";

    perm = new FileIOPermission(FileName,'w');

    perm.assert();


    attachment = new System.Net.Mail.Attachment(FileName);

    attachementCollection.Add(attachment);

    smtpClient = new System.Net.Mail.SmtpClient(SMTPServer);

    smtpClient.Send(mailmessage);


    CodeAccessPermission::revertAssert();


}

Expected output: 




Tuesday, 12 January 2021

Find the list of menuitems assigned to particular privilege in D365 F&O

 Today, I will be discussing out about how to fetch the list of menu items assigned to particular privilege using X++. In AX 2012 this data was stored was on table level. However,  in D365 F&O we will be using metadata API to get this information.

Below is the code snippet of it. The code will extract the list of all menu items which are covered under privilege 'CurrencyView' and it will export data in excel sheet. The excel sheet will contain following information : 

- Privilege

- Entry point (Menu item)

- System name of  menu item

- Menu item type


using Microsoft.Dynamics.ApplicationPlatform.Environment;

using Microsoft.Dynamics.AX.Metadata.Storage;

using Microsoft.Dynamics.AX.Metadata.Storage.Runtime;

using Microsoft.Dynamics.AX.Metadata.MetaModel;

using System.IO;

using OfficeOpenXml;

using OfficeOpenXml.Style;

using OfficeOpenXml.Table;

class Test_GetMenusForPrivilege

{

    public static void main(Args _args)

    {

        str packageDir = EnvironmentFactory::GetApplicationEnvironment().Aos.PackageDirectory;

        var providerConfig = new RuntimeProviderConfiguration(packageDir);

        var provider = new MetadataProviderFactory().CreateRuntimeProvider(providerConfig);

        SecurityPrivilege   secPrivilege;

        MemoryStream memoryStream = new MemoryStream();


        using (var package = new ExcelPackage(memoryStream))

        {

            var currentRow = 1;

            var worksheets = package.get_Workbook().get_Worksheets();

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

            var cells = CustTableWorksheet.get_Cells();

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

            System.String value = "Privilege";

            cell.set_Value(value);

            cell = null;

            value = "Entrypoint or menuitem name";

            cell = cells.get_Item(currentRow, 2);

            cell.set_Value(value);

            cell = null;

            value = "System name of menuitem";

            cell = cells.get_Item(currentRow, 3);

            cell.set_Value(value);

            cell = null;

            value = "Menu item type";

            cell = cells.get_Item(currentRow, 4);

            cell.set_Value(value);


            while select Identifier from secPrivilege

            where secPrivilege.Identifier == "CurrencyView"

            {

                AxSecurityPrivilege privilege = provider.SecurityPrivileges.Read(secPrivilege.Identifier);

                var enumerator = privilege.EntryPoints.GetEnumerator();


                while (enumerator.MoveNext())

                {

                    currentRow ++;

                    cell = null;


                    cell = cells.get_Item(currentRow, 1);

                    cell.set_Value(secPrivilege.Identifier);


                    AxSecurityEntryPointReference entryPoint = enumerator.Current;

                    cell = null;

                    cell = cells.get_Item(currentRow, 2);

                    cell.set_Value(entryPoint.Name);


                    cell = null;

                    cell = cells.get_Item(currentRow, 3);

                    cell.set_Value(entryPoint.ObjectName);


                    cell = null;

                    cell = cells.get_Item(currentRow, 4);

                    cell.set_Value(entryPoint.ObjectType);

                }

            }

            package.Save();

            file::SendFileToUser(memoryStream, "PrivilegeWithMenuItems");


        }   

    }

}


Output file



Monday, 24 February 2020

How to call external class method in enterprise portal

Today, I will be discussing about how to call external class method in enterprise portal.
There was a requirement in which we need to update some information on updating the vendor account within purchase requisition web page on enterprise portal.

For changing this target i created a new class and added a static method inside it. This class was created with in AX and names as PRTestHelper class.

Class: PRTestHelper
Static Method : updateVendorAccount

Now we need to add override the ondatachanged method of vendor account field in PurchReqLineInfo_ascx_cs. Add following code in the class.

 protected void VendAccount_DataChanged(object sender, AxBoundFieldDataChangedEventArgs e)
{
        this.setupDefaultDimension(true);
       
       
        if (Page.IsPostBack)
        {
            Page.Validate();
            if (Page.IsValid)
            {
                DataSetViewRow row;

                row = this.PurchReqLineDS.GetDataSet().DataSetViews["PurchReqLine"].GetCurrent();
                this.AxSession.AxaptaAdapter.CallStaticClassMethod("PRTestHelper", "updateVendorAccount", row.GetFieldValue("RecId"), row.GetFieldValue("VendAccount"));
                DialogHelper.Close(CloseDialogBehavior.RefreshPage);
            }
        }
       
   }


// Following code is used to call method :  this.AxSession.AxaptaAdapter.CallStaticClassMethod("PRTestHelper", "updateVendorAccount", row.GetFieldValue("RecId"), row.GetFieldValue("VendAccount"));

First parameter is : Class name
Second parameter is : Method name
Third parameter is : RecId of Purchase Requisition line
Fourth parameter is : Vendor account

Note : 3rd and 4th parameter are optional as we are using them to send parameter to static method.

How to find web controls in Enterprise portal (EP)

Today , I will be discussing about the approach through which we can find out the web controls of enterprise portal.

Lets take an example of Purchase Requisition web page in Enterprise portal.

1) Go to Enterprise portal -> Purchase Requisition tab -> Click on one of the Purchase requisition

2) Click on Page tab









3) Click on Edit page drop down and select edit page option.























4) Click on drop arrow and select edit web part. The name within managed content item is web control name.


Dynamics 365 F&O - Changes in financial dimension structure methods as compared to AX 2012

Today , I will be discussing about the changes of methods which are commonly used for financial dimension or ledger dimension development using X++.
There are number of methods which have been moved from DimStorage class to other classes in D365 F&O.
Here is the list of those methods.



Custom Business events Part 3 - (Activate custom business event) in D365 F&O

 In this blog we will discuss about the steps to activate a custom business in D365 F&O. As we know that business event catalog does not...