Quantcast
Channel: Dynamics NAVAX
Viewing all 219 articles
Browse latest View live

Generate SQL query for GL transactions [AX 2012]

$
0
0

In my last blog I did a demonstration of using an SQL query to build a PowerBI report for the general ledger transactions.

I hard coded the RecId for the financial dimensions. It might be cumbersome to build the query manual. So here I wrote a job you could run to get the query. It will spit out an infolog which you should be able to copy and paste.

static void navax_generateGLQuery(Args _args)
{
    DimensionAttribute  dimensionAttribute;
    str                 sqlStatement, dimNameStr, dimMaxStr, name;
    sqlStatement =
    @'
        SELECT
        GeneralJournalCube.*
        %1
        FROM GeneralJournalCube INNER JOIN
        (
            SELECT
            DAVC.RecId as CombinationId
            %2
            FROM
            DIMENSIONATTRIBUTEVALUECOMBINATION DAVC INNER JOIN
            DIMENSIONATTRIBUTEVALUEGROUPCOMBINATION DAVGC ON
            DAVC.RECID = DAVGC.DIMENSIONATTRIBUTEVALUECOMBINATION INNER JOIN
            DIMENSIONATTRIBUTELEVELVALUE AS DAVL ON
            DAVL.DIMENSIONATTRIBUTEVALUEGROUP = DAVGC.DIMENSIONATTRIBUTEVALUEGROUP INNER JOIN
            DIMENSIONATTRIBUTEVALUE AS DAV ON DAV.RECID = DAVL.DIMENSIONATTRIBUTEVALUE INNER JOIN
            DIMENSIONATTRIBUTE DA ON DA.RECID = DAV.DIMENSIONATTRIBUTE
            GROUP BY DAVC.RECID
        )
        Dimensions ON
        Dimensions.CombinationId = GeneralJournalCube.LEDGERDIMENSION
    ';
    while select ViewName, RecId, Type, Name from dimensionAttribute
    {
        if (dimensionAttribute.Type == DimensionAttributeType::CustomList)
        {
            name = dimensionAttribute.Name;
        }
        else
        {
            name = dimensionAttribute.ViewName;
        }
        dimNameStr += strFmt(',%1\n', name);
        dimMaxStr += strFmt(',MAX(CASE WHEN DA.RECID = %1 THEN DAV.ENTITYINSTANCE ELSE NULL END) AS %2\n', dimensionAttribute.RecId, name);
    }
    sqlStatement = strFmt(sqlStatement, dimNameStr, dimMaxStr);
    info(sqlStatement);
}

Its a bit crude but at least you get all the dimensions.

image


Multithreading with Business Operation Framework [AX 2012]

$
0
0

In this post I will discuss the basics of multi threading with business operations framework and I will provide a sample you can work with.

Multithreading can give you a huge performance boost if you could spin each process separately. The biggest hurdle with writing a process to work via multi threading can be a little confusing and time consuming to develop. So, what I have done is create a generic xpo project which I have used many times as a starting point.

Below is a screenshot of what the net result is of my sample project.

image

The xpo contains the following project.

image

Download xpo

The \Classes\Processor\process method is the main entry method. If it is run with out the batch it will execute each record separately.

Otherwise, if it is run in batch it will bundle the records based on a default bundle size (I have set it to 10). I then use a list to store the 10 customer recIds. The reason I bundle the records is because when you multithread, you may not want to process each record separately. As there maybe an overhead in spinning up each thread.

image

Then on the task class that is receiving the bundle, breaks up the list and gets all the RecIds.

image

Credit to both Klaas Deforche and Kenny Saelen who have written a great book on services. They have also written great posts on their blog.

http://www.artofcreation.be/2010/10/03/batch-multithreading/

http://www.ksaelen.be/wordpresses/dynamicsaxblog/2012/02/business-operation-framework-and-multi-threading/

KB3034554 - Ledger journal performance [AX 2012]

$
0
0

