Monday, December 6, 2010

Enable/Disable table field on form by code

FormDataSource_ds.object(fieldNum(TableName,Field)).allowEdit(false);

or for arrays

FormDataSource_ds.object((new
SysdictField(tableNum(TableName),fieldNum(TableName,FieldName),1).id())).allowEdit(false);

where 1 is the number of the field in the array.

Yes, you can go to the table and set AllowEdit Yes/No
Yes, you can also go to the form and set the field to Enabled Yes/No
Yes, you can also go to the particular field control and set Enabled to Yes/No

so why would you use this method?

1. If multiple controls are using this field and you want to disable
all instances of the field, but you dont want to disable it on the
table level
2. If the field is part of an array EDT, like Dimension, and you just
want to disable one field, not the others

Monday, November 22, 2010

Dynamics AX Intelligent Data Management Framework

currently assessing whether the IDMF tool for Dynamics AX is worth
implementing at my current workplace.

if you don't know what it is, go here (you'll need your
partnersource/customersource login):
https://mbs.microsoft.com/partnersource/downloads/releases/ax_idmf.htm?printpage=false&stext=Data
Management Framework

here is a document i created which may help out, if you happen to be
doing the same thing.

http://cid-53c50a8f9ecf30c8.office.live.com/view.aspx/Public/Dynamics%20AX/Assessment%20of%20Data%20Management%20Framework.doc

Thursday, November 18, 2010

OnlyFetchActive on Form Datasource

this property on the datasource can speed things up especially if you
have one field that has lots of data stored in it and you still want
to show it on the form

if you need to show it on the form (on another tab preferably), you
can use a display method instead.

on the display method

display Memo memoDisplay(TableDS _tableDS)
{
;
if (formTableDS.RecId != _tableDS.RecId)
{
select firstonly log from formTableDS where
formTableDS.RecId == _tableDS.RecId;
}
return formTableDS.memo;
}

formTableDS is declared in the Class declaration of the form

Sunday, October 17, 2010

Override Form Caption

if you want to override a form caption completely, use the following
code in the datasource's active() method, just after the super.

winapi::setWindowText(element.hWnd(), "My caption override text");

Saturday, September 4, 2010

Re: Filtering on Date using QueryBuildRange

syntax for advanced filtering on date:

    queryBuildRange = queryBuildDataSource.addRange(FieldNum(MyTable, MyDate));
    queryBuildRange.value(strFmt('(MyDate ==  %1)',  Date2strXpp(_myDate)));


Tuesday, August 10, 2010

email field validation

public boolean validateField(fieldId _fieldIdToCheck)
{
boolean ret;
str email;
;

ret = super(_fieldIdToCheck);

if (_fieldIdToCheck == fieldnum(WRPartyApplDetails, NewEmail))
{
email = this.Email;

if ( strfind(email, "@", 1, strlen(email)) == 0
|| strfind(email, ".", 1, strlen(email)) == 0)
{
error("Must contain a '@' character and at least one '.'");
ret = false;
}

if ( strscan(email, ".@", 1,strlen(email)) > 0
|| strscan(email, "@.", 1,strlen(email)) > 0)
{
error("Cannot have the '@' and the '.' one after the other");
ret = false;
}
}

return ret;
}

Monday, July 5, 2010

Technical Best Practices for Dynamics AX - Shared and AOT Object Standards

some good reading


Technical Best Practices for Dynamics AX - Shared and AOT Object Standards
 - http://www.packtpub.com/article/technical-best-practices-for-dynamics-ax-shared-and-aot-object-standards

Technical Best Practices for Dynamics AX - Application Design Standards
- http://www.packtpub.com/article/technical-best-practices-for-dynamics-ax-application-design-standards


--
Kind Regards
Jonathan Sulte

====================
if (first && succeed == false)
   while (!succeed)
       try();
====================

Wednesday, June 9, 2010

Refreshing form data but staying on the current record

if you want to refresh a form, but want to stay on the current record you are on, use this code:


