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));
        }
}

Get Current language in AX 2012 and D365FO

 Here is the X++ code to find the current language


static void main(Args _args)
{


info(companyinfo::languageId());

    // user
    info(new xInfo().language());\


    // system
    info(SystemParameters::getSystemLanguageId());

}

Scheduling Batch Job using X++

X++ code for  Scheduling Batch Job

static void JobSchedule(Args _args)

    {
        BatchHeader objBatchheader;
        SysRecurrenceData sysRecurrenceData;       
        BatchInfo objBatchInfo;
        BatchRetries noOfRetriesOnFailure = 0;
        Batch batch;
        BatchJob batchJob;
        RetailCDXScheduleRunner objRetailSchedule;
        ;

        // Setup the RunBaseBatch Job
        objBatchheader = Batchheader::construct();
        objRetailSchedule = new RetailCDXScheduleRunner();
        objBatchInfo = objRetailSchedule.batchInfo();
        objBatchInfo.parmRetriesOnFailure(noOfRetriesOnFailure);
        objBatchInfo.parmCaption("Description should be here"); // Description Batch Job
        objBatchInfo.parmGroupId('YourBatchGroup'); // Batch Gorup
        objBatchInfo.parmBatchExecute(NoYes::Yes);
        objBatchheader.addTask(objRetailSchedule);

        // Set the recurrence data
        sysRecurrenceData = SysRecurrence::defaultRecurrence();
        SysRecurrence::setRecurrenceStartDateTime(sysRecurrenceData, DateTimeUtil::addSeconds(DateTimeUtil::utcNow(), 20)); // Set range of recurrence
        SysRecurrence::setRecurrenceNoEnd(sysRecurrenceData);
        SysRecurrence::setRecurrenceUnit(sysRecurrenceData, SysRecurrenceUnit::Minute); // Set reccurence pattern
        objBatchheader.parmRecurrenceData(sysRecurrenceData);
        // Set the batch alert configurations
        objBatchheader.parmAlerts(NoYes::No, NoYes::Yes, NoYes::No, NoYes::Yes, NoYes::Yes);
        objBatchheader.save();

        // Update the frequency to run the job to every two minutes
        ttsbegin;
        select forupdate batchJob
            join batch
            where batchJob.RecId == batch.BatchJobId
            && batch.ClassNumber == classnum(RetailConnScheduleRunner);

        sysRecurrenceData = batchJob.RecurrenceData;
        sysRecurrenceData = conpoke(sysRecurrenceData, 8, [10]);
        batchJob.RecurrenceData = sysRecurrenceData;
        batchJob.update();
        ttscommit;
    }

Get ledger dimension values for active account structure in AX 2012 & D365FO

Here is the code  for  ledger dimension values for active account structure

public static DimensionValue getdimension(LedgerDimensionAccount _ledgerDimension, 

Name _dimensionName )

    {
        DimensionAttributeLevelValueAllView dimAttrView; //View that will display all values for ledger dimensionsDimensionAttribute dimAttr; 

        select DisplayValue from dimAttrViewwhere dimAttrView.ValueCombinationRecId == _ledgerDimension 
        return dimAttrView.DisplayValue;
    }

Monday 30 August 2021

Uploading and download file in D365FO

Create a simple form with two buttons file upload & download.

For Upload:

Using button clicked event: File::GetFileFromUser()

For Download:

For Download button: new Browser().navigate(fileUrl).


[Form]

public class SLD_UploadDownload extends FormRun
{
    str fileUrl;
 
    [Control("Button")]
    class UploadButton
    {
        public void clicked()
        {
            FileUploadTemporaryStorageResult result = File::GetFileFromUser() as FileUploadTemporaryStorageResult;
            if (result && result.getUploadStatus())
            {
                fileUrl = result.getDownloadUrl();
                info(fileUrl);
            }
        }
    }
 
    [Control("Button")]
    class DownloadButton
    {
        public void clicked()
        {
            new Browser().navigate(fileUrl);
        }
    }
}

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...