A bit of a spotlight on this KB. I wasn’t aware of for some time and now it is included in AX2012R3CU9.

Problem was that each line insert/update/delete caused a tax calculation. This was more prominent when importing large journals (several thousand lines).

The solution Microsoft provides in this KB is a technical solution. It gives you the ability to ignore tax calculations if you wanted to do it while importing (via AIF or custom code).

I have written something previously that discusses this.

http://dynamicsnavax.blogspot.com.au/2014/04/tips-to-improve-ledger-journal-import.html

 

https://fix.lcs.dynamics.com/Issue/Resolved/616114?kb=3034554&bugId=3360809&qc=0872aea67f72bae9e4f30e1e2f653e6071a7556b6589633dd4fdf521cd720f5b

clip_image002

clip_image004

Note: This new field is not part of the DIXF journal entity.

Here is a work around. Because the Fields in the query are set to Dynamic=No. Lets add it ourselves

image

Right click and add the field.

image

Refresh the target entity by either deleting and creating again. Or re generating the mapping.

Below I did not add a new field to the DMF staging table but you probably should to do it properly. I am just illustrating an idea.

image

Open journal line form is slow [AX 2012]

$
0
0

I have posted a few times about journal performance. Make sure to have a look at those.

This one is specifically about open the journal line form being slow. I tested with a 40,000 line journal.  Opening the form took about 7 minutes.

I ran the code profiler against it and found one particular method that took way too long. taxAmountJournal().

image

It ended up being a display method. This particular display method shows up on the form as “Calculated sales tax amount”.

After right click and hiding the field, the load of the form is instant. Same when jumping (focus) from line to line.

clip_image001

KB2996035 - Performance issues when printing 1000s of customer account statements

$
0
0

A bit of a spotlight on this KB. This is not in AX2012R3CU9 but available on LCS for download.

When you are printing a large number of customer statements it can take hours to print. This can be cut down dramatically.

I don’t have perfect stats but with our testing on a TEST box. It ran 2.5 times faster. Producing over over 3000 statements in 30minutes. I think with better infrastructure we can get much better results. (12GB x 4 Cores test box – was a shared box for other services) The more cores the faster it is.clip_image002

The installer contains 2 KBs in one.

clip_image004

clip_image006

The code is generic in nature but requires that you still make a small change to the code. Not sure if this was forgotten. Add this method to the controller class of the report.

image

Final result should show you a new check box “Use parallel processing”. If this is ticked then it will multi thread and the prints will be out of sequence.

If you don’t tick or see this flag, you are not multi-threading.

Resolve the ledger dimension in the a different account structure [AX 2012]

$
0
0

Recently I had a look at an error that occurred on a custom journal posting routine. It was somewhat similar the journal allocations by looking at existing transaction to make adjustment. What I didn’t know is the account structure has changed. An error popped up: Account structure X for the combination x-x-x-x-x, is not valid for the ledger X.

 image

When ever using ledger dimensions don’t just stamp the LedgerDimensionRecId. Use this method to resolve the RecId in the current account structure for the current company.

toLedgerDimension = DimensionDefaultingService::serviceCreateLedgerDimension(fromLedgerdimension);

I had to do a quick unit test to prove this. Below is a job that converts.

Code:
staticvoid resolveLedgerDimension(Args _args)
{
//My expected values are
//Dimension display value = '1.1.4.2.03--'
//Account structure and dimension From RecId - Brazil - 52565566264
//Account structure and dimension Resolved RecId - Brazil SI - 22565539091
RecId fromLedgerdimension = 52565566264;
RecId toLedgerdimension;
toLedgerdimension = DimensionDefaultingService::serviceCreateLedgerDimension(fromLedgerdimension);
info(strFmt("From RecId %1 to %2", fromLedgerdimension, toLedgerdimension));
info(strFmt("From Display value %1 to %2",
conPeek(AxdDimensionUtil::getLedgerAccountValue(fromLedgerdimension), 1),
conPeek(AxdDimensionUtil::getLedgerAccountValue(toLedgerdimension), 1)));
info(strFmt("From Account structure %1 to %2",
DimensionStorage::getAccountStructureFromLedgerDimension(fromLedgerdimension).Name,
DimensionStorage::getAccountStructureFromLedgerDimension(toLedgerdimension).Name));
}



