Thursday, November 2, 2017

Models Projects and Packages in D365

Today we will highlight an important architectural change in Dynamics AX 365. In AX 2012, the only option we had was over-layering for any sort of customization/modification in the out of box functionality. We had models/projects as set of elements, as the part of a given layer. Each layer can have one or more models/projects. Models can be exported to files that have the .axmodel extension and projects can be exported to xpo file. In Ax 2012, models files and XPO's are used for deployment purpose.

How do we customize or modify any element in DAX365?

In DAX365, we have same elements reside in Application Explorer and these elements are objects such as tables, forms and classes, menu items etc. Customization of any object is done once it is added into a project and a project is linked or associated with a model.

Model:

Unlike AX2012, In DAX365, creating a model is mandatory thing for any sort of customization. A particular model can contain multiple Visual Studio projects. Therefore you can say it is a collection of projects and a single project can have all or subset of elements from originating model. However, association of a project is only with a single model. It is basically a unit of development/customization. Metadata for models is stored locally on an XML file called a descriptor XML.

Package:

As it is already mentioned that previously in AX 2012, we used XPO's and model as deployment unit. However in DAX365, we have packages for deployment purpose. A package may contain one or more models. In addition to elements of the model, this also includes model metadata which is the description data that define the properties and behavior of the model.  Also a package can be exported to a file which can then be deployed into a staging or production environment. In other words, you can say package is an independent set of layers and models.  It's also a set of folders that consists of XML files representing the elements in the system. In this way, a package can be viewed as a mini model store. Physically package translates directly to unit of compilation which is an assembly or DLL file. Packages can reference other packages that is similar to how .NET assemblies can reference each other.

Packages References:

Referencing a packages is useful, when it is required to reuse a functionality that exists in to another package. In this way, one or more packages can be combined to create a deployable package. And lastly, XML files are stored in the model directory that sit inside the package directory.

Layers:

Layers are the traditional AX concept but in D365, there is a new process where we extend layers as shown below.


Also when you create your model, you specify which layer the model is going to live in. However the importance of layer is quite minimal for instance, you are not required to provide a key for your model to live in that layer. Previously layers were single stack of code that over-layered upon each other. This new process uses layers but they are located in independent stacks.

This was only an architectural overview of Dynamics AX 365, I would further elaborate how do we customize the elements with some examples.

Go through links for further explanation and understanding and share your feedback on the post in comments section.



Friday, March 10, 2017

Refresh caller datasource in the list page AX 2012

Today I am going to share with you sample code for updating the caller datasource on list page action menu item. We normally refresh the caller data source on a normal form like this way.


FormRun callerForm;

callerForm = element.args().caller();

callerForm.dataSource().refresh();
callerForm.dataSource().reread();
callerForm.dataSource().research();

In case of a list page how would you get the grid to refresh since the list page does not allow any override methods, because it uses Interaction Class. However, if I am going to use an action menu item. Code sample provided bellow is useful for this purpose.



void main(Args _args)
{

FormDataSource   callerDataSource;

callerDataSource = _args.record().dataSource();
callerDataSource.refresh();


callerDataSource.reread();
callerDataSource.research(true);
}



Thanks to read the post and hope that will help you in refresh the caller data source both for list page and normal form.

Tuesday, November 15, 2016

Batch jobs in AX 2012

Today, I will demo about batch jobs in AX 2012. At first, I will let you explore the Batch Server Overview on msdn. You have to follow all the steps as given bellow:
1. Configure an AOS instance as the batch server. (Click System administration > Setup > System > Server configuration).

2. Create a new Batch Group, name it ProcessD (Click System administration > Setup > Batch group).
 3. Add available batch server for batch group that has been created.
Now we have to create and schedule a batch job. Let's say we are going to schedule a batch which will fetch the number of purchase orders that are invoiced and add the count in a table named PurchaseOrders. So let's add a custom table Purchase Orders adding two fields DateTill and TotalPurchaseOrder.
Now create a class "ProcessingDataBatch", set it run at server. Also make sure you extend it with RunBaseBatch to make it behave like a batch job.



class ProcessingDataBatch extends RunBaseBatch
{
}
private void processdata()
{
    PurchTable          purchTable;
    PurchaseOrders      purchaseOrder;
    ttsBegin;

    select count(PurchId) from purchTable
        where purchTable.PurchStatus == PurchStatus::Invoiced;

    if (purchTable.PurchId)
    {
        purchaseOrder.TotalPurchOrders = purchTable.PurchId;
        purchaseOrder.DateTill         = today();
        purchaseOrder.insert();
    }


    ttsCommit;
}
public void run()
{
   this.processdata();
}
public static ClassDescription description()
{
    return "Process Data";
}
public static void main(Args _args)
{
    ProcessingDataBatch scheduler = new ProcessingDataBatch();

    if (scheduler.prompt())
    {
        scheduler.run();
    }
}

Now next thing is to compile the code and Generate Increment CIL which is required to setup every time you update the code.

In order to deploy the above class as batch Process job, we can do it in two way. Either to create a ax job or a action menu item.

static void ProcessingData(Args _args)
{
    BatchHeader header;
    SysRecurrenceData sysRecurrenceData;
    Batch batch;
    BatchJob batchJob;
    ProcessingDataBatch _ProcessIncrement;
    BatchInfo processBatchInfo;
    BatchRetries noOfRetriesOnFailure = 4;
;

    select batch where batch.ClassNumber == classnum(ProcessingDataBatch);
    if(!batch)
    {
        header = BatchHeader::construct();
        _ProcessIncrement = new ProcessingDataBatch();
        processBatchInfo = _ProcessIncrement.batchInfo();
        processBatchInfo.parmRetriesOnFailure(noOfRetriesOnFailure);
        processBatchInfo.parmCaption("Process Data");
        header.addTask(_ProcessIncrement);
        // Set the recurrence data
        sysRecurrenceData = SysRecurrence::defaultRecurrence();
        SysRecurrence::setRecurrenceStartDateTime(sysRecurrenceData, DateTimeUtil::addSeconds(DateTimeUtil::utcNow(), 20));
        SysRecurrence::setRecurrenceNoEnd(sysRecurrenceData);
        SysRecurrence::setRecurrenceUnit(sysRecurrenceData, SysRecurrenceUnit::Minute);
        header.parmRecurrenceData(sysRecurrenceData);
        // Set the batch alert configurations
        header.parmAlerts(NoYes::No, NoYes::Yes, NoYes::No, NoYes::Yes, NoYes::Yes);
        header.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(ProcessingDataBatch);

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

}
When you execute this AX job, you would be able to see a new batch job created in waiting state at System Administration > Inquiries > Batch jobs > Batch jobs with caption Process Data.

 Another way is to add an action menu item ProcessingDataBatchSchedule
Open action menu item select the available batch group as created above and set the recurrence as needed.

See the batch job state here, you can specify alerts check logs and modify recurrence, remove or delete batch jobs etc. Hope this blog post is going to help you in start your work on batch jobs. You can explore the batch jobs in this post as well.