Showing posts with label Batch jobs. Show all posts
Showing posts with label Batch jobs. Show all posts

Friday, 10 September 2021

Read JSON file data in AX 2009 using batch processing

Today, I will share the code snippet which can be used to read 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.


We will create a new class with name as 'JSONReaderWrapper' and add following methods in it.

class JSONReaderWrapper
{
   Newtonsoft.Json.Linq.JObject    jObject;
}

//Add these methods
public int getIntNode(str path)
{
    return this.traversePath(path);
}

public real getRealNode(str path)
{
    return this.traversePath(path);
}
public str getStringNode(str path)
{
    return System.Convert::ToString(this.traversePath(path));
}
public boolean isFound(str _path)
{
    return this.traversePath(_path) != null;
}
public void loadJson(str _json)
{
    ;
    jObject = Newtonsoft.Json.Linq.JObject::Parse(_json);
}

public static JSONReaderWrapper parseJson(str _json)
{
    JSONReaderWrapper reader = new JsonReader();
    ;

    reader.loadJson(_json);
    return reader;
}
private anytype traversePath(str                               path,
                             Newtonsoft.Json.Linq.JContainer   obj = jObject)
{
    List                            pathElements;
    ListEnumerator                  le;
    Newtonsoft.Json.Linq.JValue     value;
    Newtonsoft.Json.Linq.JToken     token;
    Newtonsoft.Json.Linq.JTokenType thisType,
                                    nestedType;
    Newtonsoft.Json.Linq.JObject    newObject;
    Newtonsoft.Json.Linq.JArray     newArray;
    str                             current,
                                    thisTypeString,
                                    nestedTypeString;

    #define.JObject("Newtonsoft.Json.Linq.JObject")
    #define.JArray ("Newtonsoft.Json.Linq.JArray")

    ;

    pathElements = strSplit(path, @".\/");

    le = pathElements.getEnumerator();

    if (le.moveNext())
    {
        current = le.current();

        thisType = obj.GetType();
        thisTypeString = thisType.ToString();

        switch (thisTypeString)
        {
            case #JObject:
                token = obj.get_Item(current);
                break;
            case #JArray:
                token = obj.get_Item(str2int(current) - 1);
                break;
            default:
                return null;
        }

        if (token)
        {
            nestedType = token.GetType();
            nestedTypeString = nestedType.ToString();

            if (nestedTypeString != #JObject && nestedTypeString != #JArray)
            {
                switch (thisTypeString)
                {
                    case #JArray:
                        return obj.get_Item(str2int(current) - 1);
                    case #JObject:
                        return obj.get_Item(current);
                    default:
                        return null;
                }
            }

            switch (nestedTypeString)
            {
                case #JObject:
                    newObject = Newtonsoft.Json.Linq.JObject::FromObject(token);
                    return this.traversePath(strDel(path, 1, strLen(current) + 1), newObject);
                case #JArray:
                    newArray = Newtonsoft.Json.Linq.JArray::FromObject(token);
                    return this.traversePath(strDel(path, 1, strLen(current) + 1), newArray);
                default:
                    return null;
            }
        }
        else
        {
            return null;
        }
    }
    else
    {
        return null;
    }
}

//Create another class which extends RunBaseBatch and add a method in it.

Json input string  = "{\"ItemDef\":[{\"ItemId\":\"Test1\",\"Price\":1},{\"ItemId\":\"Test2\",\"Price\":2},{\"ItemId\":\"Test3\",\"Price\":3}]}";
client server static  void readJsonFileData(str _jsonInput)
{
    str              jsonResult;
    System.Exception ex;
    str              itemId;
    str              quantity;
    str              conditionCode;
    real             intResult;
    container        jsonConResult;
    int              i;
    JSONReaderWrapper   reader;
;


    try
    {
        jsonResult = _jsonInput;

        new InteropPermission(InteropKind::ClrInterop).assert();

        reader = JSONReaderWrapper::parseJson(jsonResult);

        for (i = 1; reader.isFound(strfmt("ItemDef.%1.ItemId", i)); i++)
        {
            itemId = reader.getStringNode(strfmt("ItemDef.%1.ItemId", i));
             price = reader.getIntNode(strfmt("ItemDef.%1.Price", i));
             info(strfmt("%1 = %2", itemId, price));

        }


     }
     catch(Exception::CLRError)
     {
        ex = CLRInterop::getLastException().GetBaseException();
        error(ex.get_Message());
     }

}

Read files from folder in AX 2009 with batch processing

 Today, I will be discuss out how to read files from folder in AX 2009.

Below is the code snippet which can be used to read files from folder in ax 2009 using batch job.

public void readFilesFromFolder()

{

    #Evat_NL

    #File

    Filename                        baseFolder;

    Filename                        filename;

    Filename                        foundBaseFileNameVal;

    int                             itemCounter;

    System.IO.DirectoryInfo         directoryFolder;

    System.IO.FileInfo[]            files;

    System.IO.FileInfo              filelist;

    InteropPermission               permission;

    counter                         filesCount;

    counter                         i;

   ;

     filePath      = "D:\\MJ\\Test";

  

    permission  = new InteropPermission(InteropKind::ClrInterop);

    permission.assert();


    baseFolder = filePath;

    directoryFolder  = new System.IO.DirectoryInfo(baseFolder);

    files      = directoryFolder.GetFiles("*.json");  //Depending upon file type

    filesCount = files.get_Length();


    for (i = 0; i < filesCount; i++)

    {

        filelist               = files.GetValue(i);

        fileName        = filelist.get_FullName();

        foundBaseFileNameVal  = filelist.get_Name();


       if (System.IO.File::Exists(FileName))

       {

            //Read txt from file

       }

    }


       CodeAccessPermission::revertAssert();


}

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. 




Monday, 1 October 2018

Debug your batch job in D365FO

Today, I will be discussing about how to debug a batch job in D365FO. The process of debugging is bit easier in D365FO then compared to AX 2012.

All others steps are same with attach to process technique. Just need to select another process at a time of attachment.

1) Go to debug menu and select attach to process option.


















