Thursday, August 30, 2012

Spotlight: Adding PowerView Dashboards To Dynamics AX 2012

Hi,

I hope everybody is doing great today and that you are ready to enjoy this long weekend.

Today I wanted to take the time and give a spotlight to one of my co-workers, Murray Fife. Murray Fife is a Senior Solutions Architect for Junction Solutions. He has contributed a lot to the community over the years and he is always paving the road on new topics regarding AX in general.

On this post, I would like to share a recent post he created on adding PowerView dashboards to AX 2012.



From the post "One of the built in features is the ability to create your own data from the base query that you run, and that data may be images rather than the traditional data types"

You can access his post from here.

I encourage you to read this post and follow Murray Fife to get his latest updates on AX 2012.

This is all for now folks.

Until next time.

Friday, August 17, 2012

Working with the AX 2012 EDT relation migration tool



Hi there!

This week I was faced with a couple of problems related to the relationships between tables made under an Extended Data Type (EDT). In my case, I learned that when relationships between tables exist through EDTs, they only capture a single field relationship and not necessarily a “real” relationship between tables.

A good example of this is when we assign an ItemId EDT to a custom field in a custom table. In this case, AX 2012 will ask you to create an EDT relationship, so I did. Later on the week, I was getting an error related to a violation of a primary key in the custom table I created when data was being inserted to it.

The error was related to the relationships being defined under an EDT as the kernel was have issues defining which relationship to examine first.

It took me a while to understand that the problem was the EDT relationship and after looking at some documentation it was easy to catch the issue as EDT relationships do not contain relationship metadata, such as cardinality and relationship type, and more often than not, they cannot be included in the relations node.

Luckily for us, AX 2012 provides a simple way to fix the EDT relations issues fairly easy. In fact, the migration can be done both manually or using the new EDT relation migration tool. However, if the data model is not correct, there are cases where we are going to have to fix the EDT’s manually.

To begin using the EDT relation migration tool, open the form for the tool by using the navigation path Tools > Code upgrade > EDT relation migration tool as seen in the picture below.



NOTE: Just keep in mind that if you are using this tool for the first time, AX 2012 will ask you if you want to refresh all the EDT relationships data, click yes and the EDT Migration tool will open.


When the form has opened, follow the next steps:
  1. Select a table from the Table name pane.
  2. Select each relation in the EDT relations table and choose an action from the Migration action drop-down menu for each of them.
  3. After you have set an action on all the relations for that table, click the Migrate single table button on the ribbon at the top of the form.

See Image for clarification:



What happens in the background?

  1. The migration tool attempts to find a match for the EDT relation in the existing relations in the selected table. If a match is found, the SourceEDT property on the table relation is set to the name of the EDT.
  2. However, if there is no match found in the table, the EDT migration tool will create a new table relationship only if the index (IndexType ) on the referenced table (shown by “”) is set to the correct table relationship.
  3. Finally, the tool will not create a new table relation if the matching index for the EDT field on the referenced table is set to NoIndex, Unique, NonUnique.

Example: Migrating an EDT relation to a new table relation.

This example shows the case in which an EDT relation is migrated to a table where the table relation was previously not defined. The result from this example will be the creation of a new table relation.

The EDT PKTableField1 defines a relation to the PKTable.Field1 field, which is an alternate key AK1.


In addition, before the EDT migration, the FKTable.Field1 field uses the EDT PKTableField1, which makes it a foreign key into PKTable. However, there is no table relation defined on the FKTable, and the ExtendedDataType property on FKTable.Field1 is set to PKTableField1 instead.



We choose the FKTablle and under the Migration Action, we choose Migrate.



What happens in the background?

The EDT relation migration tool performs the following actions:
  • The EDT migration tool creates the new relation to the PKTable under the Relations node of the FKTable. This relation will be of type Normal because the key is not the primary key.
  • Then, the EDT migration tool will set the EDTRelation property of the PKTable relation to Yes. This is because the tool performs the direct migration of an EDT relation to the table relation.
  • Then, the EDT migration tool creates one field link, FKTable.Field1 == PKTable.Field1, for the PKTable relation.
  • Finally, the EDT migration tool will set the SourceEDT property of the field link to PKTableField1.

What to expect the next time we use the tables?
  • All the APIs that used the EDT relation first on FKTable.Field1 will now find the same relation with the same field link under the PKTable relation by examining its SourceEDT property.
  • If a table relation that refers to PKTable already exists in FKTable, all the APIs that used those table relations will not pick up the PKTable relation because it is flagged as an EDTRelation, and the PKTable relation to the Relations node of the FKTable, with its EDTRelation property set to Yes.



