Sunday, 4 September 2016

Query Ranges in X++

Query Ranges in X++


Expressions in query ranges
One of least understood but most powerful Axapta features is the so-called Expressions in query ranges syntax. This is not the same as simply using a QueryBuildRange object in a query and specifying a criteria for a single field.

Introduction

This is a method of specifying ranges on queries which allows you to perform complex comparisons, and create complex join situations which would be impossible using the standard syntax.


Syntax

To use the special syntax, you should first add a range to your QueryBuildDataSource object in the normal way. Note that for this special syntax, it does not matter which field you use to add the range.
To specify the range value itself, certain rules must be followed:
§  The entire expression must be enclosed within single-quotes, not double-quotes
§  The entire expression must be enclosed in parenthesis (brackets)
§  Each sub-expression must be enclosed in its own set of parenthesis
§  For fields in the current table, simply the field name can be used
§  For fields in other tables, a prefix of the relevant datasource name must be added. This is not always the same as the table name.
§  String values should be surrounded by double-quotes, and wrapped in a call to queryValue()
§  Enum values should be specified by their integer value
§  Date values should be formatted using Date2StrXpp()
§  Blank string like ' ' will not work as expected, use sysquery::valueEmptyString().


Examples

In the example below, we construct a query and add a single datasource.
The range is then added, using the DataAreaId field on each table. Any field can be used, but using an unusual one such as DataAreaId helps remind a casual reader of the code that it's not a normal range.

query = new Query();
dsInventTable = query.addDataSource(tableNum(InventTable));
 
// Add our range
queryBuildRange = dsInventTable.addRange(fieldNum(InventTable, DataAreaId));
Given the above, the following are valid range specifications:

 

Simple criteria

Find the record where ItemId is B-R14. Take note of the single quotes and parenthesis surrounding the entire expression.
queryBuildRange.value(strFmt('(ItemId == "%1")', queryValue("B-R14")));
Find records where the ItemType is Service. Note the use of any2int().
queryBuildRange.value(strFmt('(ItemType == %1)', any2int(ItemType::Service)));
Find records where the ItemType is Service or the ItemId is B-R14. Note the nesting of the parenthesis in this example.
queryBuildRange.value(strFmt('((ItemType == %1) || (ItemId == "%2"))', 
    any2int(ItemType::Service),
    queryValue("B-R14")));
Find records where the modified date is after 1st January 2000. Note the use of Date2StrXpp() to format the date correctly.
queryBuildRange.value(strFmt('(ModifiedDate > %1)', Date2StrXpp(01012000)));
Find records where the Field is blank (null) or an empty string. For more see Sys::Query Docs
qbrStatement = this.query().dataSourceName("BankAccountTrans2").addRange(fieldnum(BankAccountTrans,AccountStatement));
//qbrStatement.value("!?*");//this is the old way that may not work in future versions of AX
qbrStatement.value(sysquery::valueEmptyString());//this is the new way 

 

Complex criteria with combined AND and OR clauses

Find all records where the ItemType is Service, or both the ItemType is Item and the ProjCategoryId is Spares. This is not possible to achieve using the standard range syntax.
Note also that in this example, we are using the fieldStr() method to specify our actual field names and again, that we have nested our parenthesis for each sub-expression.
queryBuildRange.value(strFmt('((%1 == %2) || ((%1 == %3) && (%4 == "%5")))',
    fieldStr(InventTable, ItemType),
    any2int(ItemType::Service),
    any2int(ItemType::Item),
    fieldStr(InventTable, ProjCategoryId),
    queryValue("Spares")));

 

WHERE clauses referencing fields from multiple tables

For this example below, we construct a query consisting of two joined datasources (using an Exists join). Note that we specify the datasource names when adding the datasources to the query.
The ranges are then added, using the DataAreaId field on each table as described in the earlier example.
query = new Query();
dsInventTable = query.addDataSource(tableNum(InventTable), tableStr(InventTable));
dsInventItemBarCode = dsInventTable.addDataSource(tableNum(InventItemBarCode), tableStr(InventItemBarCode));
dsInventItemBarCode.relations(true);
dsInventItemBarCode.joinMode(JoinMode::ExistsJoin);
 
// Add our two ranges
queryBuildRange1 = dsInventTable.addRange(fieldNum(InventTable, DataAreaId));
queryBuildRange2 = dsInventItemBarCode.addRange(fieldNum(InventItemBarCode, DataAreaId));
Find all records where a bar code record exists for an item and was modified later than the item was modified.
In this example, we are using the range on the BarCode table. Therefore the unqualified ModifiedDate reference will relate to InventItemBarCode.ModifiedDate. The other field is a fully-qualified one, using the DatasourceName.FieldName syntax.
queryBuildRange2.value(strFmt('(ModifiedDate > InventTable.ModifiedDate)'));
Note that if we had added our InventTable datasource using the following code
dsInventTable = query.addDataSource(tableNum(InventTable), "InventTableCustomName"); // Note that we are manually specifying a different datasource name 
then the query range would need to appear as follows
queryBuildRange2.value(strFmt('(ModifiedDate > InventTableCustomName.ModifiedDate)'));

 

