Pages

Monday, February 17, 2014

Exchange Rate field Enable in AX 2012

HI All

In standard AX, the AP invoice journal and the general journal contain the field for currency exchange rate. However, this field by default is not editable.

Path: Accounts payable à Journals à Payment journal à Lines à General tab
 
by default in standard this field is non editable .

Solution : To make this field as editable 
AOT-->Classes-->LedgerJournalFormTrans-->setExchRateEnabled() Method. Just comment this whole code automatically Exchange rate and Secondary exchange rate fields should get enabled.



Monday, February 3, 2014

AX SSRS Error: The request failed with HTTP status 401: Unauthorized.


In AX, when certain users attempt to access an SSRS report in an environment, they are getting the error 'The request failed with HTTP status 401: Unauthorized' (Figure 1 below). This was occurring for all reports for this user. Other users were able to access the report perfectly fine. The user was able to run everything perfectly the day before. The answer was Troubleshooting step 5 below: Log out of Windows instance and log back in. I'll provide the long troubleshooting steps below in case someone else's issue was different.




TROUBLESHOOTING STEPS:
This issue is a permissions issue somewhere. At this point, we need to determine if its an issue with the user accessing the report. You can do the below troubleshooting steps. This was the order I did it in but you don't have to do it in this order. 

  1. SSRS server (server permissions)
  2. SSRS reports (SSRS permission restrictions)
  3. AX security issue (probably not but good to check)
  4. An issue with all users or just them
  5. An issue with local cache or something screwy with current windows session
Troubleshoot 1: 
To help the users identify this issue, I usually ask them to do the following on the server where they are receiving this error:

  1. Click on the Start menu in Windows
  2. Type 'cmd' in the 'Search programs and files' search line in the start menu
  3. In the command prompt, type 'ping CDBRS-MAX01'
  4. Take a screenshot of the command responses and send back the results.
    1. The results should come back with the standard ping response of 'Reply from XX.XX.X.XXX: bytes=32...''.
If #4 got a weird response or an error message, the user doesn't have access to the server. Make sure they can ping the server and have them run it again. 

Troubleshoot 2:
Having established they can access the report server, have the user access the report through the SSRS server. Have them do the following in the server where the AX client is erroring and if necessary, the SSRS report server itself:

  1. Go to internet explorer and access the SSRS report server (commonly 'http://[SSRSSERVERNAMEHERE]/reports'
  2. Once here, go to 'Dynamics AX' folder
  3. click on the report that is erroring
  4. Run the report and see if it runs. Just make sure required fields are populated.
If the report runs for them, SSRS security should be good. If it fails, make sure they're setup in the proper groups to run the reports and try again. 

Troubleshoot 3:
Have the user run the report from a server other than the one where the user was encountering the error. I logged into the AOS on their machine under my name and did the hold shift+right click on the .axc file, enter their credentials so we were running AX as that user in my server instance, and try running the report. 

Troubleshoot 4: 
Have other users attempt to run that report as well as others. Determine if its an issue with just that user. If no one is able to run the report or others, the reports may need to be deployed or the SSRS server settings need to be checked.

Troubleshoot 5:
This actually resolved the issue. Something went wrong with the user's Windows server session. I wasn't exactly sure what the issue was but having the user log out and log back in to the server resolved.

In this test, do the following:

  1. go to the person's terminal and watch them try to run the report
  2. hold shift+right click on the .axc file they were using to run the report and run as a different user. Use your own user
  3. In AX under your user in their terminal session, try to run the troubled report. 
  4. If it passes (it did in my instance), hold shift+right click on the .axc file and run as a different user, only this time use the person's credentials. For us, the user was able to run the report this way but not when just clicking on the .axc in the normal fashion
Your issue might be different but this was what it was for us so I decided to share.  Hope this helps!

How To: Clear or Delete data from an AX container



Using the conDel Function [AX 2012], a user can delete certain elements from a container. When these elements are removed, the numbering in the container will adjust accordingly so that the numbers will always be sequential

There are three parameters container conDel(container container, int start, int number):
  1. container container
    1. the container that the user wishes to have the data deleted from
  2. int start
    1. the spot in the container to start deleting values
      1. If this number is 0, it will not delete anything
      2. The number given will actually be deleted (e.g. 2 will actually include element 2 in the deletion)
  3. int number
    1. the number of elements to delete in the container
      1. If this number is larger than the container, it will delete everything from the start value on
static void daxTestDelContainer(Args _args)
{
    container   test = ['a','b','c','d','e','f','g','h','i']; 
    container   testManip = test;
    int         i; 

       
    info ("BEGIN TEST - the container data in full");
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }        

      
    info ("TEST conDel(testManip, 0, 3) - Remove 3 at spot 0");
    testManip = conDel(testManip, 0, 3);
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }    

    
    info ("TEST conDel(testManip, 1, 3) - Remove 3 at spot 1");    
    testManip = conDel(testManip, 1, 3);
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;    

    
    info ("TEST conDel(testManip, 2, 3) - Remove 3 at spot 2");
    testManip = conDel(testManip, 2, 3);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;

    
    info ("TEST conDel(testManip, 3, 5) - Remove 5 at spot 3");
    testManip = conDel(testManip, 3, 5);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;

    
    info ("TEST conDel(testManip, 3, 50) - Remove 50 (more than container has) at spot 2");
    testManip = conDel(testManip, 3, 50);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

}


