Pages

Sunday, January 1, 2017

Batch jobs in Dynamics 365

My intention was to test how batch jobs are working in new Dynamics 365.

At first configuration. Configure batch group. Please check mentioned blog post and see if your configuration is correct.

Additional check if Microsoft Dynamics AX Batch Management Service is Running.






Basic code for batch job.

class goBatchTest extends RunBaseBatch
{
    #define.CurrentVersion(1)
    #define.Version1(1)

    public boolean canGoBatchJournal()
    {
        return true;
    }

    public boolean init()
    {
        return true;
    }

    protected void new()
    {
        super();
    }

    public container pack()
    {
        return [#CurrentVersion];
    }

    public void Update()
    {
        CustTable custTable;

        while select firstonly10 custTable
        {
    
            info(strFmt("[%1] %2", custTable.AccountNum, custTable.name()));
        }
    }

    public void run()
    {
        #OCCRetryCount
        if (! this.validate())
            throw error("");

        try
        {
            ttsbegin;

            this.Update();

            ttscommit;
        }
        catch (Exception::Deadlock)
        {
            retry;
        }
        catch (Exception::UpdateConflict)
        {
            if (appl.ttsLevel() == 0)
            {
                if (xSession::currentRetryCount() >= #RetryNum)
                {
                    throw Exception::UpdateConflictNotRecovered;
                }
                else
                {
                    retry;
                }
            }
            else
            {
                throw Exception::UpdateConflict;
            }
        }

    }

    public boolean runsImpersonated()
    {
        return true;
    }

    public boolean unpack(container packedClass)
    {
        Version version = RunBase::getVersion(packedClass);
    ;
        switch (version)
        {
            case #CurrentVersion:
                [version] = packedClass;
                break;
            default:
                return false;
        }

        return true;
    }

    public boolean validate(Object _calledFrom = null)
    {
        if (false)
            return checkFailed("");

        return true;
    }

    server static goBatchTest construct()
    {
        return new goBatchTest();
    }

    static ClassDescription description()
    {
        return "Test batch job";
} static void main(Args args) { goBatchTest goBatchTest; goBatchTest = goBatchTest::construct(); if (goBatchTest.prompt()) goBatchTest.runOperation(); } protected boolean canRunInNewSession() { return false; } }

When you are coding and extending from classes, below screen shows how and what methods you can override.




Next thing is right click on batch class object and select Set as Startup Object. After that Ctrl+F5.

You should see this windows. Configure batch job as usually in older versions of Dynamics AX.


Check results in System Administration. Working as expected.



As I see in this very basic actions, I haven't found no changes to previous versions of Dynamics AX batch jobs. Everything seems to be pretty much the same, at least till that moment.

Wednesday, December 28, 2016

Form patterns report

Form pattern report can give you a lot of useful informations about how forms in Dynamics 365.

Create report from Visual Studio menu. It will iterate through all forms in AOT.

It will create CSV file type report. You can open it in Excel.

Let's describe columns:

Model - Model name where form belongs
Form - Form name
Style - Form style. You can find more here
Pattern - Top level pattern applied to that form
Controls - Indication how big form is
Covered controls - Number of covered controls by non custom pattern
Percent covered controls - Percent of covered controls by non custom pattern
Pattern Version - Pattern version
Unspecified count - Indicate how many controls doesn't have pattern applied
Custom count - How many controls do not fit to existing pattern

Based with this report you can track progress of work with your forms.

Wednesday, December 7, 2016

Deploying packaged in AX7

Today's plan is to move development between two enviroments. From development to test enviroments for example. We have two options. Using power shell and using LCS. Let's do this with power shell.

It's diffrent to we are used for. There are no XPO files. Now we have models and deployable packages.

To make things faster I have create new model dev7, create new class in that model.

Next thing is to create package.

 Select model from which package will created.




After Visual Studio will create package go to folder c:\Pckg in my case, where it was placed.
Extract zip file, run PowerShell as Administrator and start typing:

Get-ChildItem C:\Pckg\AXDeployablePackage_20161111_14_22_30 -recurse | Unblock-File -Confirm

This command will unblodck files. Now go to C:\Pckg\AXDeployablePackage_20161111_14_22_30  folder and perform steps.

Generation runbook. Following MSDN:
The runbook provides the sequence of steps that must be run to update the environment. The following illustration shows an example of a runbook file. Each step in a runbook is associated with an ID, a machine name, and step execution details.

.\AXUpdateInstaller.exe generate -runbookid="dev7_RB" -topologyfile="DefaultTopologyData.xml" -servicemodelfile="DefaultServiceModelData.xml" -runbookfile="dev7_RB.xml"

Import runbook into AX
.\AXUpdateInstaller.exe import -runbookfile="dev7_RB.xml" 

By this command you can check what runbooks you have imported and are ready to install
.\AXUpdateInstaller.exe list

Start importing to target enviroment
.\AXUpdateInstaller.exe execute -runbookid="dev7_RB"

Check runbook
.\AXUpdateInstaller.exe export -runbookid="dev7_RB" -runbookfile="dev7_RB.xml"

Below you can find more references about AX7 architecture.

References:
Design-Compile-Run Part1: 2012 Paradigms

Design-Compile-Run Part2: Design, Compile, Run in AX 2012

Design-Compile-Run Part3: Design, Compile, Run in AX7

Design-Compile-Run Part4: Paradigms in AX7

Install a deployable package



Tuesday, November 1, 2016

Create sales order, sales line and confirmation from X++ code in AX7

I have installed few days ago Virtual Machine with AX7. I have described it on my blog post.
Today I would like to write some code which was often used in older versions of AX system. Let's try to create sales order and sales line from X++ and after all confirm it. At the end I will compare to what we have in 2012/2009.

First thing what you have to do is model. Create model.

Name it. In this case it is Development7.

Select existing package and Next.

You should finish with following.

As you may see AOT is diffrent to what we are used to in previous versions. In my opinion moving development to Visual Studio gets better for Dynamics. And now I would like name X++ rather to X# because as I see C# and X++ are getting closer from year to year which is fine because both have their pros and cons.

Let's add standad job. You can do this by pressing right click on project name and select Add and naxt New Item...


Select Job.

Right click on more time on project name and this time select Properties. As you may see on screen below, what I'm doing is selecting company on which I would like to have orders and lines created. In this case it is BRMF company.




Below code. Code is almost the same as I'm using on AX 2012. We may assume at this moment that code in AX7 is the same as in AX2012. We will see in future how it is, when I will investigate new AX7.

public static void main(Args _args)
{
    SalesTable       salesTable;
    SalesLine        salesLine;
    SalesFormLetter  salesFormLetter;
    InventDim        inventDim;
    NumberSeq        numberSeq;
    
    numberSeq = NumberSeq::newGetNum(SalesParameters::numRefSalesId());
    numberSeq.used();
    
    // Sales table
    salesTable.SalesId = numberSeq.num();
    
    salesTable.CustAccount = "BRMF-000002";
    
    salesTable.ShippingDateRequested = today();
    
    salesTable.SalesType = SalesType::Sales;
    
    salesTable.initFromCustTable();
    
    if (!salesTable.validateWrite())
    
        throw Exception::Error;
    
    salesTable.insert();
    
    
    // Sales lines
    salesLine.SalesId = salesTable.SalesId;
    
    salesLine.ItemId = "BRMF020";
    
    salesLine.SalesQty = 2;
    
    inventDim.InventSiteId = "SAL-01";
    
    salesLine.InventDimId = InventDim::findOrCreate(inventDim).inventDimId;
    
    salesLine.createLine(true, true, true ,true ,true, true);
    
    
    // Confirmation
    salesFormLetter = SalesFormLetter::construct(DocumentStatus::Confirmation);
    
    salesFormLetter.update(salesTable);
    
    info(strFmt("Sales %1 created and confirmed.", salesTable.SalesId));
}


Right click on job and Set as Startup Object.


Run job by pressing F5. Sales order created.












Go to accounts receivables and all sales orders and find previously created. Select tab SELL. Find GENERATE group and click on Confirmation.



Sales order is confirmed.

Also we can see how line is looking,

It seems that a lot of code is reused from older AX versions in new AX7 which is fine for us. However as much as I'm reading I see there are a lot of new fantastic technologies which we will investigate in next posts.

Wednesday, October 26, 2016

AX7 on Oracle VirtualBox

I have started my advetures with AX7 today on my local machine.

To make things working you need:
  1. Set Virtualization on your CPU enabled
  2. Application where you can run VHD images. I have choosen VirtualBox from Oracle
  3. AX7 VHD Image
  4. Account on Office365
At first, check your settings in bios. Make you Virtualization Enabled. For me it is Intel Virtualization Technology.

Now following steps. Create virtual machine by pressing New.


Name it. In this case it is ax7.


 As much RAM as you can add is nice to have.


Select your VHD image.
 

Press Start button to run virtual machine. It will take some time to initiate windows. 

After some time you should see standard login prompt. Type password: pass@word1



















Run As Administrator Provisioning tool, type your Office 365 account and press Submit.
After some time you will be granted to administrator.




























Open IE. You will find this address. Open it. Login with your Office 365 credentials.




Once you have issues with login with your Office365 account try below trick:
  1. Start Visual Studio as Administrator
  2. Find in AOT CustTable Form for example
  3. Right click on it and Add to new project. 
  4. In your project right click on CustTable form and Set as startup object
  5. Go to Debug  and press Start without debugging




Monday, October 10, 2016

Upload blob data in AX. BinData class.

I would like to present you very user full class which is avaiable in 4, 2009 and 2012 versions of AX.

Everytime you have to work with blob type data in just few lines you can load and save fille in AX in container type field. Works on client and server side.

Below you can see example of how to load file to container and back, form container to file:

    BinData             binary;
    FilePath            filePath;
    FileIoPermission    perm;
    container           con;
    ;

    filePath = @"c:\temp\from.jpg";
    binary = new BinData();
    perm = new FileIoPermission(filePath, 'rw');
    perm.assert();
    binary.loadFile(filePath);
    con = binary.getData();
      
    binary.setData(con);
    binary.saveFile(@"c:\temp\to.jpg");


Please check MSDN to see more sources where from you can read and save data to.

Sunday, September 25, 2016

Document Data Sources and integration with Excel

On below video you can watch how to create document data sources service. Document data sources are used to integrate AX Queries with Excel. Excel must have installed PowerPivot plugin . Data from Document Services are only read-only. This integration can be used to create small, simple Bi system in your company.


You can also connect Document Services with Visual Studio. Just add service reference with correct address.
You can see example, written in C#.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ODATA_Test.MAN_CustomersNS;
using System.Net;

namespace ODATA_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var uri = new Uri("http://192.168.20.6:8104/DynamicsAx/Services/ODataQueryService" );
            ODataQueryService service = new ODataQueryService(uri);
            service.Credentials = new NetworkCredential { UserName = "***", Password = "***" , Domain = "***" };

            var query = from c in service.MAN_Customers
                        select c;

            foreach (MAN_Customers item in query)
            {
                Console.WriteLine(item.CustTable_AccountNum + " "   + item.DirPartyTable_Name);
            }

            Console.ReadKey();
        }
    }
}