Conditional joins

We will modify our previous example slightly, to remove the automatic addition of relations for the join.
query = new Query();
dsInventTable = query.addDataSource(tableNum(InventTable), "InventTable");
dsInventItemBarCode = dsInventTable.addDataSource(tableNum(InventItemBarCode), "InventItemBarCode");
dsInventItemBarCode.joinMode(JoinMode::ExistsJoin);
 
// Add our two ranges
queryBuildRange1 = dsInventTable.addRange(fieldNum(InventTable, DataAreaId));
queryBuildRange2 = dsInventItemBarCode.addRange(fieldNum(InventItemBarCode, DataAreaId));
We can now use the query expression to specify whatever we like as the join criteria.
Find all records where either the ItemType is Service, or the ItemType is Item and a barcode exists. The join criteria is only applied in the second half of the expression, so all Service items will appear irrespective of whether they have a bar code. Again, this is not possible to achieve using the standard query ranges.
queryBuildRange2.value(strFmt('((%1.%2 == %3) || ((%1.%2 == %4) && (%1.%5 == %6)))',
    query.dataSourceTable(tableNum(InventTable)).name(), // InventTable %1
    fieldStr(InventTable, ItemType), // ItemType %2
    any2int(ItemType::Service), // %3
    any2int(ItemType::Item), // %4
    fieldStr(InventTable, ItemId), // ItemId %5
    fieldStr(InventItemBarCode, ItemId))); // %6 
Using the techniques above, it is possible to create queries with almost as much flexibility as using SQL statements directly.
Filter on array fields
queryBuildRange.value(strFmt('((%1.%2 == "%4") || (%1.%3 == "%5"))', 
    queryBuildDataSource.name(),
    fieldid2name(tablenum(<table>), fieldid2ext(fieldnum(<table>, Dimension), Dimensions::code2ArrayIdx(SysDimension::Center))), 
    fieldid2name(tablenum(<table>), fieldid2ext(fieldnum(<table>, Dimension), Dimensions::code2ArrayIdx(SysDimension::Purpose))), 
    "some dim2 value", 
    "some dim3 value"));
Note: you must always specify the datasource name if you use Query Expression syntax to filter on array fields. See also Limitations section at the bottom of the page.

 

Using wildcards and comma-separated range values

Again, the previous example here was using standard syntax, not the special syntax using expressions. It's not possible to modify the above examples to work with wildcards.
The above statement applies to AX versions < 5.0
AX 5.0 introduced solution to wildcards - while you still cannot directly use wildcards in ranges, now it supports the 'LIKE' keyword.
(AccountNum LIKE "*AA*" || Name LIKE "*AA*")

Sunday, 21 August 2016

Installation of Management Reporter 2012 for AX 2012

Installation of Management Reporter 2012 for AX 2012

Reference Link
This post will take you through the basic steps of installing, configuring and a basic test of Management Reporter 2012 for AX 2012. This tool is now easily available after AX 2012 R2 CU7 as part of the Dynamics AX Setup and the tools has also been translated and made available for multiple languages.

The Reporting tool has a lot of features and Microsoft has release several videos to cover some of the functionality. Technet also describes in detail how to install and setup this tool, and you can also download a comprehensive set of whitepapers and documents covering a lot of ground for this tool.

For the sake of simplicity, I will run you through the setup with some screen shots. I am assuming you're the tech guy which has been given the task by the financial consultant to get this tool installed as soon as possible.
As with all UI, there might be minor changes in the upcoming versions.

The guide will be in three sections:

  1. Installing the Server components
  2. Installing the Client components
  3. Testing!

Before you begin you should have prepared a new domain user which will be used by the service to connect and collect data from AX. I will assume you have full access to the AOS and SQL Server and that you are on AX2012 R2 with CU7 (or higher). Needless to say, but you can obviously do all the three steps above on the same machine - if that is your swag.

Estimated installation time? We should be done within an hour. :-)


1. Installing the Server Components

Run AXSetup and choose to install "Management Reporter"


Type in the details for the AOS you want to the Management Reporter Service to connect to. This is neat if you want to diversify what AOS you want to handle any load.



Select the SQL Server Instance and Database holding the business data. In my example setup threw an error before I was able to select an actual server running a SQL Server Instance. Maybe they'll fix that in some update.  



Enter the credentials for the service account which the Management Reporter Service will run as. I chose to use the same service account as the AOS.



Type in some additional details for the Management Reporter Service. Default port is 4712. The first database entry points to the configuration database. The second to the data mart database, which will hold report data. I just added a suffix so I can test installing multiple instances later on. 



