-->
Use of Category Hierarchy are a great way to classify our items ad other stuff. 


There can be scenarios in which you need to associate a particular entity (Item for instance) with Category Hierarchy. Once required, you will need the user to select a category (from the category hierarchy tree) against the entity which you are associating with category. 

Generally it would mean a lot of work. Make a custom form, drop the tree control, write complete tree populating logic, on user click event pass the category RecID to the parent form and so on. But this is not the way we develop on systems that are classified under the category of ERP :)

We are suppose to reuse the existing logic to save time and effort, and extend AX rather reinventing.

One of my friend, an expert in his domain ما شاء الله , Amir Nazim helped me in this. He gave me the correct reference of a perfectly reusable solution already applied on Purchase Order (Procurement module) form.

At the very bottom, we need a primary key based relation between your table and EcoResCategory table (The table that actually holds the definition of each category item). Hence on PurchLine Table, we have a relation with EcoResCategory table 

And on PurchTable Form, are the two overridden methods (at DataDource > PurchLine ) as follows;
  • lookupReference
  • resolveReference
Bodies of both the methods are provided for our reference;


//lookUpReference()

    return EcoResCategory::lookupCategoryHierarchyRole(
        _formReferenceControl,
        EcoResCategoryNamedHierarchyRole::Retail);
//resolveReference()

public Common resolveReference(FormReferenceControl _formReferenceControl)
{
    return EcoResCategory::resolveCategoryHierarchyRole(
        _formReferenceControl,
        EcoResCategoryNamedHierarchyRole::Retail);
}

These two methods does the rest for us that is populating the tree, displaying it as a lookup and etc. Enjoy re-usability :)

Transact SQL - nth day of Month (DateName)

maqk® by Maqk | 3:10 AM

One of my projects wants me to identify the given date's day name (DateName) ad find its occurrence in the given month. Say today is Tuesday, 20th May 2014, and this is the 3rd Tuesday of this month.

Once it is identified that the given date [20 may 2014] is 3rd Tuesday of the month, go back to last month's 3rd Tuesday, print sales data, keep going back for last 4 months and print sales data, interesting :) yet tiring too

So we are going to know if today, or any given date's day (DateName) is 2nd Monday of the Month, or 4th Tuesday  ? or 3rd Sunday ? or nth day of Month

Just now I wrote some code to find the occurrence of day in current month. The code is not refactored for any good :D (Sorry its mid mid night and my brain cells are too short i guess). Any ways it does the trick

Declare @du_date datetime, @du_date_FirstDate datetime
Declare @du_date_DateName nvarchar(10), @thDayOccStr nvarchar(4)
Declare @thDayOcc int

Set @du_date = getDate()

Select @du_date_DateName = DATENAME(dw, @du_date)

Set @thDayOcc = 0
Set @du_date_FirstDate = dateadd(day,1-datepart(day,@du_date),@du_date)

While (@du_date_FirstDate <= @du_date)
Begin
--** Calculate which th day it is of this month, next we will find same for last month(s) **--
if (DATENAME(dw, @du_date_FirstDate) = @du_date_DateName)
Begin
Set @thDayOcc += 1
--** FOR LOGGIN , U MAY ENABLE FOLLOWING **--
--Select 'Adding', DATENAME(dw, @du_date_FirstDate_Copy), @du_date_DateName, @thDayOcc
End

Select @du_date_FirstDate = DateAdd(dd,1,@du_date_FirstDate)
End
Set @thDayOccStr = Convert(nvarchar(100), @thDayOcc)

Select [Date processed] = @DU_Date, @du_date_DateName, [DateName occurence in Month] = @thDayOcc,
 @thDayOccStr +
Case
When @thDayOcc = 1 Then 'st '
When @thDayOcc = 2 Then 'nd '
When @thDayOcc = 3 Then 'rd '
Else 'th '
End
+ @du_date_DateName + ' of the Month'
There are tons of blog posts available on the internet guiding to use business connector for read/write operations. Most of them are dealing with how to write opening a table buffer, initializing it, setting field values (set_Field()) and then hitting the write operation.

This is good and simple, and so is sending parameters to table / class, but I could not find the later under any relevant title, hence getting the exactly required thing difficult.

