Wednesday, 29 September 2021

Difference Between Edit And Display Method in Ax

Display Method:

The display method means that the method’s return value is being displayed on a form or a report. This value is fixed and cannot be edited on the form or report. If a user only wants to display the value display method is used.


Edit Method: 

Edit methods are basically the same as display methods. Edit indicates that the method’s return type is to be used to provide information for a field that is used in a form. The value in the field can be altered and that users can also write data to the fields.

Setting default field value in AX

Using table initValue() we can set default values of any table field during creating a new record. This can also be done on a form level so that the value will only be set for the specific form. Here is the example, let's suppose the table is yourTable and fields are currentDate, YourField

public void initValue() { super(); // setting current date time yourTable.currentDate = this.Now();

//setting any default value yourTable.YourField = "Default value";

}

Thursday, 9 September 2021

lookupReference method on form data source field in AX / X++

 public Common lookupReference(FormReferenceControl _formReferenceControl)
{
    HcmWorker HcmWorker;
    Query query = new Query();
    QueryBuildRange         queryBuildRange, qbr1;
    QueryBuildDataSource    qbds, qbds1, qbds2, qbds3, qbds4, qbds5;
    SysReferenceTableLookup sysTableLookup;
    qbds = query.addDataSource(tableNum(HcmWorker));
    qbds1 = qbds.addDataSource(tableNum(DirAddressBookPartyView));
    qbds1.addLink(fieldNum(DirAddressBookPartyView,RecId),fieldNum(HcmWorker, Person));
    qbds2= qbds1.addDataSource(tableNum(RetailStoreAddressBook));
                     qbds2.addLink(fieldNum(RetailStoreAddressBook,AddressBook),fieldNum(DirAddressBookPartyView,AddressBook));

    qbds3= qbds2.addDataSource(tableNum(RetailStoreTable));
    qbds3.addLink(fieldNum(RetailStoreTable,RecId),fieldNum(RetailStoreAddressBook,StoreRecId));
    qbds4 =qbds3.addDataSource(tableNum(LedgerJournalName));
    qbds4.addLink(fieldNum(LedgerJournalName, SL_RetailStoreId),fieldNum(RetailStoreTable,StoreNumber));

    sysTableLookup = SysReferenceTableLookup::newParameters(tableNum(HcmWorker), _formReferenceControl, true);
    sysTableLookup.addLookupField(fieldNum(HcmWorker,personnelNumber));
    sysTableLookup.addLookupField(fieldNum(HcmWorker, Person));

    qbr1 = qbds2.addRange(fieldNum(RetailStoreAddressBook,AddressBookType));
    qbr1.value(queryValue(RetailAddressBookType::Employee));

    queryBuildRange = qbds4.addRange(fieldNum(LedgerJournalName,JournalName));
    queryBuildRange.value(queryValue(journalName));

    sysTableLookup.parmQuery(query);

    return sysTableLookup.performFormLookup();
}

Find Current Exchange rate using X++ / Ax

Below is the code to find the current exchange rate of given currencies in X++

static void CurrentExchangeRate(Args _args)
{
    ExchangeRate     exchangeRate;
    ExchangeRateType ExchangeRateType; 
    ExchangeRateCurrencyPair exchangeRateCurrencyPair;
    real             exchRate;
    
    CurrencyCode fromCurrency  = "USD";
    CurrencyCode toCurrency    = "PKR";
    TransDate    transDate     = today();
    
    select firstonly exchangeRateCurrencyPair 
        where 
        exchangeRateCurrencyPair.ExchangeRateType 
        == Ledger::find(Ledger::current()).DefaultExchangeRateType
        &&  exchangeRateCurrencyPair.FromCurrencyCode == fromCurrency 
        &&  exchangeRateCurrencyPair.ToCurrencyCode   == toCurrency;

        exchRate = exchangeRate::findByDate(exchangeRateCurrencyPair.RecId,
            transDate).ExchangeRate;
    
    info(strFmt("Exchange Rate = %1",exchRate/100));
    
}

Send notification/ alert using X++ in Ax 2012

 Here is the X++ code to send the custom notification alert in Ax 2012.

