Tuesday, April 26, 2016

X++ Get table property

This simple code illustrates the table property by X++.

static void Job19(Args _args)
{
    SysDictTable    sysDictTable;  
    TreeNode        treeNode;
    TableName       tableName = 'VendTable';
    TableId         tableId;
    ;
 
    tableId         = tableName2Id(tableName);
    sysDictTable    = new SysDictTable(tableId);
    treeNode        = sysDictTable.treeNode();
 
    info(strFmt('%1',tableName));
    info(strFmt('%1',tableId));  
    info(strFmt('%1',treeNode.AOTgetProperty("CreatedDateTime")));
    info(strFmt('%1',treeNode.AOTgetProperty("SaveDataPerCompany")));
}









































Tuesday, April 19, 2016

X++ Get the list of user with role

Hi, if we would like to display the user list with its role, we can use a kind of the following code. It isn't quite a good code as we should join all tables in the while select statement, however I got the display with '@sys..' and not found the solution yet, so I change a bit back to basic by adding one more select in it.

static void getUserWithRole(Args _args)
{
    UserInfo            userInfo;
    SecurityUserRole    securityUserRole;
    SecurityRole        securityRole;
   
    int i=0;
    ;

    while
    select userInfo
        join    securityUserRole
        where   securityUserRole.User == userInfo.Id
    {
        i++;
        if (i >= 5)
            break;
       
        info(userInfo.Id);    
       
        securityRole = null;
        select securityRole
        where  securityRole.RecId == securityUserRole.SecurityRole;
       
        if (securityRole)
        {
            info(securityRole.AotName);
            info(securityRole.Name);          
            info(securityRole.Description);                      
        }  
    }
}

The result if we write it in csv format, will looks like below. Until the next post!

Tuesday, April 12, 2016

X++ Create task to monitor batch running overnight and send email

Good morning! In real-life we have many batches which are scheduled to run overnight. This scenario will show how to create a task to check their status and send email to related supporters.

There are two sub tasks for this. They are:
1. Batch status checking
2. Sending email
3. Schedule task and configuration

Let's start with the class and other methods.

class batchMonitor extends RunBaseBatch
{
    boolean isCompleted;
    #define.filename(@'E:\aaa\batch.csv')


public container pack()
{
    return conNull();
}

public boolean unpack(container packedClass)
{
    return true;
}

public void run()
{
    this.genCSV();
    this.sendEmail();
}

} // end class


1. Batch status checking

This method will check batch status and write csv.