In addition to the above, we can also double check the outcome of the EDT migration tool by looking at the SourceEDT property of FKTable.Field1. This should have been set to PKTableField1 to maintain a relationship with the EDT.



Let recap for a minute on what we just went over. The EDT relation migration tool can be used to automate the following actions:

  • Copy an EDT relation to all hosting tables.
  • Automatically set the EDT migration properties (markers) to reflect migration status.
  • Automatically populate relation metadata.
  • Derive cardinality from the index on the foreign key.
  • Derive the relationship type from the delete action/key composition.
  • Determine role names.
  • Report AOT objects impacted by the migration, depending on the relation used. The objects that can be affected include:
    • Queries:
    • Forms
    • Delete actions on tables
    • Data sets
    • X++ reports
Well folks, I think this is it for now. I really hope you like this article and that can help you at some point in your AX 2012 adventure. Also, I will be writing a bit more about AX 2012 Retail and Inventory and Product management in AX 2012 soon, so don’t miss it!



Have a great and restful weekend!




Friday, August 10, 2012

Working with the LedgerGeneralJournalService AX 2012



Hi There!

I hope everyone had a good week and that you are ready for an excellent weekend.

As you may well be aware by now, in AX 2012 you can import data by using services. You can use these services to import Customers, GL transactions, Products, etc.

You can learn more about services and AIF in one of my posts called Microsoft Dynamics AX 2012 Services and (Application Integration Framework) AIF architecture , and you might want to take a look into Services and Application Integration Framework .

On this post, I would like to share with you some code to import GL transactions into AX 2012 using the LedgerGeneralJournalService available in AX 2012.


static void ImportGLTransWithLedgerGeneralJournalService(Args _args)
{

    // Set these variables.
    LedgerJournalNameId                     journalName = 'GenJrn';
    SelectableDataArea                        company = 'CEU';
    TransDate                                     transactionDate = 10\10\2012;

    str                                     line1MainAccount = '256369';
    str                                     line1FullAccount = '256369--';
    str                                     line2MainAccount = '400090';
    str                                     line2FullAccount = '400090-10-';
    str                                     line2Dimension1Name = 'BusinessUnit';
    str                                     line2Dimension1Value = '10';


    LedgerGeneralJournalService             ledgerGeneralJournalService;
    LedgerGeneralJournal                       ledgerGeneralJournal;

    AfStronglyTypedDataContainerList              journalHeaderCollection;
    LedgerGeneralJournal_LedgerJournalTable   journalHeader;
    AifEntityKeyList                                         journalHeaderCollectionKeyList;
    RecId                                                       journalHeaderRecId;


    AfStronglyTypedDataContainerList                   journalLineCollection;
    LedgerGeneralJournal_LedgerJournalTrans       journalLine1;
    AifMultiTypeAccount                                       journalLine1LedgerDimension;
    LedgerGeneralJournal_LedgerJournalTrans       journalLine2;
    AifMultiTypeAccount                                       journalLine2LedgerDimension;
    AifDimensionAttributeValue                             journalLine2Dim;
    AfStronglyTypedDataContainerList                   journalLine2DimCollection;
    ;

    ledgerGeneralJournalService = LedgerGeneralJournalService::construct();
    ledgerGeneralJournal = new LedgerGeneralJournal();

    // Create journal header.
    journalHeaderCollection = ledgerGeneralJournal.createLedgerJournalTable();
    journalHeader = journalHeaderCollection.insertNew(1);
    journalHeader.parmJournalName(journalName);

    // Create journal lines.
    journalLineCollection = journalHeader.createLedgerJournalTrans();
    // Line 1
    journalLine1 = journalLineCollection.insertNew(1);
    journalLine1.parmLineNum(1.00);
    journalLine1.parmCompany(company);
    journalLine1.parmTransDate(transactionDate);
    journalLine1.parmAccountType(LedgerJournalACType::Ledger);
    journalLine1.parmTxt('AX Wonders Journal Import test');
    journalLine1.parmAmountCurDebit(235.00);

 
    // Define Ledger Dimensions
    journalLine1LedgerDimension = journalLine1.createLedgerDimension();
    journalLine1LedgerDimension.parmAccount(line1MainAccount);
    journalLine1LedgerDimension.parmDisplayValue(line1FullAccount);
    journalLine1.parmLedgerDimension(journalLine1LedgerDimension);


    // Line 2
    journalLine2 = journalLineCollection.insertNew(2);
    journalLine2.parmLineNum(2.00);
    journalLine2.parmCompany(company);
    journalLine2.parmTransDate(transactionDate);
    journalLine2.parmAccountType(LedgerJournalACType::Ledger);
    journalLine2.parmTxt('AX Wonders Journal Import test');
    journalLine2.parmAmountCurCredit(500.00);
    journalLine2LedgerDimension = journalLine2.createLedgerDimension();
    journalLine2DimCollection= journalLine2LedgerDimension.createValues();

    journalLine2Dim= new AifDimensionAttributeValue();
    journalLine2Dim.parmName(line2Dimension1Name);
    journalLine2Dim.parmValue(line2Dimension1Value);
    journalLine2DimCollection.add(journalLine2Dim);

      // Define Ledger Dimensions
    journalLine2LedgerDimension.parmAccount(line2MainAccount);
    journalLine2LedgerDimension.parmDisplayValue(line2FullAcct);
    journalLine2LedgerDimension.parmValues(journalLine2DimCollection);
    journalLine2.parmLedgerDimension(journalLine2LedgerDimension);


    // Insert records.
    journalHeader.parmLedgerJournalTrans(journalLineCollection);
    ledgerGeneralJournal.parmLedgerJournalTable(journalHeaderCollection);
    journalHeaderCollectionKeyList =
        LedgerGeneralJournalService.create(ledgerGeneralJournal);

    journalHeaderRecId =
        journalHeaderCollectionKeyList.getEntityKey(1).parmRecId();

    info(strFmt("LedgerJournalTable.Recid = %1", int642str(journalHeaderRecId)));

}