static void SendNotificationAlert(Args _args)
{
    EventInbox  EventInbox,inbox;
    EventInboxData  eventInboxData;
    SysUserInfo SysUserInfo;
    int64 inboxId;
    ;

    ttsBegin;
        select SysUserInfo 
            order by SysUserInfo.Id 
            where SysUserInfo.Id== curUserId();

    { 
        select maxof(inboxId) from inbox;
        inboxId = EventInbox::nextEventId();
        EventInbox.CompanyId              =   curext();
        EventInbox.AlertTableId           =   212;
        EventInbox.AlertCreatedDateTime   =   DateTimeUtil::utcNow();
        EventInbox.ParentTableId          =   212;
        EventInbox.IsRead                 =   NOYES::No;
        EventInbox.Subject                =   "Notification Received ..";
        EventInbox.AlertedFor             =   "Notification Testing .. "; 
        EventInbox.UserId                 =   SysUserInfo.Id;
        EventInbox.ShowPopup              =   NOYES::Yes;
        EventInbox.Visible                =   NOYES::Yes;
        EventInbox.Message                =   'Notification Received ..!!';
        EventInbox.NotificationType       =   EventNotificationType::Information;
        EventInbox.insert();

        eventInboxData.DataType           =  EventInboxDataType::Context;
        eventInboxData.InboxId            =  inboxId;
        eventInboxData.insert();

        info("Notification sent");

    }

    ttsCommit;
}

Wednesday, 8 September 2021

Difference between Ax 2012 and D365FO (AX 7)

Microsoft Dynamics 365FO (AX 7) is web-based and there is no separate client.

For development, Microsoft Dynamics 365FO (AX 7) uses Visual Studio (VS) IDE whereas the older version Ax 2012 uses MorphX. 

MorphX


Visual Studio

The other difference is Dynamics 365 for Operations is an introduction to Extensions. This extends the functionality of elements without overriding the existing ones.

The other main difference is the architecture.



Microsoft Dynamics AX 2012 different form styles are available where in Ax 7 Form patterns are introduced which makes development easier.

Another is the Introduction of data entities in Dynamics D365 Finance and Operations 

Access Form Controls In Form pre/post Event Handlers in Dynamics 365 for Operations (AX7)

This blog will explain all possible ways where form control can be accessed in form using event handlers at different form levels. Events on a form are available at the form level, form control level and on the datasources level in Dynamics 365 for Operations (AX7).

We will access the form control in following

  1. Form’s Method pre/post Event Handlers
  2. Form’s  Event Handlers
  3. Form’s DataSource Event Handlers
  4. Form’s Control Event Handlers
  5. Class’s Method Event Handlers

Form Control Access in Form’s Method pre/post Event Handlers

For example, we are using the CustTable form. and using the init method pre-event handler. we are going to access the CustTable_name control in the event handler. Both pre post event contail XppPrePostArgs class parameter. This will provides information about arguments and return values for event handlers. 




In Form’s Event Event Handlers





In Form’s DataSource Event Handlers





Form’s Control Event Handlers





In Class’s Method Event Handlers







Tuesday, 7 September 2021

Compile Ax 2012 using command prompt / AX compilation using AXBuild

Firstly, stop the AOS service before starting the compilation

Open the command prompt and type the below command to compile Ax 2012. You can found AXBuild below location. first, change the directory by copy-paste below command

cd C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin

Next, enter the command for compilation

AXBuild.exe xppcompileall /s=01 

here s = 01 is the server-id


AxBuild.exe can accomplish a full compile of all X++ code which is faster than compiling form MorphX client menu.

For more details visit https://docs.microsoft.com/





Microsoft D365FO/ AX Interview Questions

