Microsoft Dynamics AX

Axapta

GDPR tool for Microsoft Dynamics AX 2012

The European Union has introduced strict data protection rules last month, for which companies had to become legally compliant to avoid fines. We have a set of patches to apply to get a GDPR tool for Microsoft Dynamics AX 2012, which has been released to assist us:

  • KB4056903 Privacy Policy update
  • KB4074643 DAPIA Security tool
  • KB4057507 SQM Data collection

The part relevant for us is the tool, which allows capturing which interactive users have logged on to AX, who are using a security role that may access sensitive information.

GDPR tool for Microsoft Dynamics AX 2012
User log for roles with sensitive information access
GDPR tool for Microsoft Dynamics AX 2012
Setup of roles with sensitive data access

Unfortunately Microsoft only provides a high-level guideline on what shall be included and provides very little tangible assistance. Due to this I have felt we needed some way to identify what security roles could really be accessing sensitive data, so I came up with an X++ job that does exactly this. You may pass in menu items for forms, reports and also tables that may access details such as Customers, Global Address Book, Vendors, Address and Contact details. The tool is using the Security framework to determine which roles can edit such data, but you may change filter criteria to also include View access.

static void WIK_GDPR_enable_roles(Args _args)
{
    #AOT
    
    // List of tables which might contain sensitive data
    container           tables = [
        [menuitemDisplayStr(CustTable), UtilElementType::DisplayTool]
        ,[menuitemDisplayStr(CustTableListPage), UtilElementType::DisplayTool]
        ,[menuitemDisplayStr(CustTableEdit), UtilElementType::DisplayTool]
        ,[menuitemDisplayStr(CustTableDetails), UtilElementType::DisplayTool]
        ,[menuitemDisplayStr(GlobalAddressBookListPage), UtilElementType::DisplayTool]
        ,[menuitemDisplayStr(DirPartyTable), UtilElementType::DisplayTool]
        ,[menuitemDisplayStr(DirPartyTableEdit), UtilElementType::DisplayTool]
        ];
    
    // Replace role settings?
    boolean                 update = NoYes::Yes;
    
    UtilElementType         objectType;
    str                     objectName;
    int                     i = 1;
    SysSecFlatDataTable     objects;
    SysSecFlatDataTable     allObjects;
    SysUserLogRoleSettings  roleSettings;
    SecurityRole            securityRole;
    
    allObjects.setTmp();
    
    while (i <= conLen(tables))
    {
        objectName = conPeek(conPeek(tables, i), 1);
        objectType = conPeek(conPeek(tables, i), 2);
        
        switch (objectType)
        {
            // Implemented from \Forms\SysSecObjectsInRole\init
            case UtilElementType::DisplayTool:
                SysSecObjectsFromEntryPoint::GenerateData(
                    SysSecObjectsAnalyzeType::SecViewRelatedRoles,
                    objectName,
                    enum2int(objectType));
                break;
                
            case UtilElementType::OutputTool:
                SysSecObjectsFromEntryPoint::GenerateData(
                    SysSecObjectsAnalyzeType::SecViewRelatedRoles,
                    objectName,
                    enum2int(objectType));
                break;
                
            case UtilElementType::ActionTool:
                SysSecObjectsFromEntryPoint::GenerateData(
                    SysSecObjectsAnalyzeType::SecViewRelatedRoles,
                    objectName,
                    enum2int(objectType));
                break;
                
            case UtilElementType::Table:
                SysSecObjectsFromSecurableObject::GenerateData(
                    objectName,
                    enum2int(objectType));
                break;
        }
            
        while select objects
        {
            allObjects.clear();
            buf2Buf(objects, allObjects);
            allObjects.doInsert();
        }
        
        i++;
    }
 
    if (update)
    {
        i = 0;
        ttsBegin;
        
        update_recordSet roleSettings
            setting HasAccessToSensitiveData = NoYes::No;
        
        // No join for Tmp object, must use nested loop
        while select allObjects
            group by Role//, IsOverride
            where allObjects.IsOverride    == NoYes::No
                && ((allObjects.AccessRight != AccessRight::View && allObjects.AccessRight != AccessRight::NoAccess)
                    && (allObjects.EntryPointAccess !=  AccessRight::View && allObjects.EntryPointAccess != AccessRight::NoAccess))
        {   
            select firstOnly forUpdate roleSettings
                join RecId from securityRole
                    where  securityRole.AotName      == allObjects.Role
                        && roleSettings.SecurityRole == securityRole.RecId;
            
            if (roleSettings)
            {
                roleSettings.HasAccessToSensitiveData = NoYes::Yes;
                roleSettings.doUpdate();
                i++;
            }
        }
        
        ttsCommit;
        
        info(strFmt('%1 security roles have been updated', i));
    }
 
    while select Role, RoleName
        from allObjects
        group by RoleName, Role//, AccessRight, EntryPointAccess
        where allObjects.IsOverride     == NoYes::No
            && ((allObjects.AccessRight != AccessRight::View && allObjects.AccessRight != AccessRight::NoAccess)
                && (allObjects.EntryPointAccess !=  AccessRight::View && allObjects.EntryPointAccess != AccessRight::NoAccess))
    {
        info(strFmt('%1 (%2)', allObjects.Role, allObjects.RoleName));
    }
}

