Pages

July 26, 2012

How to split a Form in two window

hi Friends,
WE a going to create a new form and want to show this form in two interrelated windows, like the following form
Untitled
on the basis of the header the line level information will update,
so for get this type of design in your form you have to write three methods in from design.
1.
int mouseDown(int x, int y, int button, boolean ctrl, boolean shift)
{
    int ret;
    ret = super(x, y, button, ctrl, shift);
    return _formSplitterVertical.mouseDown(x, y, button, ctrl, shift);
}

2.
int mouseMove(int x, int y, int button, boolean ctrl, boolean shift)
{
    int ret;
    ret = super(x, y, button, ctrl, shift);
    return _formSplitterVertical.mouseMove(x,y,button,ctrl,shift);
}

3.
int mouseUp(int x, int y, int button, boolean ctrl, boolean shift)
{
    int ret;
    ret = super(x, y, button, ctrl, shift);
    return _formSplitterVertical.mouseUp(x, y, button, ctrl, shift);
}

after adding these three methods in your form design it will spilt  into two windows, now write your code for validation what ever is your requirement.

- Harry

Top 5 AIF Development Tips and Tricks

Top 5 AIF Development Tips and Tricks
1. Enable the debugger
You will notice, if you put a breakpoint into your document class, that when you run the associated action, the breakpoint will get ignored – leaving you in the dark. This is because the action is called using a ‘runas’ function call  to change the user executing the code.
To workaround this replace the runas method calls with direct calls in\Classes\AifOutboundProcessingService\ and \Classes\AifInboundProcessingService, eg:
1 /*
2 runas(message.sourceEndpointAxUserId(),
3 classnum(AifInboundProcessingService),
4 staticmethodstr(AifInboundProcessingService, processAsUser),
5 [message.pack(), messageId]);
6 */
7 AifInboundProcessingService::processAsUser([message.pack(), messageId]);

2. Run jobs instead of waiting for batch processing
The usual way for the AIF to run is using the batch processing framework, where you setup an interval for the inbound and outbound processing  to run.  This minute or so can feel like an age when you are in the middle of developing:
clip_image002
AIF batch processing
So use a custom job to have the AIF run instantly at the click of a button, here is an example of the receive job:
01 static void runAIFReceive(Args _args)
02 {
03 AifGatewayReceiveService aifGatewayReceiveService;
04 AifInboundProcessingService aifInboundProcessingService;
05 ;
06
07 aifGatewayReceiveService = new AifGatewayReceiveService();
08 aifGatewayReceiveService.run();
09 aifInboundProcessingService = new AifInboundProcessingService();
10 aifInboundProcessingService.run(true);  // pass true for debug mode
11 }

3. Use file adapters
clip_image004
When using the AIF, you will most likely be using a Biztalk, Web service or MSMQ adapter. Testing actions using one of these adapters can be a pain as you will most likely require another program to send or receive the message.
To get around this you can use a file adapter during testing, so that you can just write the message in plain XML and drop the file into a directory on your file system to be processed.
Then when you are finished testing / developing you can easily swap the file adapter out.
4. Compose messages with the Visual Studio XML editor
During development (when you use a file adapter), you can create the message using notepad or any other text editor. I recommend using the Visual Studio XML editor to quickly compose these to take advantage of intellisense, schema validation and other useful features (like inserting a guid):
clip_image006
5. Use the pipeline
It is unlikely (if you are integrating with a third party) that the XML schemas  of the external system match those in AX.
To transform the message into the format AX can handle you can use the pipeline to add a component to run an xslt on the inbound XML:
clip_image008


Enjoy...
Harry

July 25, 2012

How to fetch Values from WorkFlow Tables

How to fetch Values from WorkFlow Tables

Hi friends,
   I am facing a problem since many days and now i got the logic to fetch values from a workflow table, but still it’s for only PO and PR and i am working on the GL transaction also, here is the Code, Use copy and paste it in a job and run.