Here is a list of questions that we think are best to prepare for the Dynamics interview


  1. Difference between AX2012 and D365FO
  2. How to perform Customization on forms, tables, classes in D365FO
  3. Explain Event handlers
  4. Difference between Display and edit method.
  5. Override methods in tables, forms.
  6. Difference between the temp table and the container?
  7. Difference between In-Memory and TempDB
  8. Types of reports are there in Ax
  9. Report development steps
  10. What is Chain of Command 
  11. Types of delete action?
  12. DIXF Framework
  13. What is the development environment used in D365FO?
  14. Difference between form init() & DS init()
  15. Types of Table groups
  16. Differentiate Refresh (), Reread (), Research (), Executequery ()?
  17. Difference Between Pass By Reference And Pass By Value
  18. Different ways to create lookups in AX 
  19. Difference between Primary & Cluster index.
  20. Main classes in report development  
  21. What Is User Interface Builder Class?
  22. what are maps in Ax?
  23. What are views in d365?
  24. What is the difference between overloading and overriding?
  25. What is Polymorphism? how it works in AX?
  26. How to create a model in D365FO?
All the best !!!

CurrencyExchangeHelper class in Ax / X++

In AX 2012, a class CurrencyExchangeHelper is available to do conversions from one currency to another. Here are some important examples

This method will convert amounts from one currency to another currency:

Static void main(Args args)
{
CurrencyExchangeHelper currencyExchangeHelper;
AmountMst convertedamount;
CurrencyCode FromCurrency =  ‘USD’;
CurrencyCode toCurrency =  ‘EUR’;    
        AmountMst amountToConvert = 5000;
TransDate transactionDate = systemDateGet();

//initializing class CurrencyExchangeHelper
currencyExchangeHelper = CurrencyExchangeHelper::newExchangeDate(Ledger::current(), transactionDate);

//converting AED to USD
        convertedamount =  currencyExchangeHelper.calculateCurrencyToCurrency(toCurrency, fromCurrency, amountToConvert, true); 
 
info(strFmt(“Converted Amount: %1”, Convertedamount));
}

transaction currency into accounting currency:

Static void main(Args args)
{
CurrencyExchangeHelper currencyExchangeHelper;
AmountMst convertedamount;
CurrencyCode transCurCode = ‘EUR’;   
        AmountMst amountToConvert = 5000;
TransDate transactionDate = systemDateGet();
//initializing class CurrencyExchangeHelper
currencyExchangeHelper = CurrencyExchangeHelper::newExchangeDate(Ledger::current(), transactionDate );

//converting Transaction To Accounting
    convertedamount =  currencyExchangeHelper.calculateTransactionToAccounting(transCurCode, amountToConvert, true);  
info(strFmt(“Converted Amount: %1”, Convertedamount));

}

accounting  currency into transaction currency:

Static void main(Args args)
{
CurrencyExchangeHelper currencyExchangeHelper;
AmountMst convertedamount;
CurrencyCode AccCurCode = ‘USD’;   
        AmountMst amountToConvert = 5000;
TransDate transactionDate = systemDateGet();
//initializing class CurrencyExchangeHelper
currencyExchangeHelper = CurrencyExchangeHelper::newExchangeDate(Ledger::primaryLedger(CompanyInfo::findDataArea("ISL").RecId), transactionDate );

//converting accounting into trancastion currency
    convertedamount =  currencyExchangeHelper.calculateAccountingToTransaction(AccCurCode, amountToConvert, true);  

info(strFmt(“Converted Amount: %1”, Convertedamount));

}



Thursday, 2 September 2021

Get Company Currency in X++ / AX

Here is the one-line code to get company currency