The XPO could be downloaded from GitHub.

https://github.com/DAXRunBase/AX-2012-R3/tree/master/GDPR%20security%20roles
By |2020-03-23T13:37:46+01:00June 29th, 2018|Categories: AX 2012|Tags: , , , , |4 Comments

Hardcoded label fix tool for AX 2012

It is a common problem that developers create the objects and code in the shortest time possible to meet a deadline, and that is when we meet with the hardcoded label problem, which is a Best Practice violation. Our environment had about 6000 hardcoded label values as well, and I was looking for a general solution to fix them, which resulted in creating a new tool.

This tool is heavily beta version, comes with no warranties, use it at your own risk.

Hardcoded label

The hardcoded label fix tool is version control compatible, and you should really use it through that, in case you would like to roll back a set of incorrect modifications easily.

Once you open the form, the Scan button will process your entire AOT on the current layer and model and stores TreeNode path, type, text and possible label matches. Processing can take up to several hours.

Then you could multi-select labels and press Commit to replace the values. For blank entries it tries to create a new label in the currently selected (must be checked out in advance!) label file and language. If there are multiple hits for the text, it is marked by 3 asterisks, and you need to pick one on the right pane to use. In case you want to have your own labels created anyway, you could erase the recommended @SYS* or whatever entries, save the record then commit for a new one.

Please note that due to the nature of AX DB being Case Insensitive, it is possible that a label is recommended which has a different case, like you get label for ‘a’ instead of ‘A’.

The project can be downloaded from the DAXRunBase GitHub.

By |2018-03-30T13:54:33+02:00March 30th, 2018|Categories: AX 2012|Tags: , , , , |1 Comment

Picking list registration performance

We recently have implemented a new Picking application in our warehouse. Our slow performing statement e-mail has immediately highlighted that with our data volume the WMSOrder and SalesTable records were underperforming, taking 5+ seconds each time when the form was opened (close to 20). We needed to fix the Picking list registration performance.

WMSOrder

Apparently it is a standard AX form and table, but the link which they have been using is incorrectly defined, resulting in an InnerJoin for SalesTable unnecessarily.

Picking list registration performance

Also the field used for the join has no index, you should create one for WMSOrder.InventTransRefId to gain more performance.

After the adjustment it looks much better and performs really fast:

WMSOrder

 

By |2018-02-27T10:22:18+01:00February 27th, 2018|Categories: AX 2012|Tags: , , , , , |0 Comments

SQL data compression for Dynamics AX 2012 (Part 2)

