Context Menus (D365 for Finance and Operations)

Friends,

It has been long..Hope you are all well. Happy New year 2018.

In older versions of AX, We used right-click context menus (shortcut menus) by using the PopupMenu class

But in the current version, this can be achieved by using ContextMenu API and by overriding 2 methods getContextMenuOptions(), to add options to the context menu and selectedMenuOption() to process the user’s selection

Lets create a new form as shown below by name SRContextMenu. I have added CustGroup Table as a dataSource and in the design I have added CustGroup control to the grid.

 

image

Lets see the coding part to achieve this now. Override the classDeclaration method of the form/element and add the below line of code

[Form]

public class SRContextMenu extends FormRun

{

    public const int rootIdx = 1;

}

Then override the getContextMenuOptions method as shown below from the CustGroup control

image

Add the below lines of code in the method. In the below example, I am adding a new new context menu option with the label – “Get customer balance(s )”

[Control("String")]

    class CustGroup_CustGroup

    {

        public str getContextMenuOptions()

        {

            str ret;

            ContextMenu menu = new ContextMenu();

            ContextMenuOption option = ContextMenuOption::Create("Get customer balance(s)", rootIdx);

            List menuOptions = new List(Types::Class);

            // Add label and ID of menu option

            menuOptions.addEnd(option);

            menu.ContextMenuOptions(menuOptions);

            return menu.Serialize();

        }

 

    }

Next override the selectedMenuOption() method as shown below from the CustGroup control

image

Add the below lines of code to Process the user selection from the context menu

// Define new override on the control for processing the user selection

        public void selectedMenuOption(int selectedOption)

        {

            CustTable custTable;

            AmountCur  balanceAmt;

 

            switch (selectedOption)

            {

                case1:

                    break;

                case rootIdx:

                    while select CustTable where CustTable.CustGroup == CustGroup.CustGroup

                    {

                        balanceAmt += CustTable.balanceMST();

                    }

                    info(strFmt("%1", balanceAmt));

                    break;

                default:

                    break;

            }

        }

Now, lets open the form and see the newly added Context menu option. Right click on the customer group control in the grid and you will find our newly created option as shown below.

 

image

Double click on the option and it will process the context menu option. In this example, I am showing all the customer balances of that particular customer group in the Infolog

image

Some guidelines before using context menus

 

  • The most important commands should be at the top of the menu.
  • Remove commands that don’t apply to the current state of the element that is the target of the right-click.
  • Right-click is a shortcut. Therefore, the commands on the context menu should always be available in other places on the page.
  • Don’t create submenus of context menus. Submenus are hard to use and aren’t touch-friendly.
  • Limit the number of menu items to five.

Happy D365ing,

image

Advertisements

Sending Email using X++ Code (AX7 /D365 for Operations)

Friends,

I was just researching on the emailing capabilities in D365 and found that SysINetMail, SysMailer and some of the smmOutlook classes are deprecated because these classes used predominantly client-side technologies that are no longer available

Below is the quick code snippet that can be used in D365 to send emails. Please note, this is just a untested sample code, with out any setups configured. please ensure all setups are done and improvise the code accordingly.

SysMailerFactory class internally used SysImailer* classes to send emails.

class SRSendEmail_D365

{       

    public static void main(Args _args)

    {  

        SysMailerMessageBuilder messageBuilder = new SysMailerMessageBuilder();

        Email   toEmail;

        Email   fromEmail;

         

        try

        {

            FromEmail = "sreddy@xyzcompany.com";

            toEmail   = "tester@xyzcompany.com";

 

            messageBuilder.setBody("Hello from D365", false);

            messageBuilder.setSubject("Email Test from D365");

            messageBuilder.addTo(toEmail);

            // Note: not calling setFrom() defaults to the current user for SMTP client, whereas

            // when sent to Outlook any setFrom() value will be ignored since profiles on the client are used

            messageBuilder.setFrom(fromEmail);

 

            // Open the generated email in the configured client

            // Sends a message interactively, allowing the user to view and modify the message before

            SysMailerFactory::sendInteractive(messageBuilder.getMessage());

            // Try using sendNonInteractive method too

        }

        catch (Exception::Error)

        {

            throw error("@SYS33567");

        }

    }

 

}

Happy Dax6ng,

image

Write to Excel (Create an Excel) using X++ Code (AX 7/D365 for Operations)

Hi all,

