Friday, January 25, 2013

SpotLight: How to use X++ Delegates in Dynamics AX 2012


Hi there,

I hope you are ready for a long and restful weekend. Certainly, I'm as this has been a tough week with lots of new challenges and lots of new learning, which is great. 

On this post I would like to point out a very interesting post about using delegates in Microsoft Dynamics AX 2012. The post was written by Marcos Calderon, who works for Microsoft as their SDE Lead. 

In his post he starts by showing us how to create a delegate in Microsoft Dynamics AX 2012, then he explains what delegates are and why they are used. He also explains what Event Handlers are and their relationship to the AX 2012 AOT. 



Finally, he give us an example on how to add an event handler programmatically in X++, and how to publish the subscriber into the same tier for later use.

From the post:

"...X++ delegates expose the publisher -subscriber pattern where a delegate defines a clear contract in a publisher class. This contract is used when an event occurs where the event can be a change of state, where all interested classes receive notification that the event has occurred."

You can access his post from here.

Well folks, that's all for now and until the next post!



Monday, January 14, 2013

Get Product Attribute Values in AX 2012 - Let's Code!





Hi There,

I hope that your weekend went OK and that you are ready for another interesting article about AX 2012.

Today I wanted to talk a bit about Product Attributes in AX 2012. As we all know by now, with the introduction of AX 2012 things got a little bit more complicated when dealing with Product Categories and Attributes. 

Categories in AX2012 are used to classify products, customers, and other type of data for reporting and analysis. In addition, each category must have a parent , and child elements (you can learn more about it here).

On the other hand, Product Attributes in AX 2012 focus on the details that we want to maintain for certain products. Before you can create a product attribute, you must define an Attribute Type. Now the great thing about product attributes is that we can assign them from different modules of AX 2012, and the attribute will belong to that module only and not other (you can learn more about it here).

When trying to get a Product Attribute Value for a Product in AX 2012, it is important to understand that there are three main tables involved.

 EcoResProductAttributeValue
 EcoResAttribute

 EcoResValue 

The following code will help you get the Product Attribute Value:

public static AttributeValueText getItemIdAttributeValue(RefRecId _product)
{
    EcoResProductAttributeValue ecoResProductAttributeValue;
    AttributeValueText          attributeValueText;
    InventTable                 InventTable;
    EcoResAttribute             ecoResAttribute;
    EcoResValue                 ecoResValue;
    ;


    //We only query a level down the inventtable and just used the InventTable.Product RecId as a reference for ecoResProductAtributeValue


    while select ecoResProductAttributeValue
        where ecoResProductAttributeValue.Product == _product
            join Name from ecoResAttribute
            where ecoResProductAttributeValue.Attribute ==    ecoResAttribute.RecId
                join ecoResValue where ecoResValue.RecId == ecoResProductAttributeValue.Value
    {
        attributeValueText = ecoResValue.value();
    }

    return attributeValueText;
}


If you notice, the only parameter we need in the example above is the Inventory Table Product Reference in order to find the correct value within the
EcoResProductAttributeValue View. 


The alternative can be to use the Inventory Table in the query as well, and it will look like this:


public AttributeValueText getItemIdAttributeValue()
{
   
    EcoResProductAttributeValue ecoResProductAttributeValue;
    AttributeValueText          attributeValueText;
    InventTable                 InventTable;
    EcoResAttribute             ecoResAttribute;
    EcoResValue                 ecoResValue;
    ;

    while select InventTable where InventTable.itemid == this.parmItemId()
        join RecId from ecoResProductAttributeValue
        where ecoResProductAttributeValue.Product == InventTable.Product
            join Name from ecoResAttribute
            where ecoResProductAttributeValue.Attribute == ecoResAttribute.RecId
                join ecoResValue
                where ecoResValue.RecId == ecoResProductAttributeValue.Value
    {
        attributeValueText = ecoResValue.value();
    }

    return attributeValueText;

}


In the code above I'm using an Inventory Table Item Id and referring the selected record in the EcoResProductAttributeValue View. 


Until the next post and have a great week.




Wednesday, January 9, 2013

Spotlight - ERP Evaluation Checklist




Hi There,

I would like to share a great article about choosing the right ERP solution. 

The article was written by Jen Dorsey and she is a Marketing Manager at Microsoft. In her blog, she presents 10 point evaluation items to take into consideration when choosing and/or evaluating an ERP solution.

You can access her blog from here


From the post:

"Choosing the right enterprise resource planning (ERP) solution is a strategic investment for your company, so it's well worth your time to carefully examine your options...


...Business solutions from Microsoft feature a consistent look and feel that your people already know and work with. If they already know and use Microsoft Outlook, Word, and Excel, they will find the Microsoft Dynamics ERP user experience familiar and adopt it faster."