It has been a while since I have touched up on SQL data compression in part 1 on my blog. It is time to re-visit the topic.

SQL data compression for Dynamics AX 2012 (Part 1)

Since that post Microsoft has published an excellent series of articles on how to apply compression within AX, or directly on SQL Server. It is a must-read blog post for everyone, so start there:

https://blogs.msdn.microsoft.com/axinthefield/sql-server-data-compression-for-dynamics-ax-0-blog-series/

Since JJ Food Service has a very large database, we have started applying compression to Production AX. Our SalesLine and CustInvoiceTrans has been between 250-350 GB size each! Our approach was to apply compression before a maintenance window using the Enterprise Edition license of SQL Server in ONLINE mode and using TempDB sorting, so it was running during business hours only adding a slight overhead to the system (mostly as disk I/O). It took 4 and 6 hours respectively, and space saving was more than 75% which is excellent.

Once the compression has finished and we were about to begin our regular Friday night maintenance, once the AX AOS, reporting and web services were all down, we could run the post-compression SQL script provided by Microsoft to populate the SQLStorage table. This is required for the Data dictionary synchronization step to recognize compressed indexes, so it would not drop and recreate them uncompressed.

Eventually we will consider compressing our whole database for Page level. The reason being is that Dynamics 365 for Finance and Operations, Enterprise edition in the background uses full page compression for the whole AX database. If you would like to use the upgrade scripts from 2012, even the documentation mentions that compression is a pre-requisite step:

https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/migration-upgrade/prepare-data-upgrade

As a result we have seen great performance boost for the tables involved and much lower numbers in the slow performing SQL statements, since more data could be kept in the SQL memory buffer.

Implementing Microsoft Dynamics 365 for Finance and Operations – Book review

It has been very busy times in the past couple of weeks, by doing the preparation steps for our upgrade to Dynamics 365 for Finance and Operations at JJ Food Service. As you can imagine it is not an easy task with an AX system that has been running for 11+ years, upgraded for every major version since 3.0 with a 2TB+ database size. As the Technical architect and with no partner involved I needed to understand all the components, challenges to be expected, processes to be completed in order to carry out a successful move to the cloud. Fortunately I have received an editorial copy of Implementing Microsoft Dynamics 365 for Finance and Operations.

Implementing Microsoft Dynamics 365 for Finance and Operations
Implementing Microsoft Dynamics 365 for Finance and Operations

First of all I really like the idea that the book starts with an introduction of the various Dynamics 365 products and reporting/data management tools, since Microsoft’s intention is to bundle together different applications in the cloud via a subscription-model. This gives a great overview of the available tools. One point to mention here is that CRM has been split up and compartmentalized as different, smaller applications. This is the direction where Dynamics AX is heading as well eventually.

The Implementing Microsoft Dynamics 365 for Finance and Operations book is also touching up on Application Lifecycle Management (ALM), through the utilization of LifeCycle Services (LCS) portal. This is what we use for managing and architecting our environments, going through the project implementation, mapping our business processes, deploying data packages and releasing code.

Since the book is aimed at audience like myself, technical architects with a strong development background, I have found this book to be an excellent resource for getting into the nooks and crannies of using Visual Studio for development, VSTS for version control, walking through the various major changes like ditching AIF for RESTful API, JSON and OData.

I also really like that the book touches up on the automated testing part, which is very much neglected in most implementation projects. I would expect that it would change in the future, forcing customers and partners to provide testing in some form before code could be applied in a Production instance with a certain code coverage threshold met.

All-in-all I found the details very well summarized in the book, and is a great starting point to build essential knowledge for a new AX 7 implementation project. The rest could be filled in by reaching out to the extensive Microsoft Docs site as a detailed technical and user manual, if you need more insight into the various areas.

By |2020-03-23T13:49:16+01:00February 27th, 2018|Categories: AX 7, Dynamics 365 for Finance and Operations|Tags: , |1 Comment
Go to Top