That's all for now folks!



Friday, July 20, 2012

Deploying Customizations between AX 2012 Environments



Hi there!

I hope everyone is having a good week and that you are ready for another article about AX. In this post, I would like to focus on deployment strategies in AX 2012. I have been getting lots of emails with questions about deploying customizations between two Microsoft Dynamics AX 2012 environments. There is a good reason for this as many people seem confused about the model store file, and how can it be used to move metadata between two AX 2012 environments.

In this post I would like to recommend moving customizations by exporting the entire model store file between AX 2012 environments.

To start, I would like to share some definitions that we are going to be using in this post (source: www.microsoft.com)

Application Layer: A single layer of AX 2012 application that exists within a model store (NOTE: The elements in higher layers will override elements in lower layers)

Model Store: A collection of tables in the AX 2012 database that contains the application metadata. (NOTE: The model store can be compared to the AOD file share in AX 2009)

Metadata: Information about the properties or structure of data in the Application Object Tree (AOT) that is not part of the data values. (NOTE: Everything element that exists in the AOT is considered metadata)

Model store file (.axmodelstore): A complete model store that has been exported from the database. The file includes all metadata, compiled artifacts, CIL code, and security artifacts. The file is used for moving consistent metadata between environments with minimum downtime.

Model file (.axmodel): This is a model that has been exported from a model store. (NOTE: This file is the main vehicle of metadata deployment in AX 2012)

Moving right along , when deploying metadata between AX 2012 environments, we can do it using a number of different methods that range from importing/exporting XPO files to moving a whole model store file at once.

The following table shows a comparison between these methods (source: www.microsoft.com)



XPO Files
Model Files
Model Store Files
Imported/exported by using…
MorphX

AXUtil.exe or Windows PowerShell cmdlets
AXUtil.exe or Windows PowerShell cmdlets
Can be uninstalled?
No
Yes
No
Can be signed?
No
Yes
No
Microsoft Dynamics AX Object IDs from source environment preserved?
No



No



Yes



Compile required?
Yes
Yes
No
IL Generation required?
Yes

Yes

No


This might vary from project to project, but I believe that we should adopt a single and concise method that we can apply in our projects to quantify the results over a period of time, and to minimize downtime.

In addition, I think that a crucial step to achieve a consistent deployment methodology is to understand that the environments we are moving data from/to need to have the same metadata structure. For example, in the last six months I have learned that if a customer already has a production AX 2012 instance running, the Test and Staging environments can and should be a replica of it to avoid conflicts on ID’s and model store metadata.

We also need to ensure that any customizations we do, must first be applied to the source environment, then have them thoroughly tested, and then move them to the production environment via our preferable method. Otherwise, we open the door to inconsistency between environments.


So, let’s take a look at how the deployment process should be (source: www.microsoft.com)



Microsoft has outlined a list of common mistakes that arise when importing a single model into a production environment.

1-We start with a customization that we want to move into the target environment.





2-Then we import the model that contains our customizations. Because this is a new object that does not exist in the target system (Stage/Production), AX might give the object an ID that is different from the ID in the source system.





3-Then, someone uses he system and adds transaction records that reference the AXID.





4-Let’s say that the next day we make another customization and want to deploy the entire model store for minimal downtime (which was a different approach from step 2). To do this, we export the entire model store, which includes the IDs.




As you can see, this inconsistency will create conflicts because the ID’s as the two instances have different ID's.