Until the next post!



Perform in-place upgrade to Microsoft Dynamics AX - A Summary in Pictures 2012 R2



Hi There,

I hope everyone is having a good week so far and that you are ready for another topic on AX 2012 R2. I was reading the AX 2012 R2 upgrade guide and it seems like a lot of information to process. Therefore, I thought on creating a summary of the complete AX 2012 R2 upgrade process through pictures and just a few words. As the saying says, a picture express a thousand words. 

You can download the original document here, which is a very useful guide when it comes to upgrade to AX 2012, AX 2012 Feature Pack, and AX 2012 R2.

Moving right along, An upgrade from Microsoft Dynamics AX 2012 or Microsoft Dynamics AX 2012 Feature Pack to Microsoft Dynamics AX 2012 R2 is classified as an in-place upgrade. The great thing about this type of upgrade is that it does not requires source-to-target workflow, which is when we needed to upgrade an AX 4.0 instance to AX 2009 before bringing it to AX 2012, instead the upgrade is done directly into the source AX 2012 system, so look for upgrade XPO in your AX 2012 R2 setup files. 


Create a Test System

Duplicate your existing production system to create the test system. You can accomplish this by copying a virtual machine image, or, alternatively, you can build a new system by using Setup from your legacy Microsoft Dynamics AX version, and then copying over the production database


 
Run the Microsoft Dynamics AX 2012 R2 Setup on the Test System

By running Microsoft Dynamics AX 2012 R2 Setup on the test system, you accomplish the three numbered tasks shown in the following picture.

Back up the Test System Model Store

Create a file backup of the model store. This backup is used during code upgrade of the models in the customer layer. i.e. AxUtil.exe exportstore /file:[full path of file and file name]


Back up the Test System Model Store
 
Create a file backup of the model store. This backup is used during code upgrade of the models in the customer layer. i.e AxUtil.exe exportstore /file:[full path of file and file name]



Create Development System

Duplicate the Microsoft Dynamics AX 2012 R2 test system to create the development system, which is used to upgrade customer models





Upgrade Customer Models

Customer models belong to one of the customer layers. In ascending order, these layers include the ISV, VAR, CUS, and USR layers. Code upgrade is performed by layer, meaning that each customer layer is upgraded separately, starting at the lowest layer and working up through the higher layers.




Upgrade Code on the Development System and Export the Upgraded Models

All tasks on the checklist have to be completed for each layer that contains models that require upgrade.



Import the Model Store Backup to the Development System

On the development system, import the backup of the model store that you made in the procedure “Back up the test system model store.” i.e. AxUtil.exe importstore /file:[full path of file and file name] /idconflict:overwrite



Import Upgraded Models into their Layers on the Development System

Import the upgraded model or models into the appropriate customer layers. Start with models from the lowest layer, then work up through the higher layers.



Repeat Code Upgrade for Each Layer

For each remaining layer that contains customized models, repeat the upgrade procedure, moving from the lowest remaining layer to the highest layer.



Export the Upgraded Model Store

Export the fully upgraded model store that you have created on the development system to a file. This file acts as the source of the upgraded customer models that are used to prepare for data upgrade first on the test system and later on the production system. i.e. AxUtil.exe exportstore /file:[full path of file and file name]



Import the Upgraded Model Store into the Test System

On the test system, import the model store file that you made in the procedure “Export the upgraded model store.” i.e. AxUtil.exe importstore /file:[full path of file and filename] /idconflict:overwrite



Perform Data Upgrade on the Test System



Upgrade Production System

On the production system, enter single-user model. All client users other than the administrator will be disconnected form the Microsoft Dynamics AX system at this point. This action starts the downtime window during which new business transactions cannot be processed.



Upgrade the Core Production System

Upgrade on the production system requires that you run Microsoft Dynamics AX 2012 R2 Setup on each computer in your deployment.



Upgrade AOS and Other Components

Run Setup on the production system to upgrade the core server and client components.



Perform Data Upgrade on the Production System

Complete the tasks on the checklist as described earlier in this how-to in the section “Perform data upgrade on the test system.



Upgrade Additional Server Components

When data upgrade is completed, you can complete the upgrade of server components.



Upgrade Additional Clients

Run Setup on your additional Microsoft Dynamics AX client systems to upgrade the client software.




I hope this summary can serve you well as a snapshot of the complete AX 2012 R2 in-place upgrade. There is a lot to learn with this new release and I would expect lots of customer wanting to upgrade to R2 after Convergence 2013.


Have a great rest of the week and until the next post.



Friday, January 4, 2013

Business Benefits of Microsoft Dynamics AX 2012 R2

 
 
Hi There!
 