2) Select the batch.exe process and make sure show processes for all users is selected. 
Note : Batch Service has name batch.exe and its location is (C:\CustomerServiceUnit\DOBind\Packages\Cloud\AosWebApplication\
AosWebApplication.csx\roles\AosWeb\approot\bin ) –at least on locally deployed machines

















After attaching the process  symbols will be loaded. When you will execute your batch job at that time you will be able to debug X++ code.







Friday, 13 July 2018

Create a batch job

Today I will be discussing about how to create a batch job.  Below are the steps which are required to create a batch job.

1. Go to system administration module -> Inquiries -> Batch jobs -> batch jobs











2. It will open a screen of batch jobs. Click on File and select new. A record for batch job will be added. Now add job description and select view tasks.
3. Now add new task by clicking on file then on new button. It will create a new task and you have to set its class name and company account.















4. For class click on text box and it will open list of class.
Note : Your class should extend RunBaseBatch. Then it will be visible in below screen shot.
















5. Now set batch group and run location. I have selected server as run location and batch group empty.




6. Now close task screen and you will be back on batch job main screen. Here you can set recurrence of batch job. For this you will select recurrence and add parameters according your requirements.






















7. Now you will be observing that you job is in withhold status. In order to start its execution. Change its status to waiting by clicking on functions drop down. Select change status then waiting option.


















Keep checking your job by refreshing it. Its status will be change from waiting to executing and then to ended.  There are chances you job might encounter errors. You can check them by clicking on log button available in action pane.

Create batch job using x++

Today I will be discussing about how to create batch job through x++.  Before going in code lets discuss what are batch jobs.

Batch job : It is group of tasks that submitted to an AOS for automatic processing. These tasks can run sequentially or simultaneously. Additionally, we can create dependencies between one task and another which means that we can setup a different sequence of tasks, depending on whether an earlier task successfully processed or fails.

You can create batch jobs either manually or by code. But here I will be showing a code snippet for batch job creation through x++. I have created a job just for demonstration which will create batch jobs. .













Note:  TestDemo class is my custom class that extends runBaseBatch. It will have its own run method which will contain business logic.
.
public class TestDemo extends RunBaseBatch
{}

Batch job Id :  It will be recid of current batch job.
SysRecurrence : This sysRecurrence class will be used to set recurrence of job. You may set it to default recurrence or as per your requirements
SysRecurrenceUnit : This method will be used to set count for retry. It need parameters and i have choosen 1 minute for retry.
Batchinfo : It will give batch information.
AddTask   : It will create /add task in batch job.Two parameters are required in this method one is  yourclassname and another is batchjobid.
parmCaption : It will be used for setting caption of job.

Tip : You can use this code for creating a single batch job with single task and as well as multiple task. It depend upon your requirements whether you want multiple task in parallel for instance dependency task.

For dependency task use this method : batcheader.addDependency(batchtask2, batchtask1, batchDependencyStatus::FinishedOrError);




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