static void theaxapta_WorkflowHisory()
{
    WorkflowTrackingTable           workflowTrackingTable;
    WorkflowStepTable               workflowstepTable;
    WorkflowTrackingStatusTable     workflowTrackingStatusTable;
    WorkflowTrackingCommentTable    workflowTrackingCommentTable;

    utcdatetime     dt[];
    string100     Comment;
    int i;
    ;
    i = 1;
   select workflowtrackingtable join workflowsteptable
    where workflowsteptable.StepId == workflowtrackingtable.StepId
    &&    workflowtrackingtable.ContextRecId == PurchTable::find('NBH1112_PO000025').RecId;

   while select workflowtrackingtable
            where  workflowtrackingtable.ContextRecId == PurchTable::find('NBH1112_PO000025').RecId
    {

        dt[i] = workflowtrackingtable.createdDateTime;
        i ++;
        info(strfmt("Step Name == %1......  user Code: %2", workflowsteptable.Name,  workflowtrackingtable.User));
    }
    info(strfmt('User Approved: %1 - %2.....%3......%4.......%5..........', dt[1], dt[2],dt[3],dt[4]));

    select workflowTrackingCommentTable  where workflowTrackingCommentTable.TrackingId == workflowTrackingTable.TrackingId;
    while select workflowTrackingCommentTable  where workflowTrackingCommentTable.TrackingId == workflowTrackingTable.TrackingId
    {
        info(strfmt("Comment...=  %1",workflowTrackingCommentTable.TrackingMessage));
    }


//    select workflowTrackingCommentTable
//    where workflowTrackingCommentTable.TrackingId == workflowTrackingTable.TrackingId;
//
//    info(strfmt('Date Approved: %1', workflowTrackingCommentTable.TrackingMessage, DateTimeUtil::applyTimeZoneOffset(workflowTrackingCommentTable.createdDateTime, DateTimeUtil::getUserPreferredTimeZone())));
//

}

Note: This is rough code, you may need to update it as per your requirement.
Enjoy,
Harry.

Add a button to go to Main Transaction

Add a button to go to Main Transaction

Hi guys,

The following code for adding a button on your forms to go to the main transaction form/table, to do this type of magic you have to add a button on you form and copy paste the following code in the click method of that button.

void clicked()
{
    Common buffer;
    selectableDataArea company = curExt();
    Args args = new Args();
    SysDictTable dictTable;
    FormRun formRun;
    WorkflowTrackingStatusTable trackingStatus;
    ;
    trackingStatus = WorkflowTrackingStatusTable::findByCorrelation(WorkflowTrackingStatusTable.CorrelationId);
    if (trackingStatus.RecId)
    {
        changecompany(trackingStatus.ContextCompanyId)
        {
            dictTable = new SysDictTable(trackingStatus.ContextTableId);
            buffer = dictTable.makeRecord();
            select buffer where buffer.RecId == trackingStatus.ContextRecId;
            if (! buffer)
            {
                 info('You cannot go to the origin of the workflow instance. The record no longer exists or you do not have sufficient access.');
return;
            }
            dictTable.formRef();
            args.lookupRecord(buffer);

            args.name(dictTable.formRef());
            formRun = ClassFactory.formRunClass(args);
            formRun.init();
            formRun.run();
            formRun.detach();
        }
    }
}

This a very simple code to go to main Transaction Table, in above methods you can add your comment also to make it more user friendly, this a good practice to give error or empty records messages to End user to make your coding efficient and more user friendly.
-Harry

July 24, 2012

Reporting Framework in AX 2012

Hi friends,
    Today i want to share reporting concepts in AX 2012 with you guys.....

We will start with understanding basic concepts in Reporting Framework to examples.

Reporting Framework Terminologies,

As you all know, the reports in AX 2012 have moved to SSRS reporting, so MS has introduced a robust reporting framework wrapping over the basic SSRS reporting functionality. There are many terms used in reporting framework in AX that I will try and explain here:
·         Report Definition Language: RDL is an XML application primarily used with Microsoft SQL Server Reporting Services. RDL is usually written using Visual Studio. AX has Report Definition Language Contract classes that can generate and build the RDL for an AX SSRS report. This contract provides a weakly typed representation of parameters. It contains methods that can be used to get or set values. It also contains a map of parameter names and the SrsReportParameter class. The base class is SrsReportRdlDataContract.