Count Number of Tables,Forms EDT's in AX 2012


To count number of Tables, EDT's, Form's.. etc all objects in AOT . Run the below job to get number of objects available in AOT. 



static void daxCountTablesInAX(Args _args)
{    
    // Count of all the Objects.    
    info (strFmt("Tables in AX: %1", treenode::findNode('\\Data Dictionary\\Tables').AOTchildNodeCount()));    
    info (strFmt("Extended Data Types in AX: %1", treenode::findNode('\\Data Dictionary\\Extended Data Types').AOTchildNodeCount()));    
    info (strFmt("Forms in AX: %1", treenode::findNode('\\Forms').AOTchildNodeCount()));
    info (strFmt("Parts-- Infoparts in AX: %1", treenode::findNode('\\Parts\\Info Parts').AOTchildNodeCount()));
    info (strFmt("Part- Form Parts in AX: %1", treenode::findNode('\\Parts\\Form Parts').AOTchildNodeCount()));
    info (strFmt("Part -- Cues in AX: %1", treenode::findNode('\\Parts\\Cues').AOTchildNodeCount()));
    info (strFmt("Part-- Cue Groups in AX: %1", treenode::findNode('\\Parts\\Cue Groups').AOTchildNodeCount()));
    info (strFmt("DataSets in AX: %1", treenode::findNode('\\Data Sets').AOTchildNodeCount()));
    info (strFmt("SSRS Reports in AX: %1", treenode::findNode('\\SSRS Reports\\Reports').AOTchildNodeCount()));
    info (strFmt("SSRS Reports report style templates in AX: %1", treenode::findNode('\\SSRS Reports\\Report Style Templates').AOTchildNodeCount()));
    info (strFmt("SSRS Report report datasources in AX: %1", treenode::findNode('\\SSRS Reports\\Report Datasources').AOTchildNodeCount()));
    info (strFmt("Report Images in AX: %1", treenode::findNode('\\SSRS Reports\\Report Images').AOTchildNodeCount()));
    info (strFmt("Report Templates in AX: %1", treenode::findNode('\\Reports\\Report Templates').AOTchildNodeCount()));
    info (strFmt("Report Section Templates in AX: %1", treenode::findNode('\\Reports\\Section Templates').AOTchildNodeCount()));
    info (strFmt("Visual Studio Projects of Dynamics AX Model Projects in AX: %1", treenode::findNode('\\Visual Studio Projects\\Dynamics AX Model Projects').AOTchildNodeCount()));
    info (strFmt("Visual Studio Projects of C Sharp Projects in AX: %1", treenode::findNode('\\Visual Studio Projects\\C Sharp Projects').AOTchildNodeCount()));
    info (strFmt("Visual Studio Projects of Web Application Projects in AX: %1", treenode::findNode('\\Visual Studio Projects\\Web Application Projects').AOTchildNodeCount()));
    info (strFmt("Visual Studio Projects of Analysis Services Projects in AX: %1", treenode::findNode('\\Visual Studio Projects\\Analysis Services Projects').AOTchildNodeCount()));
    info (strFmt("Menus  in AX: %1", treenode::findNode('\\Menus').AOTchildNodeCount()));
    info (strFmt("Menu Items Display in AX: %1", treenode::findNode('\\Menu Items\\Display').AOTchildNodeCount()));
    info (strFmt("Menu Items Output in AX: %1", treenode::findNode('\\Menu Items\\Output').AOTchildNodeCount()));
    info (strFmt("MenuItems Action in AX: %1", treenode::findNode('\\Menu Items\\Action').AOTchildNodeCount()));
    info (strFmt("Reports- Report Templates in AX: %1", treenode::findNode('\\Reports\\Report Templates').AOTchildNodeCount()));
    
}