static void  main(Args _args)
{
    info(CompanyInfo::standardCurrency());
    info(Ledger::accountingCurrency(CompanyInfo::current());
}

SQL In Operator in X++ / D365FO

Sometimes we need to select the records only if the field value is in a set of expected values. Microsoft Introduce In Operator in X++ in D365FO. Remember this can only be used for enum type fields

First, you need to assign containers with specified values. Here is sample code where the query selects only the records with status delivered, Sales, Invoice in where clause

Static void main(Args args)
{
SalesTable  salesTable;
container con = [SalesStatus::Delivered, SalesType::Sales,  SalesStatus::Invoiced];
 
select from salesTable
where salesTable.SalesStatus in con;
}

Wednesday, 1 September 2021

Converting amount in words using X++

During SSRS report development in ax sometimes we have a requirement to convert the amount into words, unfortunatly in SSRS report level, there is no such method available. You have to write VB code to do it.

The more simple solution would be to write the code in the report data provider class to perform conversion and store it into a field that can easily be used in the SSRS report

Here is the code you can convert the amount in words in Ax / D365FO 

private String255 AmountInWords(real _amount)

{

     int             amount;

     String255             amount2Words;

    amount       = real2int(round(_amount , 1));

    amount2Words = Global::numeralsToTxt(amount);

    amount2Words = subStr(amount2Words,5,strLen(amount2Words)-4);

    amount2Words = subStr(amount2Words,strLen(amount2Words)-10,-strLen(amount2Words));

    amount2Words = (amount2Words) + ' Only';

    return amount2Words;

}

there is a builtin function available in Global class as well, you can try this as well

Global::numeralsToTxt(Amount)


Tuesday, 31 August 2021

Get item Category hierarchy using X++ in Ax / D365FO

Here you can find the X++ code to get complete item Category hierarchy using X++ in Ax

Static void main(Args args)

ItemId itemId = "MT0001";
EcoResProductCategory EcoResProductCategory;
EcoResCategory EcoResCategory,EcoResCategoryNext;
EcoResCategoryId parentCategory;
List li = new List(Types::String);
ListEnumerator enumer;

select * from EcoResCategory
join RecId from EcoResProductCategory
where EcoResCategory.RecId == EcoResProductCategory.Category
&& EcoResProductCategory.Product == InventTable::find(itemId).Product;
parentCategory = EcoResCategory.ParentCategory;
li.addStart(EcoResCategory.Name);

while (parentCategory)
{
    select * from EcoResCategory
        where EcoResCategory.RecId == parentCategory;
    //&& EcoResCategory.ParentCategory != 0;
        parentCategory = EcoResCategory.ParentCategory;
        li.addStart(EcoResCategory.Name);
}

enumer = li.getEnumerator();

while (enumer.moveNext())
{
    info(enumer.current());
}
}

Find item attributes using X++ in Ax and D365FO

 static void GetAttribute(Args _args)

{

    inventTable                 InventTable;

    EcoResProductAttributeValue ecoResProductAttributeValue;

    EcoResAttribute             ecoResAttribute;

    EcoResValue                 ecoResValue;

    while select InventTable where InventTable.itemid == "0000001"

        join RecId from ecoResProductAttributeValue

        where ecoResProductAttributeValue.Product == InventTable.Product

            join Name from ecoResAttribute

            where ecoResProductAttributeValue.Attribute == ecoResAttribute.RecId

                join ecoResValue

                where ecoResValue.RecId == ecoResProductAttributeValue.Value

    {

        info(strFmt("%1 - %2 - %3", InventTable.ItemId, ecoResAttribute.Name, ecoResValue.value()));

    }

}

Financial Dimension Lookup using X++ in Ax 2012 and D365 for Finance and operations

X++ code to create  Financial Dimension Lookup by name

public void LocationDimLookup(FormStringControl _control)
{
    DimensionAttribute                  dimensionAttribute;
    DimensionAttributeDirCategory       dimAttributeDirCategory;
    Query                               query = new Query();
    SysTableLookup                      sysTableLookup;
    dimensionAttribute = DimensionAttribute::findByName('Location');

    if (dimensionAttribute.Type == DimensionAttributeType::CustomList)
    {
        select firstonly DirCategory from dimAttributeDirCategory where dimAttributeDirCategory.DimensionAttribute == dimensionAttribute.RecId;
        sysTableLookup = SysTableLookup::newParameters(tableNum(DimensionFinancialTag), _control);

        // Add name field to be shown in the lookup form.
        sysTableLookup.addLookupfield(fieldNum(DimensionFinancialTag, Value));
        sysTableLookup.addLookupfield(fieldNum(DimensionFinancialTag, Description));

        query = new Query();
        query.addDataSource(tableNum(DimensionFinancialTag)).
        addRange(fieldNum(DimensionFinancialTag, FinancialTagCategory)).
        value(queryValue(dimAttributeDirCategory.DirCategory));
        sysTableLookup.parmQuery(query);

        // Perform the lookup.
        sysTableLookup.performFormLookup();
    }
}