Below is the quick code snippet to export the data to excel/create an excel in AX 7/D365 for operations

Please note, in D365 we can achieve this through OfficeOpenXml namespace

Improvise it based on your requirement

using System.IO;

using OfficeOpenXml;

using OfficeOpenXml.Style;

using OfficeOpenXml.Table;

class SRWriteToExcel

{

    public static void main(Args _args)

    {

        CustTable custTable;

        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 = "Account Number";

            cell.set_Value(value);

            cell = null;

            value = "Currency";

            cell = cells.get_Item(currentRow, 2);

            cell.set_Value(value);

 

            while select CustTable

            {

                currentRow ++;

                cell = null;

 

                cell = cells.get_Item(currentRow, 1);

                cell.set_Value(CustTable.AccountNum);

                cell = null;

 

                cell = cells.get_Item(currentRow, 2);

                cell.set_Value(CustTable.Currency);

            }

            package.Save();

            file::SendFileToUser(memoryStream, ‘Test’);

           

        }

       

    }

 

}

Happy Dax6ng,

image

Read from Excel using X++ Code (AX7/ D365 for Operations)

Hi Friends,

Been long. Hope all is well. Work kept me busy.

Below is the code snippet which will be handy to read the data from excel using code in D365/ax 7

Please note that, in D365 SysExcel* classes have been deprecated.

Under your references node in solution explorer, add Microsoft.Office.InterOp.Excel reference

Use OfficeOpenXML namespace to achieve this. Improvise the below snippet based on your need.

using System.IO;

using OfficeOpenXml;

using OfficeOpenXml.ExcelPackage;

using OfficeOpenXml.ExcelRange;

 

class SRReadFromExcel_D365

{       

    public static void main(Args _args)

    { 

        System.IO.Stream            stream;

        ExcelSpreadsheetName        sheeet;

        FileUploadBuild             fileUpload;

        DialogGroup                 dlgUploadGroup;

        FileUploadBuild             fileUploadBuild;

        FormBuildControl            formBuildControl;

        Dialog                      dialog = new Dialog(“Import the data from Excel”);

 

        dlgUploadGroup          = dialog.addGroup(“@SYS54759”);

        formBuildControl        = dialog.formBuildDesign().control(dlgUploadGroup.name());

        fileUploadBuild         = formBuildControl.addControlEx(classstr(FileUpload), ‘Upload’);

        fileUploadBuild.style(FileUploadStyle::MinimalWithFilename);

        fileUploadBuild.fileTypesAccepted(‘.xlsx’);

 

        if (dialog.run() && dialog.closedOk())

        {

            FileUpload fileUploadControl     = dialog.formRun().control(dialog.formRun().controlId(‘Upload’));

            FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult();

 

            if (fileUploadResult != null && fileUploadResult.getUploadStatus())

            {

                stream = fileUploadResult.openResult();

                using (ExcelPackage Package = new ExcelPackage(stream))

                {

                    int                         rowCount, i;

                    Package.Load(stream);

                    ExcelWorksheet  worksheet   = package.get_Workbook().get_Worksheets().get_Item(1);

                    OfficeOpenXml.ExcelRange    range       = worksheet.Cells;

                    rowCount                  = worksheet.Dimension.End.Row – worksheet.Dimension.Start.Row + 1;

 

                    for (i = 2; i<= rowCount; i++)

                    {

                        info(range.get_Item(i, 1).value);

                        info(range.get_Item(i, 2).value);

                    }

                }

            }

            else

            {

                error(“Error here”);

            }

 

        }

    }

 

}

Happy Dax6ng

image

SBS Group’s AXIO Global Core Financial Solution Among First Microsoft Dynamics Solutions Available on Azure Marketplace

Friends,

I am very glad to share the news that SBS Group, a leading technology solutions and services firm, specializing in extending the Microsoft Dynamics platform with functional and industry specific solutions, announced today the availability AXIO Global Core Financials.

For more information, click here

To know more about AX Core and it’s offerings, click here.

Happy Dax6ng,

Removing a role to all or multiple users using X++ Code [Dynamics AX 2012]

Friends,

Below is the code snippet to remove a role to all or multiple users using X++ Code. In the below code, I have tried removing System administrator role to all the users except Admin and me. Please test the code before running it in any environments.

static void SR_RemoveRoleAccessToUsers(Args _args)