Now, the idea is to choose one methodology and stick with it. However, Microsoft suggests importing the entire model store file from the beginning, so we don’t run into ID conflicts in future deployments. It is essential that the target database (especially in a production environment) is initialized from an exported source database and not individual model files.

The following sequence shows the correct way to move customizations between environments to avoid conflicts.

1-We start by creating a blank AX DB by using Setup. (This will contain the Foundation SYS model).





2-We initialize the model store by importing the model store file from the source to the target system.




3-When this happens, we can start adding data to the target system, and at the same time, customizations can be made to the source system.




4-Now, when we are ready to re-deploy new customizations, the entire model store is once again exported to minimize system downtime and to avoid ID’s conflicts.




In conclusion, every implementation should include several separate environments to consistently control what code ends up running on the customer’s production system. There are many methodologies available to us, but some of these can create ID’s conflicts when the system assigns ID’s. To avoid this problem, we should move customizations between environments using the model store file.

That’s all for now, and I hope that this posts clarifies some of the doubts about deploying customizations between environments in AX 2012.

Also, keep checking my blog as I will post a very interesting article on how to setup Items for AX 2012 Retail.


Tuesday, July 17, 2012

Microsoft Dynamics AX Retail 2012 - Blank Operations



Hi There,

I hope everybody had a restful weekend and that you are ready for another creative and challenging Microsoft Dynamic AX week.

On this post I would like to take a look at how the Blank Operations work in Microsoft Dynamics AX 2012 Retail. Please note that there is a lot to cover under this topic, and I hope that what I’m covering here today can help you get started on creating your own customizations for AX 2012 POS in no time.

So, what are Blank Operations? Well, Blank Operations, in my opinion, are the fastest and easiest way to extend the AX for Retail POS application. In addition, Blank Operations can be assigned to a button action right in the Retail POS till layout, and the great thing about them is that we can deploy as many of them as we need, which makes Blank Operations very flexible.

When we create a new project in Visual Studio and use the Blank Operations namespace, we are actually overwriting an existing DLL that exists within the AX 2012 POS application folder (located in C:\Program Files (86)\Microsoft Dynamics AX\60\Retail POS\Services).



Within this DLL we can write simple and/or complex logic to achieve different business requirements. Further,  one of the greatest advantages of Blank Operations is that they don’t really touch the core AX 2012 Retail POS logic and therefore they are safe to play around with and extremely easy to deploy.

So let’s start by creating a new Project in Visual Studio and then let’s create a form that then we will hook up to a Blank Operation in our Retail POS till layout.


1-Create a new project in Visual Studio and call it BlankOperations. By default, the namespace will be BlankOperations as well.

In here add the following code:


  

2-Add the following references to your project by right clicking your References folder. (For more information on how to do this please AX 2012 POS Development - Application Triggers)




3-Set your project’s properties to build the dll into the desired folder (C:\Program Files (86)\Microsoft Dynamics AX\60\Retail POS\Services – for more information please see AX 2012 POS Development - Application Triggers)

4-Now let’s create another new project (class library), call it MyForms, and then add a form to it, and call it MyBlankOperation. You will have to set the build properties for this project the same way you did it on the previous step. However, just set the path to C:\Program Files (86)\Microsoft Dynamics AX\60\Retail POS so the MyForm project dll will exist in the root of the AX Retail POS.





Add a label to the form and build the solution.

 




5-Build the solution

6-Go to your BlankOperations project and right click references and browse to C:\Program Files (86)\Microsoft Dynamics AX\60\Retail POS and look for the MyForm.dll. Then add the reference to your code (i.e. using MyForm;)

7-Open your AX 2012 POS Retail and on the edge of the screen right-click and choose “Customize Layout



8-From the designer (hidden items) drag a button to a place in the till layout.



9-Choose whether or not you want to save the changes (If you just want to test it, you can say no and the next time you open the layout it would be stay as the original one)



10-Right-Click on the area you just created and choose New Button Grid



11-Fill out the necessary information as per the picture below and when you are done click Confirm.



12-Right-Click  on the area you just created and choose Open Button Grid



13-From the dialog box click the Button Grid drop down list and choose BlankOp, which is the name we gave to our button in step 10.



14-From the Action pane click the Item drop down list and choose Blank Operation. Then fill the information as per the picture below.



15-Now you should have a button in your till layout. Click it and you’ll see the form we created before in this tutorial.



Note that you can have many buttons with different ids that can be manipulated later in your code by an operation ID. As you can see, Blank Operations are easy to implement and deploy, and most importantly they can help you create your own custom logic without affecting the AX 2012 POS core logic, which is nice.

Well folks, this is all for now and I hope this can help you get started on Blank Operations.

Also, keep reading my blog as I will be posting and overview of the deployment process in AX 2012 and much more in the coming days.