·         Report Data Provider (RDP): A framework that helps in building, processing and rendering data to reports. Most of the reports require RDP classes that help in implementing business logic required to process data and provide data in readable, presentable and required formats design. The base class is SrsReportDataProvider. This class has two main sub classes,SrsReportDataProvderBase and SrsReportDataProviderPreProcess. We will discuss about these classes in future posts.

·         Report Data Contracts: The Report Data Contracts framework is used to provide and manage the parameters to an SSRS report. The report data contract contains all the other relevant instances like Report Data Provider contracts, print contracts, RDL contracts and query contracts that will be used by a report.

·         Printing Contracts: The framework that manages report printing (to different mediums). The base class is SrsPrintDestinationSettings. There are other supporting contracts that are used for printing, we will discuss about them in future posts.

·         Query Contracts: This framework manages the queries used to process report data. This framework is also responsible for providing dynamic filters (similar to our ‘Select” buttons on report dialogs that open the Query specification form to filter data on report queries).

·         Report Controllers: Report controllers control the report execution and dialog forms. Report controllers can be used to modify report dialogs, validate report parameters and other validations necessary before report execution. The base class is SrsReportRunController. Reports utilizing report controllers can only be used for printing data on client side. Reports controlled by controllers cannot be used in Enterprise Portals.

·         Report UI Builders: UI Builders are used to modify the report dialogs at run-time or to add additional parameters and write custom business logic to report dialogs. Ex: You want to perform some task based on data modified for one parameter, that affects other parameters or build a custom lookup etc (something that was provided by RunBaseReport framework class in previous versions. The base class is SrsReportDataContractUIBuilder.

-Harry

July 23, 2012

Microsoft Dynamics AX Development Best Practice

Microsoft Dynamics AX Development Best Practices


A  resource for AX Developers. "Microsoft Dynamics AX Development Best Practices White Paper". Apart from this check out MSDN for some very good knowledge on the following:



-Harry

July 21, 2012

How to enable debugging on Server

How to enable debugging on Server

In most of the cases, our X++ classes have to be executing within the server (AOS). In a default deployment, we're not able to debug server code.

To have this Dynamics AX feature, we must enable it in ‘Microsoft Dynamics AX Server Configuration Utility’ tool (within 'Administrative Tools' menu).

You may need to use the Manage button to Create a new Configuration. Then, on the first tab, Application Object Server, make sure that the check box option "Enable breakpoints to debug X++ code running on this server" is checked.

There is a direct registry key to do it, too. (but this way may be not supported):

REGEDIT4

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Dynamics Server\4.0\01\ Original (installed configuration)]

"xppdebug"="1"

-Harry

Form class and tables are used by a specific Dynamics AX form/functional

How to find out which Form class and tables are used by a specific Dynamics AX form/functional 


Hi Friends,


This Technique will help you every where when you need to find the back End of any form report.











This is a basic tip for developers who are starting with Dynamics AX. So, to find the form class and tables that are used by a functional process (like when you are executing and seeing an AX form), what we need to do first is to find out the form class name. To find the AOT form class name, open that form that's used in a process and Right-click on the form (over any record, for example) and select Setup. From there we can see the Form class definition and drill down to see all the tables it is using and so on.



















In red circle you found the table/Class name and its respective field.
For practice just  choose a form and try to find all related tables and used fields.
this will very help full for you to under stand the Form.


- Harry

July 20, 2012

Troubleshooting Error: No License code available for language

Troubleshooting Error: No License code available for language EN-US. Please use a licensed language
Hi there,

 I was setting up an AX Instance from an existing  database backup and I hit this below error.

Error: No License code available for language EN-US. Please use a licensed language

Event Viewer Error: The Microsoft Dynamics AX Application Object Server is running on an operating system that is not supported. The supported operating system is Microsoft Windows Server 2003 with Service Pack 1.


Solution:

The language for the startup user needs to be setup as per the installation

update dbo.USERINFO set LANGUAGE = 'EN-AU', HELPLANGUAGE = 'EN-AU' where ID = 'Admin'

Enjoy...
Harry

July 19, 2012

How to Assig access rights in Axapta between users

 How to Assig access rights in Axapta between users

Assignment of access rights for the users is a very frequent task. This script helps to assign or replicate the access rights between users instantly.