private void genCSV()
{
    // ------------- Declaration -------------
    BatchJob            batchJob;
    BatchJobHistory     batchJobHistory;
    BatchCaption        jobName;

    int                 i=0,
                        iMax=0;

    container           listOfJobName   = ['B001', 'B002'];

    str                 strCaption,
                        strRecurPeriod,
                        strBatchStatus;

    // Declaration: CSV file
    CommaTextIo         file;
    container           line,
                        lineHeader      = ['B001', 'B002'];
    #File
    ;


    // ------------- Process -------------
    isCompleted = true;

    // Check file availability
    file = new CommaTextIo(#filename, #io_write);
    if (!file || file.status() != IO_Status::Ok)
    {
       throw error("File cannot be opened.");
    }

    // Write header
    line = lineHeader;
    file.writeExp(line);

    // Write line
    iMax = conLen(listOfJobName);
    while (i < iMax)
    {
        i++;
        jobName = conPeek(listOfJobName,i);
        batchJob = null;
        batchJobHistory = null;

        select  *
        from    batchJob
        where   batchJob.Caption == jobName && batchJob.Status == BatchStatus::Waiting
            join        batchJobHistory
            order by    batchJobHistory.EndDateTime desc
            where       batchJobHistory.BatchJobId == batchJob.RecId;

        strCaption      = strFmt('"%1"',batchJob.Caption);
        strRecurPeriod  = batchJob.recurrenceText();
        strBatchStatus  = strFmt('%1',batchJobHistory.Status);

        if (strBatchStatus != 'Ended')
            isCompleted = false;

        // Write to file
        line = [strCaption,
                strRecurPeriod,
                strBatchStatus
               ];
        file.writeExp(line);

    }

    file.finalize();

}

2. Sending email

This method will send an email.

private void sendEmail(Args _args)
{
    str                                   sender    = 'test@test.com';  // mail id of the sender
    str                                   recipient = 'test@test.com';  // mulitple recipients can be specified
    str                                   cc        = 'test@test.com';  // mulitple cc id's can be specified
    str                                   subject   = 'Subject of the mail';
    str                                   body      = 'Content of the mail';

    List              toList;
    List              ccList;
    ListEnumerator    enumList;
    Set               permissionSet;
    System.Exception  exception;

    str                                     mailServer;
    int                                     mailServerPort;
    System.Net.Mail.SmtpClient              mailClient;
    System.Net.Mail.MailMessage             mailMessage;
    System.Net.Mail.MailAddress             mailFrom;
    System.Net.Mail.MailAddress             mailTo;
    System.Net.Mail.MailAddressCollection   mailToCollection;
    System.Net.Mail.MailAddressCollection   mailCCCollection;
    System.Net.Mail.AttachmentCollection    mailAttachementCollection;
    System.Net.Mail.Attachment              mailAttachment;
    ;
 
    //Prepare init value
    subject     = strFmt('Batch job status as of %1',today());
    body        = strFmt('Hi all\r\n\rPlease kindly see the batch job status as of %1 in the attached. The status is',today());
    if (isCompleted)
    {
        subject += ' - Completed';
        body += ' all completed.';
    }
    else
    {
        subject += ' - Failed';
        body += ' failed.';
    }
    body += '\r\n\rRegards\r\n\rMisterAAA';  

    try
    {
        toList = strSplit(recipient, ';');
        ccList = strSplit(cc, ';');

        permissionSet = new Set(Types::Class);
        permissionSet.add(new InteropPermission(InteropKind::ClrInterop));
        permissionSet.add(new FileIOPermission(#filename, 'test1'));
        CodeAccessPermission::assertMultiple(permissionSet);

        mailServer      = SysEmaiLParameters::find(false).SMTPRelayServerName;
        mailServerPort  = SysEmaiLParameters::find(false).SMTPPortNumber;
        mailClient      = new System.Net.Mail.SmtpClient(mailServer, mailServerPort);

        enumList = toList.getEnumerator();
        enumList.moveNext();

        mailFrom        = new System.Net.Mail.MailAddress(sender);
        mailTo          = new System.Net.Mail.MailAddress(strLTrim(strRTrim(enumList.current())));
        mailMessage     = new System.Net.Mail.MailMessage(mailFrom, mailTo);

        mailToCollection = mailMessage.get_To();
        while (enumList.moveNext())
        {
            mailToCollection.Add(strLTrim(strRTrim(enumList.current())));
        }

        enumList            = ccList.getEnumerator();
        mailCCCollection    = mailMessage.get_CC();
        while (enumList.moveNext())
        {
            mailCCCollection.Add(strLTrim(strRTrim(enumList.current())));
        }

        mailMessage.set_Priority(System.Net.Mail.MailPriority::Normal);
        mailMessage.set_Subject(subject);
        mailMessage.set_Body(body);

        mailAttachementCollection   = mailMessage.get_Attachments();
        mailAttachment              = new System.Net.Mail.Attachment(#fileName);
        mailAttachementCollection.Add(mailAttachment);

        mailClient.Send(mailMessage);
        mailMessage.Dispose();

        CodeAccessPermission::revertAssert();

        info("Email sent successfully");
    }
    catch (Exception::CLRError)
    {
        exception = ClrInterop::getLastException();
        while (exception)
        {
            info(exception.get_Message());
            exception = exception.get_InnerException();
        }
        CodeAccessPermission::revertAssert();
    }

}

3. Schedule task and configuration

     3.1 Create a folder on AOS server  - This is important as Batch is being run on Server side so we need a folder to keep the attachment file. In this case, it's E:\aaa.
     3.2 Check Outgoing email parameter

     3.3 Check Batch server parameter

     3.4 Schedule the class by the following job

static void batchSchedule(Args _args)
{
    BatchHeader     batchHeader;
    BatchInfo       batchInfo;
    RunBaseBatch    rbbTask;
    str sParmCaption = "Batch Monitoring";
    ;

    rbbTask     = new batchMonitor();
    batchInfo   = rbbTask.batchInfo();
    batchInfo.parmCaption(sParmCaption);
    batchInfo.parmGroupId(""); // The "Empty batch group".
    batchHeader = BatchHeader ::construct();
    batchHeader.addTask(rbbTask);
    batchHeader.save();
    info(strFmt("'%1' batch has been scheduled.", sParmCaption));
}

Finally, our task is in the batch list which can manage through dynamics ax standard. Thanks for reading. Until next post!

References:
Walkthrough: Extending RunBaseBatch Class to Create and Run a Batch [AX 2012]
Sending emails with CC and attachment in AX 2012

Monday, April 4, 2016

X++ Date and utcDateTime

I will consolidate the techniques relating to Date and utcDateTime here.

Conversion: Date to utcDateTime

Refer to Date to UTCDateTime Convertion Dynamics Ax 2012

Sometimes we might need to query the data on field 'createdDateTime' whose type is utcDateTime so this code will help to convert type Date to utcDateTime.

Value 0 to 86400 stand for the time period 00:00:00 to 23:59:59

date            exampleDate = 01\02\2015;    // it's 01-Feb-2015
utcDateTime     utcStartDate,
                utcEndDate;
CustTable       custTable;
;

utcStartDate  = DateTimeUtil::newDateTime(startDate,0);
utcEndDate    = DateTimeUtil::newDateTime(endDate,86400);

select  count(RecId)
from    custTable
where   custTable.createdDateTime >= utcStartDate &&
        custTable.createdDateTime <= utcEndDate;

-------------------------------------------------------------------------------------------------------------

utcDateTime: how to increase or decrease datetime value

Sometimes we might need to query the data on the specific range. This below would help to get idea to increase or decrease utcDateTime.

utcDateTime     currentday,
                yesterday;
;
    
currentday  = DateTimeUtil::utcNow();
yesterday   = DateTimeUtil::addDays(currentday, -1);    
yesterday   = DateTimeUtil::addSeconds(yesterday, 1);
    
info(strFmt('%1',currentday));
info(strFmt('%1',yesterday));










-------------------------------------------------------------------------------------------------------------

Conversion: numeric to Time (TimeOfDay)

we can convert numeric (0 - 86400) to TimeOfDay by following code.

TimeOfDay   aaa;
;
    
aaa = 3600;
info(time2Str(aaa, TimeSeparator::Colon, TimeFormat::AMPM));
    
aaa = 4200;
info(time2Str(aaa, TimeSeparator::Colon, TimeFormat::AMPM));
    
aaa = 10800;
info(time2Str(aaa, TimeSeparator::Colon, TimeFormat::AMPM));