I found my need fulfilled somewhere in Mr. Corey Lasley's blog post: Using the .NET Business Connector to Export...

So the topic actually is about reusing existing business logic. And in doing so, you will need to call several existing, well defined, well tested Class / Table methods. And in doing so.... :D you may need to call paramater less and parameter requiring static methods.

There are two methods inside the 'Axapta' class, 'CallStaticClassMethod' and 'CallStaticRecordMethod'. Both of them calls static methods from Class objects and Table objects respectively. The below code (.Net --> C#) excerpt provides a tutorial for calling an existing existing table method and passing parameters to it.

Axapta ax;
            AxaptaRecord objAxRec;
            Object[] parm = new Object[2]; 
            Object result;
            parm[0] = "Param1Value";
            parm[1] = "Param1Value";

            try
            { 
                ax = new Axapta();
                ax.Logon(null, null, null, null);
                result = ax.CallStaticRecordMethod("InventSum", "find", parm);                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
As you can see, an array of objects (size of method's parameter count) is assigned values and passed it as the last parameter.

For classes, use 'CallStaticClassMethod'
Often we need to make action panes and menu items on customized locations which form templates won't generate. Hence we need the icon ids for icons like new, edit, cancel, excel etc. Sure you will open a system form (Say salestablelistpage) and check their the icons and their ids. 

A good alternative is to have a reference table / list of all such icons you may require again to use later in such a scenario. So here it goes :)

Common image IDs for Action pane (Embedded / AOT Resources)

NEW BUTTON GROUP

New:   11045


MAINTAIN BUTTON GROUP
Edit:   10040
Edit in grid:  10011
Cancel (document): 10406
Delete:   10121


COPY GROUP
Copy:   12475
Copy Lines:  12218


OTHERS
Summary (calc):  10832
Print Mgmt:  10698
Line Quantity:  12415
Trade Agreement: 12430
Cases:   11229
Document confirmation: 10511
Line Amounts:  12458 (11038)

LIST GROUP
Send to Excel:  10156
Refresh:  11437


ATTACHMENTS GROUP
Attachments:  10442
Generate from Template: ImageResourceOfficeTemplate_ico [AOTResource]


Dynamics AX 2012: Add new design to a control document (report)

maqk® by Maqk | 5:36 PM

There can be reasons to add a new design to an SSRS report
  •  Have multiple designs side by side and print each for specific scenario
  • Have the new customized design deployed while preserving the original one
  • Have designs for different localization (As seen in AX default reports)
Its your choice. I used to keep the original report layout and fields so that I can get to the previous state whenever I want without worrying of any XPO imports. For a simple report, this may be as straightforward as mentioning the report deign name in the ssrsReportName method as follows;

However for control documents (reports generated at each specific state of a business document), this needs one more level of definition.

Set Custom design from code

Normally the report name is provided to the class as follows
controller.initArgs(_args, ssrsReportStr(SalesPackingSlip, report));

The ssrsReportStr method takes 2 parameters
  1. The report name - string
  2. The deisgn name - string
For control documents, this alone is not enough. Control document designs / formats are to be configured from the Print management feature provided in setup.

Path: -> Setup .> Forms -> Forms Setup
e.g. Accounts Payable > Setup > Forms > Forms Setup


The form provides each control document identified by the system and report and its format associated as default.

But your custom design won't appear in the configuration form unless a system class is modified for the same. There is a class with the name, "PrintMgmtDocType" with a method, 'getDefaultReportFormat()'. The default report design of a control document is resolved when the framework calls this method. You will notice that all the different localization based report formats are mentioned under the localization checks. In order for your custom design to appear in the configuration, you will have to return your custom design in some condition in this method.

For example, suppose you have added a new custom report design for sales invoice report. The code modification may look as follows;
case PrintMgmtDocumentType::SalesOrderInvoice:
if (SysCountryRegionCode::isLegalEntityInCountryRegion([#isoEE]))
{
    return ssrsReportStr(SalesInvoice, ReportEE);
}
return ssrsReportStr(SalesInvoice, CustomDesign);

You may add conditions like configuration key checks, company name, localization, menu item checks etc to decide which design to load.

Also note that these designs are originally built in the Visual Studio IDE (reporting tools extensions). When the AX model is build in visual studio and compiled in AOT, the new dsesign name is also available in X++ and would get compiled. Otherwise, the AOT may give error and may not recognize the new design. After the above code, the Print Management setup form would look like this;


Select the custom design and generate the particular control documents to see your new design in action :)
السلام عليكم و رحمة الله و بركاته
Hello and many congrats to all the readers for the new year. With the new year comes new challenges and their solutions. We continue to experience new hurdles and when we successfully handles them, create new blog posts to share our resolution with the readers. I wish this series of NEW thing continues to help us enhance our experiences to perform better in our professional careers :)

This new year eve I spent on my live client only to get surprise to see an error while deploying the changes that I made in the SalesInvoiceReport. After right clicking the report (emphasized due to recent changes)



Actually I added a new design to keep the original layout and created a new one. But all this complexity did not collaborated in the production of this error. I checked the report server is rightly configured in AX (validated the configuration to get all success), checked the report server configuration, it has to be fine since the all the reports were working fine flawlessly. 

Definitely there was something wrong due to some recent things I added. The SSRS report would compile OK, The DP and controller classes would compile fine. The model object... ahan. I compiled the model object to get a few errors. I cant remember the exact error now, and unfortunately I could not take any snapshot then, but one of the errors I remembered said 
'GenerateRdlTask failed'
Googling all this gave nothing exact for my problem. until I somehow looked in the windows event log which removed all the dark clouds in front of me and gave the real picture right in front of my eyes


Exception trace

Generation of the WCF configuration has failed, and the previously saved local configuration will be used.
Exception details:
System.InvalidOperationException: Unable to connect to a Microsoft Dynamics AX WCF service. Ensure that the Microsoft Dynamics AX AOS has fully started and that the requested WCF service is available. See the exception message below for details:
>Metadata contains a reference that cannot be resolved: 'http://myserver:8101/DynamicsAx/Services/MyMisConfiguredWebService'.
   at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.ClientConfigurationInternal.GetEndpointCollectionFromWsdlUri(String wsdlUri)
   at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.ClientConfigurationInternal.RetrieveIntegrationPortEndpoints(String aosServer, Int32 wsdlPort, List`1 portInfoList, Dictionary`2 endpointPortMap)
   at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.ClientConfigurationInternal.RetrieveEndpointsFromMetadata(String aosServer, Int32 wsdlPort, List`1 portInfoList, Dictionary`2 endpointPortMap)
   at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.ClientConfigurationInternal.ParseWsdlFromAos(String aosServer, Int32 wsdlPort, List`1 portInfoList)
   at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.ClientConfigurationInternal.GetClientConfiguration()

WCF Configuration

Initially I could not realize this error is related to my issue, deploying a changed report from AOT. But soon I realized this error will generate whenever I will attempt to deploy the report. This means that WCF configuration is always generated whenevr a report is attempted for deployment. I have ye to explore this things. I know that SSRS is based on WCF (and so is the new batch framework, SysOperationsFramework that is).

Architecture with dependency ?

But still should there be a new WCF configuration generation at deployment of each report ? Which will fail eventually if any web service endpoint is maliciously configured ? I think we definitely can have improvements here :)

The exception trace clearly mentions one of my test web service which was long stopped / moved whatever and was not taken care of since a lot of time. I saw a red "minus" icon (common for disabled or not working item representation) along with it. I deactivated it and then deployed the report. The report deployed with no more exceptions

Conclusion

Whenever a report is deployed, the WCF configuration is generated which can fail if any web service is misconfigured. The above stack trace confirms this.

AX 2012 R2 - Installing new databases from setup

maqk® by Maqk | 7:43 PM

Their can be scenarios when you want multiple databases on the same service. For example having a separated testing environment, development environment, staging and production.

I mentioned one such scenario in one of my previous posts in which I installed the new databases only to see the face of another error :) The 110 error code. 


The thing is, when you install new databases from the AX 2012 R2 setup, it does install new databases quite successfully. However, it misses two critical stored procedures on the database, the CREATESERVERSESSIONS and CREATEUSERSESSIONS

You can get these stored procedures from any dynamics ax 2012 r2 database and an apply on to your new database to fix the error.

top