// Script for assigning/swapping access rights between users.
static void assignAccessRights(Args _args)
{
UserGroupList groupList,groupListIns;
str 10 frmUser, toUser;
;

frmUser = 'usr1';
toUser = 'usr2' ;

// To delete the existing permissions of the toUser
delete_from groupList
where groupList.UserId == toUser;


while select groupList
where groupList.userId == frmUser
{
info(strfmt('Group assigned: %1',groupList.groupId));
select forupdate groupListIns
where groupListIns.userID == toUser
&& groupListIns.GroupId == groupList.GroupId;

if(!groupListIns)
{
groupListIns.UserId = toUser;
groupListIns.GroupId = groupList.GroupId;
groupListIns.insert();
}
}
info(strfmt('Permissions changed from: %1 to: %2',frmUser,toUser));
}

-Harry

July 18, 2012

Ax 2009 disk full error Cannot create temporary file: C:\Program Files (x86)\Microsoft Dynamics AX\50\Client\appl\standard\tmp\$tmp001303e8.$.


Ax 2009 disk full error

Hi Friends

This problem only seems to occur on 64-bit operating systems and it can be very tricky to pin down the cause....
It occurs on both Terminal servers and Citrix Servers seemingly at random, we've noticed that the most consistent way to reproduce it (for this implementation at least) is by trying to generate a Customer Account Statement, but it can occur also occur when using Select Criteria, trying to generate a report, or when trying to view the permissions tree in a user group

The problem






Cannot create temporary file: C:\Program Files (x86)\Microsoft Dynamics AX\50\Client\appl\standard\tmp\$tmp001303e8.$.
The disk may be full.

Which is strange since the disk isn't full on the AOS server or the Citrix/Terminal server
There is a workaround which is to run the Ax client as an Administrator but that can be a major security flaw and isn't a long term solution

The Cause
There's a registry setting which tries to create a temporary sub-directory each time a user connects to a Terminal/Citrix server.
The problem is that when this temporary sub-directory gets created, it doesn't appear that the Ax client has access to it
So while the user may have the correct access to the %temp% directory within their Citrix/Terminal server user profile, they don't have access to the %temp%\1 or %temp%\27 or %temp%\942 sub-directory (the exact number varies and is rarely the same)

The Solution
The solution is to set the registry on the terminal server to not create these sub-directories within the temp folder and just to use the main %temp% directory instead
How do you do that? Well I'm glad you asked, all it takes is a little registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server]
"PerSessionTempDir"=dword:00000000

This change needs to be made in the registry on all the Citrix/Terminal servers that are used to connect to Ax

Here's a handy KB article with a bit more information about these keys

http://support.microsoft.com/kb/243215

Couldn't find this solution posted anywhere else on the internet so it looks like this is a first. Hurrah!


Enjoy Friends...
Harry

July 17, 2012

How to create a form with SimpleList-template


How to create a form with SimpleList-template...