Sending Email using X++ / Sending Email in Ax / D365FO/ Ax 7

 Here is the complete class for sending email notifications in Ax and D365FO. Make sure the email template is already created

/// <summary>
/// Class can  be used for sending email
/// </summary>
class EmailNotification
{
    private  boolean isEmailSent(Map _mappings, str _recipientEmail, str _templateName)
    {
        boolean         isSucess;
        SysEmailTable   sysEmailTable;       
        sysEmailTable = sysEmailTable::find(_templateName);
        SysEmailMessageTable msg = SysEmailMessageTable::find(sysEmailTable.EmailId, sysEmailTable.DefaultLanguage);
        if (msg)
        {
            str messageBody = msg.Mail;
            messageBody = SysLabel::resolveLabels(messageBody, sysEmailTable.DefaultLanguage);
            messageBody = SysEmailMessage::stringExpand(messageBody, SysEmailTable::htmlEncodeParameters(_mappings));
            messageBody = strReplace(messageBody, '\n', '<br>');
            var builder = new SysMailerMessageBuilder()
                .setFrom(sysEmailTable.SenderAddr)
                .addTo(_recipientEmail)
                .setSubject(msg.Subject)
                .setBody(messageBody);
            var message = builder.getMessage();
            isSucess = SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(message);
        }
        return isSucess;
    }
    /// <summary>
    /// Sending single emails
    /// </summary>
    /// <param name = "_sysEmailTable">SysEmailTable buffer</param>
    /// <param name = "_mappings">Map</param>
    /// <param name = "_recipient">Recipient detail</param>
    /// <param name = "_attachment">File attachement</param>
    /// <returns>True/false</returns>
    private  boolean sendSingleMail(SysEmailTable   _sysEmailTable,
                                Map                 _mappings,
                                str                 _recipient,
                                FilenameOpen        _attachment = '')
    {
        boolean     isSucess;
        try
        {
            SysEmailTable::sendMail(_sysEmailTable.EmailId,
                                _sysEmailTable.DefaultLanguage,
                                _recipient,
                                _mappings,
                                _attachment,
                                '' ,
                                true,
                                _sysEmailTable.SenderName,
                                true); 
            isSucess  = true;
        }
        catch(Exception::Error)
        {
            isSucess = false;
        }
        return isSucess;
    }
    /// <summary>
    /// Method used for sending email
    /// </summary>
    /// <param name = "_emailTemplate">Email template name</param>
    /// <param name = "_mappings">Map</param>
    /// <param name = "_recipient">Recipient detail</param>
    /// <param name = "_attachment">File attachement</param>
    /// <returns>True/false</returns>
    public Static boolean sendEmail(str         _emailTemplate,
                                Map             _mappings,
                                str             _recipient   = '',
                                FilenameOpen    _attachment  = '')
    {
        SysEmailTable           sysEmailTable;
        boolean                 isSucess;
        sysEmailTable           = SysEmailTable::find(_emailTemplate); 
        EmailNotification emailNotification   =   new EmailNotification();
        if (sysEmailTable)
        {
            isSucess = emailNotification.isEmailSent(_mappings, _recipient, _emailTemplate);
        }
        else
        {
            info(strFmt("Email Template Not Found"));
        }
        return isSucess;
    }
}

Get Worker Primary Position in valid date time in X++ / Worker Primary Position in Ax

Here is the X++ code to find  Worker Primary Position in given date time