In the AOT I found a dimension combination that existed in 2 account structures that are the same.


image


image

Complex grouping of records for processing [AX 2012]

$
0
0

In this post I will discuss complex grouping of records for processing in a batch.There are many ways to achieve this but most of the time I see developers using temp tables. I feel that is not necessarily the most best way. So, in this post I will show how you can do the same using a map and a RecordSortedList. Avoiding multiple loops through records and also avoiding temp tables.

Scenario

Assume a scenario where you have to loop through unsorted records. Group them by the multiple fields including things like financial dimension value and balance. Then create a journal for each group.

Options

This could be achieved in a number of ways. But we want the best performing and extendable solution.

  1. You could do a group by selection query but that won’t work as you have to get the balance and dimensions (which are calculations).
  2. You could use a temp table to insert all the transaction. What if the key changes a few months later. Could be costly to develop the changes.
  3. You could use a map to store the RecIds and fetch the records as you loop through the map. Now you are querying the database for each fetch. You maybe also calculating the dimensions and balances during grouping and processing.
  4. You could use a RecordSortedList to store them. In my opinion is the cleanest and best way of doing it.

I will show how to do it with option 4 – using a RecordSortedList. Below in the screenshot you have 3 classes.

  • NAVAX_Process – Main batch class that is executed.
  • NAVAX_ProcessHandler – Does the grouping of the records and storing them in their respective class instance which is group in a map.
  • NAVAX_ProcessTask – The processing task class. Has an execute method which you would put

image

The handler class creates a map to store a container as the key and the class instance as the value. The key is a container because we are going to group my multiple values. At the end we will loop through the map to call the execute method for each class instance that is stored.

image

The handler class has an addRecord method. This will do the grouping by storing the values in a key. This is where you would store the calculated values to group by (I am not doing it here but using the customer group and the delivery mode instead).

image

The execute method in the handler class loops through the map and calls the execute method of the class instance that was stored.

image

Result

In this example I am going to show the result in an infolog.

image

Download the xpo

Dynamics AX 7 Development I – Create a model

$
0
0

With the recent release of AX7 CTP8 public preview there are a lot of things to learn. I thought I would do some basic series of tutorials to explain a few concepts and how to get around for developers.

In this first one I will explain how to create a model.

Click on Dynamics AX > Model Management > Create model

image_thumb12

Follow the wizard by entering a name and a publisher

image_thumb4

This is very important if you want to create extensions or if you want to customise existing functionality by over-layering (which we try to avoid as much as we can).

image_thumb6

After you finished you can create a new project in that model.

image_thumb8

In the Application Explorer there are two views

  • Model View – Shows the AOT divided into its models. Each model has its own subset of the AOT (elements that belong in the model)
  • Classic View – Shows a single AOT classic view we are used to

You will notice in the Packages folder that the model folder was created under the application suite.

image_thumb13

Good reference material available under the wiki site

https://ax.help.dynamics.com


Dynamics AX 7 Development 2 – Create a new table

$
0
0

In continuation with my regular AX posts on development basics. In this post I will describe how to create a new table. I won’t go into detail about best practices/indexes/relationshipts etc. Just a basic table creation.

Right click the project > Add > New item

2016-01-11_1519

Create an EDT and give it a name.

2016-01-11_1522

Now drag the EDT tot he Fields section in the table design.

2016-01-11_1525

On the project property make sure to tick the “Synchorinse Database on Build”

2016-01-11_1524

Now build your project. This will build the code and synchornise the table to the database.

Right click and open in table browser. This will open up a window with all the table fields.

2016-01-13_0850

Dynamics AX7 Development 3–Create a new form

$
0
0