void refreshForm()
{
    FormTable current;
    ;

    if (FormTableDataSource.RecId)
    {
        FormTableDataSource_ds.write();
        current.data(FormTableDataSource);
        FormTableDataSource_ds.research();
        FormTableDataSource_ds.setRecord(current);
    }

Tuesday, June 8, 2010

GROUPING query

if you want to group a query on a field, here is an example (used in a lookup table):

public void lookup()
{
    SysTableLookup        sysTableLookup = SysTableLookup::newParameters(tableNum(YourTable), this);
    Query                 query = new query();
    QueryBuildDataSource  queryBuildDataSource = query.addDataSource(tableNum(YourTable));
    ;

    queryBuildDataSource.orderMode(OrderMode::GROUPBY);
    queryBuildDataSource.addSortField(FieldNum(YourTable, YourField));

    sysTableLookup.addLookupfield(fieldNum(YourTable, YourField));
    sysTableLookup.parmQuery(query);

    sysTableLookup.performFormLookup();
}

Creating Lookups

here is a sample code to create lookups on a form field

public void lookup()
{
    SysTableLookup        sysTableLookup = SysTableLookup::newParameters(tableNum(YourAXTable, this);
    Query                 query = new query();
    QueryBuildDataSource  queryBuildDataSource = query.addDataSource(tableNum(YourAXTable));
    QueryBuildRange       range1 = queryBuildDataSource.addRange(fieldNum(YourAXTable, FieldYouWantFiltered1));
    QueryBuildRange       range2 = queryBuildDataSource.addRange(fieldNum(YourAXTable, FieldYouWantFiltered2));
    ;

    range1.value(queryValue(YourFormField.valuestr()));
    range2.value(queryValue(YourFormField2.valuestr()));

    sysTableLookup.addLookupfield(fieldNum(YourAXTable, FieldYouWantReturned));
    sysTableLookup.addLookupfield(fieldNum(YourAXTable, AdditionalLookupColumn));

    sysTableLookup.parmQuery(query);

    sysTableLookup.performFormLookup();

}

Sunday, June 6, 2010

QueryBuildRange date range between two dates

when you want to filter between two dates. use SysQuery::Range:

eg
        queryBuildRange = queryBuildDataSource.addRange(FieldNum(WRWaterShareTable, TenureExpiryDate));
        queryBuildRange.value(sysQuery::range(_expiryDateFilter,_expiryDateToFilter));

this function gives the flexibility of passing one or two dates. if you pass value in the first date only, it will search date equal to and after the date. if you pass value in the second date only, it will search dates equal to and before the date.

Tuesday, June 1, 2010

SysOperationProgress sample

this is the basic code of when you want to show progress. it will show the progress animation while the system is waiting to go through your code.

public void sysOperationProgressSample()
{
    SysOperationProgress        progress = new SysOperationProgress();
    counter                     counter = 0;
    counter                     progressCounter = 0;
    LineNum                     lineNum = 0;
    int                         lineTotal;

    ;

#AviFiles

    progress.setCaption("Processing Records...");
    progress.setAnimation(#AviUpdate);

    lineTotal = 9999; //set total of lines here
    progress.setTotal(lineTotal);

    while select ...
    {
        //put these lines on top (or at the bottom of what you are doing)
        counter++;
        progressCounter++;
        progress.setText(strFmt("Processing %1 of %2 records. Please wait",int2str(counter),int2str(lineTotal)));
        progress.incCount();

        /*
        your stuff here
        */
    }

}

Monday, May 31, 2010

Disallow system to remember Last Query Used values on filters

on the init of the report

public void init()
{
    SysQueryRun sysQueryRun;
    ;

    super();

    this.queryPerfTable(); //do your query stuff here

    //these code lines stop the system from remembering last used values
    sysQueryRun = new SysQueryRun(element.query());
    sysQueryRun.promptLoadLastUsedQuery(false);
    element.queryRun(sysqueryRun);

}

Thursday, April 1, 2010

PostSynchronize Scare when Upgrading AX2009

Just want to share my experience with this Dynamics AX upgrade step. I got to the part of the upgrade where it is time to do the Postsynchronize step. This is the all important part. I had to do a Presynchronize first, then a Synchronize database step. After this step, the Postsynchronize step (which was greyed out) *should* turn to green after synchronizing successfully.

 

However in my case, it did not. I spent a good hour trying to figure out why it didn’t. I resynchronized, i checked that everything was ok. It was. I reran Presynchronize then Synchronize. Nothing worked. The Postsynchronize options still stayed greyed out. It was not enabled and i could not proceed.

 

A few minutes before giving up and restoring the backup (which would mean i would have lost a few hours’ worth of upgrade time), i tried clicking back to the second step which was Provide licence Information, re ran that, reran the next step, Global Address books, re ran Setup Current Time Zone, re ran Customer Feedback Options. Skipped detect code upgrade conflicts, re ran Presynchronize (it won’t actually rerun the jobs, it will just tell you have already ran it, and it when you close out of it, it will enable the next step), re ran Synchronize... and voila!!! It worked, it opened up the Postsynchronize step!

 

What *i think* happened is when you run the upgrade, it puts some settings in a temporary table. Throughout the upgrade, which can span days, you are going in and out of AX. If this table is cleared for some reason, it loses track of what steps you have finished, and what the next step is.

 

Going back to the second step (the first step is Compile Application, and i didn’t want to do that as it takes around 30 minutes) seem to restore that temporary table and going through the steps one after the other, without shutting down, it will allow you to get to Postsynchronize.

 

I hope this helps some poor soul out there desperate to know why they cannot Postsynchronize

Thursday, March 11, 2010

Restriction for Admin Groups

When you want to restrict something to the Admin Group only, use this code:

 

#Admin

boolean canForwardDate()

{

    boolean ret;

    UserGroupList groupList;

    ;

 

    select firstfast groupList where

        groupList.groupId == #AdminUserGroup

        &&  groupList.UserId == curuserid();

 

    if (groupList)

        ret = true;

    else

        ret = false;

 

    return ret;

}

Monday, March 1, 2010

Insert Text to Multiple Rows

So imagine you need to copy a whole chunk of text into multiple rows in a table where you have a threshold of “x” number of characters per row. Here is a code I created to  chop the text up with the SPACE as a delimiter. It puts the rest of the text on the next record until all texts are inserted. This code is located in the methods of the table that it is inserting it to and called in the modifiedfield method.

 

 

void CutText(str _textToCut)

{

    int threshold;

    str delimiter, origText, curText;

    int nextLineNum, curTextLen, trimPos, nextTrimPos;

    NarrationTable narration;

    ;

 

    threshold = 74;

    delimiter = " ";

    curText = _textToCut;

    origText = curText;

 

    //check how long the text is

    curTextLen = strLen(curText);

 

    //deal with the first record to insert first

    if (curTextLen > threshold)

    {

        //find position. Note a negative value in the last parameter means to start searching from the back of the text      

        trimPos = strfind(curText,delimiter,curTextLen,-curTextLen);

 

        if (trimPos > threshold)

        {

            //find the first position

            while (trimPos > threshold)

            {

                curText = substr(curText,1, trimPos - 1);

                curTextLen = strLen(curText);

                trimPos = strfind(curText,delimiter,curTextLen,-curTextLen);

            }

            //insert the first text

            this.Notes = curText;

            //if new insert, if not, just save

            if (!this.RecId)

            {

                this.LineNum = this.GetLastLineNum(this.SecondaryId) + 1;

                this.doInsert();

            }

            else

                this.doUpdate();

        }

 

        //insert the rest in a new record

        curText = substr(origText,trimPos + 1,strlen(origText));

        trimPos = strfind(curText,delimiter,1,curTextLen);      //remove extra word

        curText = substr(curText,trimPos + 1,strlen(curText));  //remove extra word

        origText = curText;

        curTextLen = strLen(curText);

       

       //go through and cut up the rest of the text and insert it and cut it until all text can fit within the threshold

        while (trimPos)

        {

            trimPos = strfind(curText,delimiter,curTextLen,-curTextLen);

           

            while (trimPos > threshold)

            {

                curText = substr(curText,1, trimPos - 1);

                curTextLen = strLen(curText);

                trimPos = strfind(curText,delimiter,curTextLen,-curTextLen);

            }

 

            ttsbegin;

            select forupdate narration

                order by LineNum desc where

                narration.SecondaryId == this.SecondaryId;

            //there should always be a record selected. but juse in case...

            if (narration)

            {

                narration.LineNum = narration.LineNum + 1;

                narration.Notes = curText;

                narration.insert();

            }

            ttscommit;

           

            curText = substr(origText,trimPos + 1,strlen(origText));

            trimPos = strfind(curText,delimiter,1,curTextLen);      //remove extra word

            curText = substr(curText,trimPos + 1,strlen(curText));  //remove extra word

            origText = curText;

            curTextLen = strLen(curText);

            trimPos = strfind(curText,delimiter,curTextLen,-curTextLen);

        }

    }

}

Monday, February 22, 2010

AX Client Cannot Connect to AOS

This may be a simple one for some of you, but these are the common things to look out for when installing clients so that they will connect to the AOS:

 

1.       Ensure the port you are trying to connect to is open on the Internal Firewall. Default is 2712. This can be changed in the AOS however, so ensure whatever port that is, that it is open for the client to access

2.       When creating a config file from the server that is a 64bit computer, it points the folders to “Program Files (x86)”. If you are importing that AXC into the client, ensure that you change the folder pointers to “Program Files” first, before importing it.

3.       Ensure that you have matching Service Packs installed on both client, AOS and Application

Tuesday, February 16, 2010

Windows 7 Phone

i can see Dynamics AX apps appearing on this phone. In fact i can see AX being the development platform for deploying mobile applications? possible or do you think im dreaming?

http://gizmodo.com/5471805/windows-phone-7-series-everything-is-different-now?skyline=true&s=i

Sunday, February 14, 2010

AX Modification Tracker

i created this simple tracker in sharepoint to keep track of my AX Modifications



here are the call statii


here are the modules list


Tuesday, February 9, 2010

Silent Client Installation

When you want to set up an AX client without user intervention, do the following.

 

Export a Config file and place it in a shared location. Eg AXSERVER.axc

 

Create a text file in the same directory as the installation file. Insert into it the following:

 

LogDir="C:\TMP"

HideUi=1

AcceptLicenseTerms=1

InstallClientUI=1

ClientConfig=1

ClientAosServer=AXSERVER

ClientLanguage=en-au

ClientConfigFile="P:\DynamicsAX\config\AXSERVER.axc"

ConfigurePrerequisites=1

 

Then just call the setup file from the prompt by using this syntax

P:\DynamicsAX\install\setup.exe ParmFile=P:\DynamicsAX\install\SilentParamFile.txt

 

The same thing can be done with the Service Pack installs

 

Text File Content:

LogDir="C:\TMP"

HideUi=1

AcceptLicenseTerms=1

 

Then run

P:\DynamicsAX\SP1\axupdate.exe ParmFile=P:\DynamicsAX\SP1\SilentParamFileSP1.txt

 

Tuesday, February 2, 2010

The Year of the Cloud: How Coming Microsoft Products Will Make Dynamics AX the Basis of New Solutions

Good time to be in AX...

The Year of the Cloud: How Coming Microsoft Products Will Make Dynamics AX the Basis of New Solutions

Welcome back, jaysalt.

BY Brandon George, Senior Technical Architect, Sunrise Technolgies, Inc.

PUBLISHED: January 26, 2010

People have been talking about The Cloud for years, and now it’s arrived. 2010 for sure will be the year of the Cloud. And though it's not on any official calendar, those born under the year of the cloud are sure to be free thinkers, operational vs. capital based, have abilities to get projects going on their feet --- and into the cloud quickly.

Seriously, the next release,  or wave of Microsoft products, will enable more and more solutions to actually be true Hyrbid clouds. This means Dynamics AX customers will need to understand what is expected, as part of their solution design.  The next wave is just the very first part of what is on the horizon. Microsoft Dynamics AX is the business platform, which the rest of the platform makes use of to offer a total, single, hyrbid platform for users.

Most all businesses, in some form or fashion, have an interest level in the Cloud. When I talk to clients about Microsoft Azure, Microsoft's cloud platform, the biggest thing I see as an issue is what the cloud offers.  So here is my take on what the cloud offers now,  and likely in the future.

First, we must understand that  there will be two ways services and whole applications, including legacy, can live in the cloud.

As one approach, you have the true cloud based Software+Services, 'Three Screens and a Cloud' marketing tag lined approach. This includes services that are built using SQL Azure, .Net AppFabric, Windows Azure, etc. that are multi-tenant based. This means they can scale up or down, without need for the services of a system administration, depending on the load of the given service or services at hand.

This first approach is what makes such cloud-based services different from a typical hosting environment, like having a server co-located somewhere and users hitting it. This is also different than having a service hosted on some web server, and users consuming it.

Once created, and set up, then the need of the service, truly governs the resources used to serve that need.

Enter the second option for Azure platform based software or services. This is where, for example, a legacy application could be used. Here, what you have is a provisioned virtual image, which sits on top of the Azure platform. This is very similar to having a co-located box somewhere. This is not dynamically scalable, and so has a set of finite resources... unless an admin type increases those resources.

The second option is a pay-for-use as well, and it's spread out over the CPU, Disk I/O, etc.

So, now we have a better idea of what it means to be built on the Azure platform. The current service offerings from Microsoft, are of option one. These are truly dynamic scalable services, depending on the need, built using Windows Azure, .Net AppFabric, SQL Azure, etc.

While you will have the ability to consume and work with services developed by Microsoft, you’ll also be able to create your own, custom, true cloud services with Dynamics AX, and also make use and consume third party cloud based services.

 

Monday, February 1, 2010

Quick Tax Calculation

So sometimes all you need is to calculate an amount’s tax. Here it is.

 

static void CalcTax(Args _args)

{

    Tax         tax;

    Amount      taxAmount;

    ;

    tax = new Tax();

    taxAmount = tax::calcTaxAmount("GST","GST",systemdateget(),"AUD",100,TaxModuleType::Project);

   

    print taxAmount;

    pause;

}

Browsing System Tables

So you want to have a quick peek under Dynamics AX’s skirt and see how it hangs? Sometimes, you can be reading X++ that references to tables that you cannot find under the Tables node. These are more than likely System Tables.

 

An easy way to browse system tables is to go to AOT > System Documentation > Tables. You can see a list of system tables. Double clicking or right click > opening it will only bring up the help file connected to that table

 

You have to do “Right Mouse Click > Addins > Table Browser” to view the table. If you are logged in as Admin, you can do a lot of damage in these tables. I suggest you DONT change anything from here unless you really really know what you’re changing and why.

 

 

Check whether Current User is in Admin Group

If you want to check the current user is in the Admin group, use the UserGroupList system table. You can extend this code to check if a user is in a particular security group or not.

 

//check the UserGroupList system table if the current user is in there

#Admin

boolean canDoStuff()

{

    boolean ret;

    UserGroupList groupList;

    ;

   

    select firstfast groupList where

        groupList.groupId == #AdminUserGroup

        &&  groupList.UserId == curuserid();

 

    if (groupList)

        ret = true;

    else

        ret = false;

       

    return ret;

}

Sending Mail

You can use the SysInetMail class to send mail from AX. The example below also uses the Email Group setup in CRM

 

Public void EmailNotifyList(smmEmailGroupId _listName,str _subject, str _text)

{

    EmplTable emplTable;

    EmplId _emplId;

    smmEmailMembers emailList;

    sysInetMail sysInetMail = new sysInetMail();

    ;

 

    while select emailList index hint GroupIdx

        where emailList.GroupId == _listName

    {

        _emplId = emailList.EmplId;

        if (_emplId)

            if (emplTable::find(_emplId).Email)

                sysInetMail.sendMail(emplTable::find(_emplId).Email,_subject,_text, false);

   }

}

Tuesday, January 12, 2010

Inserting Records into AX5 Table Using VBA and COM

so you want to use MS Access to insert/update a Dynamics AX table. No problems! just a few things.

1. ensure that you have the COM object registered on the PC you are working on (axcom.dll - date stamp ‎Tuesday, ‎20 ‎May ‎2008, ‏‎3:33:40 PM) this is the one that comes with AX5 (2009), not the version 3 com object.

2. ensure that in MS Access, Visual Basic Editor > Tools > Reference, that you select that dll and the database file knows you are using it.

3. Do the following Code

Function InsertToProjJournalTrans(strApprovedBy As String) As Boolean
On Error GoTo err
Dim comAx As AxaptaCOMConnector.Axapta3
Dim updateTable As AxaptaCOMConnector.IAxaptaRecord

Set comAx = New AxaptaCOMConnector.Axapta3

With comAx
.Logon "", "", "", ""
Set updateTable = .CreateRecord("AxmProjJournalTrans")
.TTSBegin
.ExecuteStmt "SELECT * FROM %1", updateTable

With updateTable
.Field("TransIdRef") = 5555
.Insert
End With

.TTSCommit
.Logoff
End With

eer:
Set comAx = Nothing
err:
MsgBox err.Description & " - InsertToProjJournalTrans", vbExclamation, strAppTitle
Resume eer
End Function

hope that helps.