{

    SecurityRole        role;

    SecurityUserRole    userRole;

    UserInfo            userInfo;

 

    void removeFromSelectedUser(UserId  _userId, RecId  _recId)

    {

        fieldName                           userId;

        SysSecTreeRoles                     roleTree;

        SecurityUserRole                    securityUserRole;

        OMUserRoleOrganization              org;

        SecurityUserRoleCondition           condition;

        SecuritySegregationOfDutiesConflict conflict;

        RecId                               recId;

 

        userId  = _userId;

        recId   = _recId;

 

        ttsbegin;

 

        delete_from condition

        exists join securityUserRole

        where condition.SecurityUserRole == securityUserRole.RecId && securityUserRole.User == userId && securityUserRole.SecurityRole == recId;

 

        //<GEEEE>

        while select OMInternalOrganization, SecurityRole from org where org.User == userId && org.SecurityRole == recid

        {

            EePersonalDataAccessLogging::logUserRoleChange(org.SecurityRole, org.omInternalOrganization, userid, AddRemove::Remove);

        }

        //</GEEEE>

 

        delete_from org where org.User == userId && org.SecurityRole == recId;

 

        delete_from conflict where conflict.User == userId && ((conflict.ExistingRole == recId) || (conflict.NewRole == recId));

 

        //<GEEEE>

        EePersonalDataAccessLogging::logUserRoleChange(recId, 0, userId, AddRemove::Remove);

        //</GEEEE>

 

        delete_from securityUserRole where securityUserRole.User == userId && securityUserRole.SecurityRole == recId;

 

        ttscommit;

 

    }

 

    select role where role.Name == "System administrator"; // provide the role name to remove here   

   while select userInfo where (userInfo.id != ‘Admin’

        && userInfo.id != ‘sgirigari’) // ensure that you have admin role to run this job

    {

           removeFromSelectedUser(userInfo.id, role.RecId);

    }

    info("Removal process of role is complete.");

}

Please be careful in the above while select statement as you need to ensure that the job that is run by a developer should be added in the where clause (userInfo.Id != “Sgirigari”)to ensure that the job runs successfully as we are removing the System Administrator role. For any other role, you can ignore this where clause.

Happy dax6ng,

Sreenath Reddy

Do you want Dynamics AX to speak out messages for you ?(Text to speech) – Dynamics AX 2012 @ X++

Hi friends,

I was just trying my hands on text to speech library and developed a small class which will help to speak out the messages easily for you. This post will explain quickly how to convert text to speech using X++ by using System.Speech Library and you can explore from there Smile 

First, let’s add this library to our references Node. Go to AOT>> References >> Add references

clip_image001

Search for System.Speech in the list of assemblies, select it and click on Ok button

clip_image002

Now, let’s create a simple class by name SRSpeechSynthesizer

class SRSpeechSynthesizer

{

}

 

Add a new static method called speakAsync as shown below

 

public static void speakAsync(str _textToSpeak)

{

    System.Speech.Synthesis.SpeechSynthesizer synthesizer = new System.Speech.Synthesis.SpeechSynthesizer();

 

    synthesizer.set_Volume(100);  // 0…100

    synthesizer.set_Rate(-2);     // -10…10

 

    // Synchronous

    //you cannot perform any other function in your Windows Form until the "reader" object has completed the speech.

    //synthesizer.Speak(_textToSpeak);

 

    // Asynchronous

    synthesizer.SpeakAsync(_textToSpeak);

}

 

Now, you can use this class and method wherever you want.

 

For the sake of demo, I have used it in info class >> add method. The reason why I have added here is to speak out all the messages that get added during the any process. I know it’s annoying if there are many messages that gets added to the Infolog stack. (But choice is yours clip_image003 )

 

You can customize further by parameterizing this option specific to users (in the user options form).

Add the below lines of code to the add method.

if (session.clientKind() == ClientType::Client)

{

    SRSpeechSynthesizer::SpeakAsync(_txt);

}

clip_image004

 

That’s it. You can explore more on the System.Speech Library.

When you create a new SpeechSynthesizer object, it uses the default system voice. To configure the SpeechSynthesizer to use one of the installed speech synthesis (text-to-speech) voices, use the SelectVoice or SelectVoiceByHints method. To get information about which voices are installed, use the GetInstalledVoices method and the VoiceInfo class. (msdn). Also, ensure that audio device is installed and working fine.

 

Happy Dax6ng,

image