As we all very well know by now, the release of AX 2012 R2 (You can get more informtion about AX 2012 R2 on the What's New in Microsoft Dynamics AX 2012 for Developers) came to a reality last December, and I wanted to share the four most important business benefits of this release.
 
You can access the original post here, which was written by the Microsoft Dynamics AX Product Team.
 
New functionality for Industries and Administrative Processes
  • Manufacturing: Improve manufacturing operations for process manufacturing. AX 2012 R2 introduces new capability for management of potency, traceability and product batch sequencing to help process manufacturing streamline operations.
  • Retail: Assorment management across channels in your retail operations. New multi- and cross-channel capabilities for retail organizations, including catalogue management, cross-channel workflows, and integrated sales channel management will include a new “out of the box” web storefront.
  • Public Sector: AX 2012 R2 simplifies the financial budgeting process in public sector organizations. By combining the power of Microsoft Excel with the power of the workflow engine inside of Microsoft Dynamics AX 2012, AX 2012 R2 supports new capabilities in budget formulation with workflow approvals, flexible tracking, and reporting.
  • Professional Services: AX 2012 R2 improves in the intercompany scheduling capability of project resources will specifically benefit services organization with resources and projects across multiple entities and will improve utilization of your resources.

Improve Business Insights for all Users

New and updated KPI content is offered, and updated KPIs will come with the SQL BI cubes shipped with the release. These KPIs will surface on the different role centers.

Enabling the usage of the new Power view technology (You can learn more about this from the Murray Fife's post Creating PowerView Dashboards Against Dynamics AX 2012) introduced in Microsoft SQL Server 2012. This will help users to discover new insights through a highly interactive and familiar data visualization technology.

Increase Global Reach and Simplify International Operations

AX 2012 R2 has increased the global reach of Microsoft Dynamics AX 2012 by adding localization for 11 new markets (Brazil, Czech Republic, China, Estonia, Hungary, India, Japan, Latvia, Lithuania, Poland, and Russia), extending the reach for Microsoft Dynamics AX 2012 to support 36 localizations worldwide.


Simplify the Application Lifecycle for Customers

This goes from simplifying single instance international ERP deployment scenarios up to simplifying setup and functional implementation with new and improved lifecycle services.

Also, in AX 2012R2, we’ll see:

  • The Code Analyzer that will help us analyze the performance of custom code based on rules in the design phase of an extension by customers or partners.
  • The Data Migration Framework will support import, export and migration of data to/from Microsoft Dynamics AX 2012 in the deployment phase. It will cover over 20 scenarios including customer, vendor, product, employee, BOM, open sales and purchase order data, which can be extended by partners and customers.
  • The Diagnostics Framework will assist by analyzing data collected from the installation’s servers based on rules in the maintenance phase.

It is really exciting to see all these improvements in new release, as it will add more value to customer acros the board and it will help AX 2012 R2 to be used in other countries based on the localization improvements.

Take care and until the next post!



Thursday, January 3, 2013

Create Product / Product Masters AX 2012

 

Hi There,

I hope everyone had a great new year and that you are ready for a new one full of challenges, and good things.
 
In this post I would like to discuss how to create product and product masters in AX 2012. Sometimes our requirements vary depending on the customer, and more often than not, we need to provide a dynamic option to create either a product or a product master.

So, what is the definition of these two terms?

Product: This is the simpler of the two. They do not need product dimension groups when created.

Product Master: This type must contain product dimension groups; otherwise you’ll get a run-time error at the time the EcoResService is called.

The product dimension groups can be Color, Size, Style and Configuration. In addition, you can create any other dimension group. In my example, a user created a dimension group called “Revision”, which is the chosen one for this example. This shows how flexible AX2012 is around product dimensions.

The following code takes two parameters. One is the product name (which has a custom EDT), and the product sub type (is it product or product master). Further, to achieve this we will use the following classes:

EcoResEcoResProduct_TrackingDimGroup   
EcoResEcoResProduct_Product_Master     
EcoResEcoResProduct_Product_Distinct   
EcoResEcoResProduct_ProductDimGroup    
EcoResEcoResProduct_StorageDimGroup    
EcoResEcoResProduct_translation        
EcoResEcoResProduct_Identifier         
EcoResProductService        

           
The EcoResEcoResProduct_Product_Master (http://msdn.microsoft.com/en-us/library/ecoresecoresproduct_product_master.aspx) class is in charge of creating the new Product Master, and the EcoResEcoResProduct_Product_Distinct (http://msdn.microsoft.com/en-us/library/ecoresecoresproduct_product_distinct.aspx) class is in charge of creating the Product. These records are going to be created in the EcoResProduct Table.
 
As you probably know by now, even these records exist in the EcoResProduct table, they haven’t been release to AX just yet.

Moving right along, we will be using the EcoResProductService class (http://msdn.microsoft.com/en-us/library/ecoresproductservice.aspx) to actually create the product in the EcoResProduct Table.

/// <summary>
/// Creates a new product in EcoResProduct
/// </summary>
/// <returns>
///
/// </returns>
/// <remarks>
///
/// </remarks>
/// <exception cref="Exception::Error">
/// Throws error upon Exception.
/// </exception>

 
public static void CreateEcoResProduct(ProductName _ecmProductName, EcoResProductSubtype prodSubType)
{
    EcoResEcoResProduct_TrackingDimGroup    tracDimGroup;
    EcoResEcoResProduct_Product_Master      productMaster;
    EcoResEcoResProduct_Product_Distinct    distMaster;
    EcoResEcoResProduct_ProductDimGroup      prodDimGroup;
    EcoResEcoResProduct_StorageDimGroup      storDimGroup;
    EcoResEcoResProduct_translation          translation;
    EcoResEcoResProduct_Identifier           identifier;
    EcoResProductService                     ecoProdSvc;
    EcoResProductNumber                      lEcoResProductNumber;
    NumberSequenceTable                      numberSequenceTable;
    EcoResEcoResProduct                      ecoResProd;
    EcoResProductType                        ecoResProductType;
    boolean                                  isMaster = false;
    ;

 
    try
    {
        // create product by initializing the Service object
        ecoProdSvc = EcoResProductService::construct();

 
        // initialize the EcoResEcoResProduct object
        ecoResProd = new EcoResEcoResProduct();

     
        numberSequenceTable = EcoResProductParameters::numRefProductNumber().numberSequenceTable();


        lEcoResProductNumber = NumberSeq::newGetNumFromId(numberSequenceTable.RecId).num();
        ecoResProductType = EcoResProductType::Item;
      
        if(prodSubType == EcoResProductSubtype::ProductMaster)
        {
            isMaster = true;


            //Create a new product master
            productMaster = new EcoResEcoResProduct_Product_Master();

 
            //initialize product master
            productMaster.parmDisplayProductNumber(lEcoResProductNumber);
            productMaster.parmProductType(ecoResProductType);
            productMaster.parmSearchName(_ecmProductName);
           
            productMaster.parmVariantConfigurationTechnology(EcoResVariantConfigurationTechnologyType::PredefinedVariants);

 
            //create a product master Translation Object
            translation = productMaster.createTranslation().addNew();

 
            // create a new identifier object
            Identifier = productMaster.createIdentifier().AddNew();

 
            // Create the ProductDimensionGroup
            prodDimGroup = productMaster.createProductDimGroup().addNew();
            prodDimGroup.parmProduct(lEcoResProductNumber);
           
            prodDimGroup.parmProductDimensionGroup('Revision');

 
            // Create the StorageDimgroup object
            storDimGroup = productMaster.createStorageDimGroup().addNew();
            storDimGroup.parmProduct(lEcoResProductNumber);
            storDimGroup.parmStorageDimensionGroup("S-W-L");

 
            // Create the TrackingDimGroup object
            tracDimGroup = productMaster.createTrackingDimGroup().addNew();
            tracDimGroup.parmProduct(lEcoResProductNumber);
            tracDimGroup.parmTrackingDimensionGroup("none");

        }
        else
        {
            // Create a new product distinct master
            distMaster = new EcoResEcoResProduct_Product_Distinct();

 
            // Take the newly created and initialize ProdMaster - variable and fill with product data
            distMaster.parmDisplayProductNumber(lEcoResProductNumber);
            distMaster.parmProductType(ecoResProductType);
            distMaster.parmSearchName(_ecmProductName);

 
            // Create a translation object
            translation = distMaster.createTranslation().addNew();

 
            // Create a new identifier object
            Identifier = distMaster.createIdentifier().addNew();

 
            // Create the StorageDimgroup object
            storDimGroup = distMaster.createStorageDimGroup().addNew();
            storDimGroup.parmProduct(lEcoResProductNumber);
            storDimGroup.parmStorageDimensionGroup("S-W-L");

 
            // Create the TrackingDimGroup object
            tracDimGroup = distMaster.createTrackingDimGroup().addNew();
            tracDimGroup.parmProduct(lEcoResProductNumber);
            tracDimGroup.parmTrackingDimensionGroup("None");
        }


        // fill the translation object
        translation.parmDescription(_ecmProductName);
        translation.parmLanguageId('en-us');

 
        //translati
        translation.parmName(_ecmProductName);

 
        // fill the identifier
        identifier.parmProductNumber(lEcoResProductNumber);

 
        // add the product to ecoResProd
        if(isMaster)
            ecoResProd.createProduct().add(productMaster);
        else
            ecoResProd.createProduct().add(distMaster);

 
        // create the product using service
        ecoProdSvc.create(ecoResProd);

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




Happy New Year and until the next time!