Finally type in the credentials for the domain user which will be used to connect to AX and collect data. Either let the installer set it up or choose an existing AX User ID.


Done!



Before we continue, let us check some things. You should have a new shortcut named "Configuration Console" on the Start menu. Open the Console, locate  "Data Mart Integration" and hit Refresh. Observe that things look promising. It might take a few minutes before data has been collected fully to the Data Mart Database. 



Oh, and if you wonder how that link from AX works, you should also have an entry in LedgerParameters.ManagementReportUrl for the company that has an active integration. Setup should have added that. If not, you will have to do some manual steps from this Configuration Console, but that is not the scope of this post.

2. Installing the Client Components


Run AXSetup and chose to install "Management Reporter Report Designer". This will install both the Designer and the Viewer. You can install these on the terminal server if that fits your requirements. 



Done!




3. Testing!

Let us do some testing now that we have things installed!

The Designer


First, let's test the Designer. Locate the shortcut "Report Designer" under the Start menu. 



Enter the url to the server and port where the Management Reporter is running and connect. This is a one time per user per machine thing (as far as I know).



Select a company and hit the "Set As Default".



Select the first report and hit "Generate" on the toolbar.



Observe while the report is generated. Let it complete and wait for the report to be launched in a new window.


And the report should open. Yea, I hid some of the numbers from my demo.


The Viewer

Now for the Viewer. Locate the shortcut "Report Viewer" under the Start menu.



This tool might also need to have its connection properly set. The setting is under Tools, Connection.



Double click the generated report located in the Report Library and observe it loads an integrated view of the report.



And that is it. Now tell me, did it take you more than an hour to get this up? Next up is to inform the financial consultants that you're done and they can start hammering the tool for awesome reports. 

Final note

Have someone with access to the customer license (VOICE) download the license for the Management Reporter. It is its own license file, and you only have to copy+paste its content into the Registration form under Tools. If you don't do this step, you are limited to less than a handful of users, which is fine for testing, but not the real deal.

Also, don't bother to add users manually. These will be populated from AX dependent on what users have access to what. This is all documented in the Installation Guide for the AX provider.

Data are being held up to date by using SQL Server Change Tracking. If you however notice data not being refreshed and updated properly, you will find steps to resolve this in the already mentioned guide.

I hope this little guide helped you get going with Management Reporter 2012 for Dynamics AX 2012 R2 (CU7 and upwards). There are plenty of guides out for both installing, configuring and using this Reporting tool - I just felt like making one myself as well.

Saturday, 13 August 2016

Report to display current record in the Form in ax 2009


Reportàmethodsà initFromCaller
public void initFromCaller(Args _args)
{
    BiddingMainCostSheetTable     _BiddingMainCostSheetTable;
    BidServiceCostSheetTable _bidServiceCostSheetTable;
  //  BidSvcsBOQSectionTable _bidSvcsBOQSectionTable;
    QueryBuildDataSource    qbds;
    ;
    if (_args.caller())
    {
        if (! _args.record().RecId)
            throw error(strfmt("@SYS22338",funcname()));

        switch (_args.dataset())
        {
            case tablenum(BiddingMainCostSheetTable):
                _BiddingMainCostSheetTable  = _args.record();
                qbds = element.query().dataSourceTable(tablenum(BiddingMainCostSheetTable));
                qbds.clearRanges();
                SysQuery::findOrCreateRange(qbds, fieldnum(BiddingMainCostSheetTable, MainCostSheetId));

                if (_BiddingMainCostSheetTable.MainCostSheetId)
                {
                    SysQuery::findOrCreateRange(qbds, fieldnum(BiddingMainCostSheetTable, MainCostSheetId)).value(_BiddingMainCostSheetTable.MainCostSheetId);
                }
                break;
            case tablenum(BidServiceCostSheetTable):
                _bidServiceCostSheetTable = _args.record();
                qbds = element.query().dataSourceTable(tablenum(BiddingMainCostSheetTable));
                qbds.clearRanges();
                SysQuery::findOrCreateRange(qbds, fieldnum(BiddingMainCostSheetTable, MainCostSheetId));

                if (_bidServiceCostSheetTable.MainCostSheetId)
                {
                    SysQuery::findOrCreateRange(qbds, fieldnum(BiddingMainCostSheetTable, MainCostSheetId)).value(_bidServiceCostSheetTable.MainCostSheetId);
                }
                break;           
            default:
                throw error(strfmt("@SYS23396",funcname()));
        }
    }
}

AX Report 2009 displaying only on the last page

Hi, 
Normally developers need the term and condition or other stuff to be displayed only on the last page .To insert the footer only on the last page of Axapta report do the following stes.
1. Declare a boolean variable (pageFooter) in report class declaration method .
             public class ReportRun extends ObjectRun
            {
                 boolean pageFooter;
            }