public static HcmWorkerPrimaryPosition findByWorker(

    HcmWorkerRecId      _worker,

    utcdatetime         _validFrom = DateTimeUtil::utcNow(),

    utcdatetime         _validTo   = _validFrom,

    boolean             _forUpdate = false,

    ConcurrencyModel    _concurrencyModel = ConcurrencyModel::Auto)

    {

        HcmWorkerPrimaryPosition hcmWorkerPrimaryPosition;


        hcmWorkerPrimaryPosition.selectForUpdate(_forUpdate );

        if (_forUpdate && _concurrencyModel != ConcurrencyModel::Auto)

        {

            hcmWorkerPrimaryPosition.concurrencyModel(_concurrencyModel);

        }


        if (_worker)

        {

            if (prmisdefault(_validFrom) && prmisdefault(_validTo))

            {

                select firstonly hcmWorkerPrimaryPosition

                    where hcmWorkerPrimaryPosition.Worker == _worker;

            }

            else if (_validFrom == _validTo)

            {

                select firstonly ValidTimeState(_validFrom) hcmWorkerPrimaryPosition

                    where hcmWorkerPrimaryPosition.Worker == _worker;

            }

            else

            {

                select ValidTimeState(_validFrom, _validTo) hcmWorkerPrimaryPosition

                    where hcmWorkerPrimaryPosition.Worker == _worker;

            }

        }


        return hcmWorkerPrimaryPosition;

    }


current database name in Ax

There is a class available in AX SysSQLSystemInfo. Using this we can get the current database name

static void databse_name(Args _args)
{
    info(SysSQLSystemInfo::construct().getloginDatabase());
}

Creating Default Dimension using X++ / D365FO / AX-2012

X++ code to create default dimension in both D365FO and AX-2012

public class DefaultDimesnionHelper

{

    public static DimensionDefault createDefaultDimension(container conAttribute,container attributeValue)
    {
        DimensionAttributeValueSetStorage   valueSetStorage                     new DimensionAttributeValueSetStorage();
        DimensionDefault        result;
        DimensionAttribute      dimensionAttribute;
        DimensionAttributeValue dimensionAttributeValue;
        int                     i;
        
  
        container               conAttr = conAttribute;
        container               conValue = attributeValue;
        str                     dimValue;
  
        for (i = 1; i <= conLen(conAttr); i++)
        {
            dimensionAttribute = dimensionAttribute::findByName(conPeek(conAttr,i));
      
            if (dimensionAttribute.RecId == 0)
            {
                continue;
            }
      
            dimValue = conPeek(conValue,i);
      
            if (dimValue != "")
            {
                // The last parameter is "true". A dimensionAttributeValue record will be created if not found.
                dimensionAttributeValue =
                    dimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute,dimValue,false,true);
          
                // Add the dimensionAttibuteValue to the default dimension
                valueSetStorage.addItem(dimensionAttributeValue);
            }
        }
  
        result = valueSetStorage.save();
        return result;
    }
}

Get Employee Dimensions using X++

 X++ code to find employee dimension

static void employeeDim(Args _args)

    {
        HcmEmployment                         hcmEmployment;
        DimensionAttributeValueSetItem  setItem;
        DimensionAttributeValue              dimAttrValue;
        DimensionAttribute                      dimAttribute;
        ;

        dimAttribute    = DimensionAttribute::findByName('CostCenter');

        while select hcmEmployment
              join RecId, DisplayValue from setItem
              where setItem.DimensionAttributeValueSet ==
              hcmEmployment.DefaultDimension
              join dimAttrValue
              where dimAttrValue.RecId == setItem.DimensionAttributeValue &&
              dimAttrValue.DimensionAttribute == dimAttribute.RecId       &&
              dimAttrValue.IsDeleted == false
        {
            info(strFmt("Employee personnel number  = %1  %2 = %3 ",
           HcmWorker::find(hcmEmployment.Worker).PersonnelNumber,
           dimAttribute.Name, setItem.DisplayValue));
        }
    }

Get List of Tables using X++

 Here is the X++ code to find the complete list of tables in Ax 2012 and D365FO

public void getTableList()   

{
    SysDictTable sysDictTable;
    Dictionary dict = new Dictionary();
    DictTable dictTable;
    
    for (int i=1; i<=dict.tableCnt(); i++)
    {
        sysDictTable=new SysDictTable(dict.tableCnt2Id(i));
        }
}

Difference Between Edit And Display Method in Ax

Display Method: The display method means that the method’s return value is being displayed on a form or a report.  This value is fixed and c...