Lets have a look at creating a form. This is probably a little more exciting than the previous posts. As this is totally new to AX7.

Right click and Add > New

Select the Form object from the AX7 Artifacts

2016-01-14_1558

Initially it will show the pattern as unspecified. This is something we should always set if we expect our form to work across platforms (browsers). Otherwise we can set it to custom and it is free form. Which is a bit messy and unsupported.

2016-01-14_1600

Right click the Design and apply a pattern.

2016-01-14_1601

Once you have applied a pattern the bottom part of the form will show you the expected pattern. Now it is a matter of filling it up with the required control types.

Lets right click New > control we want to add.

2016-01-14_1608

Once you have added all your required controls.

Drag the table from the AOT to the Data Sources node. It should look something like this.

2016-01-14_1611

Now you can preview by clicking the tab.

2016-01-14_1613

Build your VS project. There should be no errors.

If you want to debug and run in a browser. Make sure to set the object as your Start Object.

2016-01-14_1614

Dynamics AX7 Development 4–Overlay or extend

$
0
0

In this post I will look at the decision of overlaying or extending. In AX7 you can extend metadata by adding a field to a table or adding a control to a form, and extend business logic by defining event handlers. You can now write event handlers on several pre-defined events on tables, forms, form data sources, form controls, and others.

Below we are going to look at a basic example comparing Overlay with Extending (using event handler). As mentioned there are many forms of extensions but for simplicity we will focus on one (event handler).

Overlay

Overlaying is when you modify existing code by changing the system behaviour. For example lets look at overlaying the initValue method on the CustTable.

Right click on the object and click Customize. This will add it to your project.

2016-01-19_0729

You will see a little [c] to indicate it is a customised object.

2016-01-19_0735

I added a bit of code to the initValue method. Notice how it has changed colour to indicate it has been customised.

2016-01-19_0738

Extension (using events)

Extensions are used in AX7 much more and is much more flexible. Extensions allow you to leave the system behaviour but adding your piece to it. In some cases you have to overlay but try to avoid that if possible. As overlaying may seem simple but it will cost you on upgrades, hotfixes, maintaining code and merging code.

Lets look at the same example but now using extensions.

On the CustTable right click and Opern designer.

2016-01-19_1608

Right click and copy the vent handler method (this will copy into clipboard).

2016-01-19_1607

Now create a class. Paste whats in clipboard. It will paste the highlighted section below.

Add your code. The vent will now be triggered after the initValue method.

2016-01-19_1610

Warning: Code block to update languageId is for illustration only. Not runnable.

More detail on the wiki page:

https://ax.help.dynamics.com/en/wiki/customize-model-elements-using-extensions/

Dynamics AX7 Development 5–More on extensions (Table extension)

$
0
0

Previous post compared the difference between overlaying and extending. It is clear the benefits of extensions.

So to continue that discussion, in this post I will look at extensions by adding a field to a table.

Right click on a table you want to extend (ie you want to add a new field).

2016-01-20_0951

This will create a table extension SalesTable.Extension. See that in the project (right hand side in the Solution Explorer).

Open up the table design.

You can now drag an EDT or create it by right clicking. The bold items are what have been added to the extension. The greyed items are what is in the base.

2016-01-20_1005

Thats it. We have added a new field to the table without having to modify the base table.

Dynamics AX7 Development 6–Adding Delegates for Customised Code in Higher Package

$
0
0

Dynamics AX is split into multiple models the main ones are as follows; Application suite, Application Foundation and Application Platform.

2016-01-20_1256

If you look at some of the debendencies you see how the organization of model affects the assemblies (how it is compiled).

Del1[1]

In some cases you have to modify the Foundation or the Platform. The issue with that is you are unable to reference code sitting in a higher package (model). In short a higher model can take dependencies and access elements in a lower model but not the other way around.

To get around this limitation you have to use a delegate method. Below is an example of a delegate. The PrintMgmtDocType has a method to get the default report form.

2016-01-29_0612