2. Override the report fetch method with query 
          public boolean fetch()
          {
               boolean ret;
               ret = super();
               printPageFooter=false;
                while(queryrun.next())
                {

                }
               printPageFooter=true;
               return true;
          }

3. Override the executeSection method of footer 
      
          public void executeSection()
          {
                if(printPageFooter==true)

                super();
           }


Report to display current record in the Form On button click in ax 2009


Report to display current record in the Form On button click in ax 2009


·         In click method (First Method)
void clicked()
{
    Args                    args;
    ReportRun               reportRun;
;
    super();

    args = new Args();
    args.name(reportStr(NSGEmplVacations));

    reportRun = new ReportRun(args);
    reportrun.report().interactive(false);
    reportrun.query().interactive(false);
                                                                SysQuery::findOrCreateRange(reportrun.query().dataSourceTable(tablenum(EmplTable)),
                  fieldnum(EmplTable, EmplId)).value(Vacations.EmplId);
    reportRun.init();
    reportRun.run();
}
·         In the click method(Second Method)
1.       void clicked()
{
    Args        args;
    ReportRun   reportRun;
    NASVacationTransId      _VacationTransId;
      ;
    args = new args();
    args.name(reportstr(NSG_VacationRequestReport));
    args.record(Vacations);
    args.parm(Vacations.NASVacationTransId);
    reportRun = classFactory.reportRunClass(args);
    reportRun.init();
    reportRun.run();
}

2.       public boolean fetch()
{
    boolean ret;

this.query().dataSourceTable(TableNum(Vacations)).addRange(FieldNum(Vacations,    NASVacationTransId)).value(_VacationTransID);
    ret = super();

    return ret;
}

3.       public void init()
{
    _VacationTransID    = element.args().parm();
    _vacTable           = element.args().record();
    super();

}

Labels

#veryusefulcode (1) AIF (8) AOT Maps (1) Args (1) Ax 2009 Reports (2) AX 2012 navigation (1) Ax 2012 Interview Questions (1) AX 7 (2) AX Architecture (1) Ax Backup (1) AX Workflow (2) AX2012 (1) AX2012 R2 (1) Ax2012R3 (1) AX2012R3 Dynamics Connector Step by Step Installation and Configuration (1) AX2012R3 EP Step by Step Installation and Configuration EP R3 (1) AX2012R3 HelpServer Step by Step Installation and Configuration (1) AX2012R3 Rapid Start Connector Step by Step Installation and Configuration (1) AX2012R3 Report Server and Analysis Server Step by Step Installation and Configuration (1) AX7 (1) Best practices (1) Blocking user to enter (1) Collection Classes (1) Container (1) D365FO (3) Data Migration Frame Work ax 2012R3 (1) Deleting duplicate Record from Table – Ax2012 (1) Delivery due date notification workflow in Ax 2012 (1) Development Steps EP (1) Dimensions (1) DIXF (1) DMF in Ax 2012 R3 (1) Dynamics Ax 2012 Interview Questions (1) DYNAMICS AX 2012 INTERVIEW QUESTIONS PART 2 (1) DYNAMICS AX 7 (1) EDT relation Migration Tool (1) EP AX 2012 (1) Ep Lookup (1) Error (1) Event Handler (1) F5 (1) File Handling (4) Filter on AX2012 Listpage (1) filtering (2) financial dimensions in AX 2012 (3) form (1) images (1) Installation and Configration (4) Installation and Configuration (11) Installation of Management Reporter 2012 for AX 2012 (1) Interaction class in ax 2012 (1) Interview Question (1) Interview Questions For Ax 2012 (1) Invent DIm (1) Jobs (2) license (1) List page and form menuitem enable code (1) Methods (1) microsoft Dynamics AX 365FO (1) Number Sequence Generation – AX 2012 (5) Number Sequence2012 (1) OLTP-OLAP (1) Passing Args (1) Passing form caller and menu item caller in ax 2012 (1) Passing Multiple Records Args (1) Posting in Ax 2012 (1) POSTING PURCHASE ORDER (1) Query (1) Query Filter Form (2) Query Ranges in X++ (1) Question and Answer (1) Report (1) Reports Controller class (1) RLS in ax 2009 (1) SALES ORDER IMPORT/EXPORT FRAMEWORK BY DMF (1) Security (1) security roles (1) Security Sysqueryrangeutil (1) Sharepoint 2016 (1) SQL SERVER (1) SSRS (2) SSRS Reports Controller class (2) Table collections & Virtual company (1) Time (1) TIPS AND TRICKS (1) Web service AIF (3) Web Services on IIS (AIF) Step by Step Installation and Configuration (1) workflow ax2012 (1) Workflow installation (1) Workflow Method (3) X++ (1)