Passing Multiple Records from one form to another through Args in Dynamics Ax 2012

The Scenario is when I select multiple grids in Form A, those records will be passed to FormB and there FormB will received the all those records and filter it and will show.

Step 1: Make one SampleTable which has three fields named (SIno, name, AddressCity).
Step 2: Make FormA with datasource as SampleTable and drag the datasource fields into the design Grid.
Step 3: Drag one button and override the click method and write the following code.
step 4: Make one Display menuitem of FormB.


void clicked()
{
int recordsCount;
SampleTable _sampleTable;
container con;
Args args;
str multiSelectString;
;
args = new Args();
recordsCount = SampleTable_ds.recordsMarked().lastIndex(); // gets the total records selected
_sampleTable = SampleTable_ds.getFirst(1);
while (_sampleTable)
{
// storing recid of selected field in container
con = conIns(con,1,_sampleTable.RecId);
// converting container to string with comma separated
multiSelectString = con2Str(con,’,');

_sampleTable = SampleTable_ds.getNext(); // moves to next record
}
// passing string
args.parm(multiSelectString);
// calling menu item
new MenuFunction(menuitemDisplayStr(FormBMenuItem), MenuItemType::Display).run(args);
}

step 5: Make FormB with datasource as same table for which you take for Form A i.e., SampleTable and drag the fields in to the
Grid of design part.
step 6: write the following code in to the init method of FormB.

public void init()
{
container con;
int i;
str multipleRecords;
super();
// getting string value from caller
multipleRecords = element.args().parm();
// string to container
con = str2con(multipleRecords,”,”);
// for sorting
for(i = 1;i<= conLen(con) ;i++)
{
SampleTbl_ds.query().dataSourceTable(Tablenum(SampleTbl)).addRange(fieldNum(SampleTbl,RecId)).value(SysQuery::value(conPeek(con,i)));
}
}

Passing Args from one Form to another Form in Dynamics Ax 2012

Args concept in dynamics ax is awesome. one can easily pass arguments from one Form to another Form with very less effort. Here, i am going to demonstrate how to pass Arguments from Form to Form. The Scenario is when I select one grid in Form A, that record will be passed to Form B and there Form B will received the whole record and filter it and will show.


Step 1: Make one SampleTable which has three fields named (SIno, name, AddressCity).

Step 2: Make FormA with datasource as SampleTable and drag the datasource fields into the design Grid.

Step 3: Drag one button and override the click method and write the following code.

void clicked()
{
Args args;
FormRun formRun;
;
super();
args = new args(formstr(FormB)); // sending Args(record) to FormB
args.record(SampleTable);
formrun = classfactory.formrunclass(args);
formrun.init();
formrun.run();
formrun.wait();
formrun.detach();

}






step 4: Make FormB with datasource as same table for which you take for Form A i.e., SampleTable and drag the fields in to the
Grid of design part.



step 5: write the following code in to the init method of FormB.

public void init()
{
SampleTable _sampleTable;
super();
_sampleTable = element.args().record();
SampleTable_ds.query().dataSourceTable(Tablenum(SampleTable)).addRange(fieldNum(SampleTbl,RecId)).
value(SysQuery::value(_sampleTable.Recid));
}