See how the delegate method is called from the Foundation and uses an EventHanderResult to pass around the result.

2016-01-29_0610

The delegate method doesnt have to have any code. It is there to allow other methods to subscribe to it.

2016-01-29_0611

Now this is the calls in the Suite. Notice how to subscribe by adding the SubscribesTo attribute.

2016-01-29_0623

Refer to the Microsoft Wiki. It has some really good examples.

https://ax.help.dynamics.com/en/wiki/delegates-for-migration/

Dynamics AX 7– (Project) Resource management changes

$
0
0

This was an interesting find under the projects module. Now you can put your hours against a Resource rather than a Worker. A resource can be a machine or facility or a worker. I feel this was lacking in prior versions and is a great addition. In prior version you were able to schedule against a resource but the time booked was always against the worker.

What this means is now all the Worker references have changed to Resource

1. Hours forecast and actuals are against a Resource

2016-01-13_1512

2. Project/Worker validaiton and Category/Worker validation.

2016-01-11_1558

2016-01-11_1557

If you look at the details of the resrouces you will see that it is linked to a worker but it can now be linked to Vendor/Machine/Tool/Location/Facitlity.

2016-01-13_1533

From a code perspective if you are upgrading it is fairly straight to port over your code. You should change from Worker to Resource.

Fromif (! ProjValEmplProjSetup::checkWorkerProj(this.Worker, this.ProjId))
Toif (! ProjValEmplProjSetup::checkResourceProj(ResourceFacade::findOrCreateByWorker(this.Worker), this.ProjId))

 

Fromif (! ProjValEmplCategorySetUp::checkWorkerCategory(this.Worker, this.CategoryId))
To

if (! ProjValEmplCategorySetUp::checkResourceCategory(ResourceFacade::findOrCreateByWorker(this.Worker), this.CategoryId))

Dynamics AX 7–Quick Searching Code

$
0
0

This is quite a helpful tip given to me some time back. Most of the time you want to find a particular piece of code from the whole AOT. In AX7 all the code is file based which means searching can be done much faster with some tools.

I have used agentransack but there are other tools out there you could use.

http://www.mythicsoft.com/agentransack/download

2016-01-11_1533

This is handy finding code examples or references in code.


Where did my list pages go in AX7?

$
0
0

In AX 2012 we had to maintain two forms; a list page and a details form. This has changed in AX7 with the introduction of form patterns. Now we only have to maintain a single form and by applying the correct patterns it is displayed accordingly. This is a big benefit and reduces the overhead of developing and maintaining two forms.

Below is an example:

2016-03-08_1655

Figure 1: Customer list

2016-03-08_1656

Figure 2: Customer details with the navigation list pulled out

Below you see the different patterns.

2016-03-08_1653

The menu item has a view option which allows you to open the form in the selected view.

2016-03-08_1701

Dynamics AX 7 - Searching using BaseX

$
0
0

In a previous post I wrote about the benefit of being file based model store. It allows for quick searching. On top of this the files being xml it allows for using complex searching using XPath and XQuery to find properties. There is a tool out there called basex which is a light weight xml database engine. Allowing for very powerful query and searching.

Download it from the site http://basex.org

Create a new Database and select the Packages folder. Make sure to tick skip corrupt files as there is 1 file it is not well formatted xml.

2016-03-18_1244

Take a few minutes

2016-03-18_1035_001

Screenshot below gets all the developer documentation on the tables.

2016-03-18_1512

Another example count the methods and the their name.

2016-03-18_1508

Big thanks to Peter Villadsen’s session at the recent tech conference.

Mining the Metadata and Authoring X++ Best Practice Rules in Microsoft Dynamics AX

I copied his queries from the video to get started (above two screenshots) but I already started experimenting with different things we can get out of the files.

Dynamics AX 2012–How to investigate SSRS errors

$
0
0

Recently I was investigating an issue when printing customer statements, randomly I was getting errors. The error wasn’t really helpful as it gave a generic error in the infolog. So, in this post I will explain how to investigate SSRS errors and hope it helps others out there.