Follow these simple steps.....
  1. Go to the AOT;
  2. Right-click the Forms-section and select the SimpleList-template;
  3. Then drag it to your project;
  4. The SimpleList-form is created, you will see a DataSource-section under the SimpleList-form;
  5. Drag and drop the table, you want to visualize on the SimpleList, to the DataSource-section of the form;
  6. Expand the Design-section of the SimpleList, you'll find the Grid-control;
  7. Finally select the Grid:
    1. Go to properties of the Grid to set the DataSource (this has to be the table that we've dropped);
    2. You also have to set the DataGroup (this is the fieldgroup or the fields of the table that we want to view);
  8. Save and open the form.

E-Book Morphx IT


Introduction to Axapta X++ and the MorphX. [DUTCH & ENGLISH]


Hi friends,
       this Ebook is really very help full for beginners developers. It contains a basic to high study material, with good examples.  This is available in two language.
English and Dutch

Enjoy guys....




I would like to share with you this e-book, free for download.

The author of this book is Steen Andreasen (Steen's website) and is written in 2006.

E-book in DUTCH: >>> Download Dutch Version <<<

To download the examples that come from the exercises in the book: >>> Click here <<<

This is a good start to introduce yourself into the world of Axapta and X++. I hope this will be helpful for you!

Building a query object

Building a query object


Query objects are used to visually build SQL statements. They are used by Dynamics AX

reports, views, forms, and other objects. Normally queries are stored in AOT, but they can also
be created from code dynamically. This is normally done when visual tools cannot handle
complex and dynamic queries. In this recipe, we will create one dynamically from code.
As an example, we will build a query that selects all active customers who belong to group 10
and have at least one sales order.

How to do it…

1. Open AOT, create a new job called CustTableSales, and enter the following code:



static void CustTableSales(Args _args)
{
Query query;
QueryBuildDataSource qbds1;
QueryBuildDataSource qbds2;
QueryBuildRange qbr1;
QueryBuildRange qbr2;
QueryRun queryRun;
CustTable custTable;
;
query = new Query();
qbds1 = query.addDataSource(tablenum(CustTable));
qbds1.addSortField(
fieldnum(CustTable, Name),
SortOrder::Ascending);
qbr1 = qbds1.addRange(fieldnum(CustTable,Blocked));
qbr1.value(queryvalue(CustVendorBlocked::No));
qbr2 = qbds1.addRange(fieldnum(CustTable,CustGroup));
qbr2.value(queryvalue(’10′));
qbds2 = qbds1.addDataSource(tablenum(SalesTable));
qbds2.relations(false);
qbds2.joinMode(JoinMode::ExistsJoin);
qbds2.addLink(
fieldnum(CustTable,AccountNum),
fieldnum(SalesTable,CustAccount));
queryRun = new QueryRun(query);
while (queryRun.next())
{
custTable = queryRun.get(tablenum(CustTable));
info(strfmt(
“%1 – %2″,
custTable.Name,
custTable.AccountNum));
}
}

2. Run the job, and the following screen should appear:

How it works…
First, we create a new query object. Next, we add a new CustTable data source to the query
by calling its addDataSource() member method. The method returns a reference to the
QueryBuildDataSource object—qbds1. Here, we call addSortField() to enable sorting by
customer name.
The following two blocks of code creates two filter ranges. The first is to show only active
customers and the second one is to list only customers belonging to a single group 10. Those
two filters are automatically added together using the SQL AND operator. QueryBuildRange
objects are created by calling the addRange() member method of the QueryBuildDataSource
object with the field ID number as argument. Range value is set by calling value() on the
QueryBuildRange object itself. It is a good practice to use queryvalue() or a similar function
to process values before applying them as a range. More functions like querynotvalue(),
queryrange(), and so on can be found in the Global application class. Note that these
functions actually process data using the SysQuery application class, which in turn has even
more interesting helper methods that might be handy for every developer.
Adding another data source to an existing one connects both data sources using the SQL

JOIN operator. It this example, we are displaying customers that have at least one sales
order. We start by adding the SalesTable table as another data source. We are going to
use custom relations between those tables, so we need to disable standard relations by
calling the relations() method with false as an argument. Calling joinMode() with
JoinMode::ExistsJoin as a parameter ensures that a record from a parent data source
will be displayed only if the relation exists in its attached data source. And finally, we create a
relation by calling addLink() and passing the field ID number of both tables.
Last thing to do is to create and run the queryRun object and show the selected data on
the screen.
There’s more…
It is worth mentioning a couple of specific cases when working with query objects from code.
One of them is how to use the OR operator and the other one is how to address array fields.
Using the OR operator
As you have already noted, regardless of how many ranges are added, all of them will be
added together using the SQL AND operator. In most cases, it is fine, but sometimes complex
user requirements demand ranges to be added using SQL OR. There might be a number of
work-arounds, like using temporary tables or similar, but I use the Dynamics AX feature that
allows passing raw SQL as a range.
In this case, the range has to be formatted like the fully qualified SQL WHERE clause including
field names, operators, and values. Each separate clause has to be in brackets. It is also very
important that filter values, especially if they are specified by the user, have to be properly
formatted before using them in a query.
Let’s replace the code from the previous example:




qbr2.value(queryValue(’10′));
with the new code:
qbr2.value(strfmt(
‘((%1 = “%2″) || (%3 = “%4″))’,
fieldstr(CustTable,CustGroup),
queryvalue(’10′),
fieldstr(CustTable,Currency),
queryvalue(‘EUR’)));
Now, the result would also include all the customers having the default currency EUR.
Using arrays fields

Some table fields in Dynamics AX are based on extended data types, which contains more
than one array element. An example in a standard application could be financial dimensions
based on the Dimension extended data type or project sorting based on ProjSortingId.
Although such fields are very much the same as normal fields, in queries, they should be
addressed slightly different. To demonstrate the usage, let’s modify the example by filtering
the query to list only customers containing a specific Purpose value. In the standard
application, Purpose is the third financial dimension, where the first is Department and the
second is Cost centre.
First, let’s declare a new QueryBuildRange object in the variable declaration section:




QueryBuildRange qbr3;




Next, we add the following code right after the qbr2.value(…) code:



qbr3 = qbds1.addRange(

fieldid2ext(fieldnum(CustTable,Dimension),3));
qbr3.value(queryvalue(‘Site1′));


Notice that we use the global fieldid2ext() function, which converts the field ID and

the array number into a valid number to be used by addRange(). This function can also be
used anywhere, where addressing the dimension fields is required. The value 3 as its second
argument here means that we are using a third dimension, that is, Purpose. In my application, I
have purposes defined as Site1, Site2, and Site3, so I simply use the first one as filter criteria.
Now, when we run this job, the customer list based on previous criteria will be reduced even
more to match customers having only a specific Purpose set.

-Harry

How to open a form by using AX code

How to open a form by using AX code

Hi Guys,

      Today we are going to open a form using code..just try following code

 if(inventtable.Family == family::MettalicCore)
   {
   new MenuFunction(MenuItemDisplayStr(Attributes1),MenuItemType::Display).run();
    }
    else
    {
     new MenuFunction(MenuItemDisplayStr(Attributes),MenuItemType::Display).run();
     }

Here we are opening a form of Attributes1 and Attributes form its a simple way.Block Super()

Here is another way take a look


static void OpenFormByCodeB()
{ FormRun formRun;
Args args = new Args();
;
args.name(formstr(CustTable));
args.record(CustTable::find('ABC'));

formRun = ClassFactory.formRunClass(args);
formRun.init();
formRun.run();
formRun.wait();
}


Now if we tweak this a little bit, we can add our code
Like this:


static void OpenFormByCodeB()
{ Object formRun;
Args args = new Args();
;
args.name(formstr(CustTable));
args.record(CustTable::find('ABC'));

formRun = ClassFactory.formRunClass(args);
formRun.init();

formRun.yourmethodgoeshere(); /* !!

formRun.run();
formRun.wait();
}

By changing the type of formRun from class FormRun to class Object, we can implement and execute extra methods on our destination form! This gives us extra possibilities for customizations. You can pass along extra parameters for example.
Only drawback: While programming, your method doesn't show up in the IntelliSense, showing all the available methods. So be carefull of typo's. 

-Harry

How export data to csv file in Ax 2009

How export data to csv file in Ax 2009

Hi friends ,

   Today we will learn how to exporting our  data from Ax 2009 to csv file format. The programming is done through X++ code. Change the code as per your requirements. Now we will have a simple example of writing the invent table to the csv file


public static void main(Args _args)
{
    Commaio file;
    container line;
    InventTable inventTable;
    #define.filename("C:\\dpk_Items.csv")
    #File

    ;
    file = new Commaio(#filename , #io_write); or  file = new Commaio(#filename , 'W');
    //file.outFieldDelimiter(';');
    if( !file || file.status() != IO_Status::Ok)
    {
        throw error("File Cannot be opened");
    }
    while select inventTable
    {
        line = [inventTable.ItemId,inventTable.ItemName];
        file.writeExp(line);
    }
}

You can save the document in any format such as doc,txt,xls only.


-Harry

Simple Dialog Box in Ax 2009

Simple Dialog Box Example in Ax 2009


Hi Friends ,
Today we are tring to develop a  simple DialogBox .
try to following code


static void Simple_Dialog(Args _args)
{
dialog dlg;
dialogGroup dlgGroup;
dialogField dlgField;
;
dlg = new dialog("Simple Dialog");
dlgGroup = dlg.addGroup("Customer");
dlgField = dlg.addField(TypeID(custAccount),"Account
Number");
if (dlg.run())
{
print dlgField.value();
pause;
}
}


-Harry