What is the Error

An error occurred rendering the report. Accessing the report server URL  caused an error. The remote server returned an error: (500) Internal Server Error.

Microsoft.Dynamics.Ax.Xpp.ErrorException: Exception of type 'Microsoft.Dynamics.Ax.Xpp.ErrorException' was thrown.
   at Dynamics.Ax.Application.SrsPrintMgmtController.Outputreports() in SrsPrintMgmtController.outputReports.xpp:line 96
   at Dynamics.Ax.Application.CustAccountStatementExtController.Runprintmgmt() in CustAccountStatementExtController.runPrintMgmt.xpp:line 129

2016-03-31_1122

Step 1 – Check SSRS log files

The first place is obviously the event viewer. That generally won’t give that much more information from my experience when it comes to SSRS.

So, first thing is to find the SSRS log file and do a search for “Error”. Log files sit somewhere here

C:\Program Files\Microsoft SQL Server\MSRS11.MSSQLSERVER\Reporting Services\LogFiles

This date and time lines up with when the error occurred in AX.

Error: The process cannot access the file 'C:\Users\axservice\AppData\Local\Temp\tnxa1quh.out' because it is being used by another process.

2016-03-31_1130

Step 2 – Find what process is causing the error

Now that we know it is an access issue the next thing is to find what process is causing the lock.

Download the process monitor and run the executable. This will create a large files. So I have been clearing every few minutes until I got the error.

https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx

2016-03-31_1117

Step 3 – Eliminate the problem and test again

By the above I can see one of the processes trying to access the file is SearchProtocolHost.exe (Windows Search Index). So, next step is to stop it.

This should never really be set up on a server. It just consumes resources for no reason. What I found on this is that it was configured to index the c:/users folder.

2016-03-31_1100_001

I would actually uninstall it.

2016-03-31_1115

This could have been antivirus or other process locking the file. Maybe folder permission issue. What ever the error these steps should help you diagnose the problem.

AX7 Recurring File (folder) integration

$
0
0

The new Dynamics AX is 100% in the cloud and that means some complication when it comes to file based integration. The AOS is hosted on the cloud and has no way of accessing folders. What we have is web services which we can stream a file to. This is explained nicely in the wiki site.

https://ax.help.dynamics.com/en/wiki/recurring-integrations/

Microsoft has released a github project to process local/network folders and stream to the web service.

https://github.com/Microsoft/Dynamics-AX-Integration

Run the DIXF sample .NET project and you will get this window.

2016-04-04_1551

The future where I see this heading is using Azure Logic Apps. Azure Logic Apps allows you to integrate with multiple connectors. I hope we get AX as one of the connectors. Today you can make it work using a wrapper web API app with swagger. Then the fields are recognized as part of the user interface.

2016-04-07_0915

These comments around Azure Logic is personal and not from Microsoft. The future is looking really cool.

Multi threading–Adding run time tasks

$
0
0

Last year I posted about multi threaded operation using BOF Also uploaded a sample project you could use to test it out or use as a template.

Multithreading with Business Operation Framework [AX 2012]

One thing I picked up after testing it in a large scale project which required scheduling it on a non default (blank) batch group. This had a few issues:

Originally I was using the 

batchHeader.addTask(this.newTaskController(recIdSet));

Below are the two issues of using this method like this.

1. There is a known issue to set the controller execution mode to be Synchronous.

Whitepaper: https://www.microsoft.com/en-us/download/details.aspx?id=29215

Screenshot of the known issue.

2016-03-31_1223

This separates it as its own batch job which disappears after it is finished. This is not the desired result when we are adding tasks at runtime. We want to keep them as tasks under the main batch.

2. Another issue is it will set the batch group as the default batch (blank). In my case the blank batch group was not my ideal batch server.

I rewrote that section as per below.

2016-03-31_1220

Viewing all 219 articles
Browse latest View live